|
|
1.1 root 1: /*
2: * Copyright (c) 1989 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Rick Macklem at The University of Guelph.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: * @(#)nfs_bio.c 7.19 (Berkeley) 4/16/91
37: */
38:
39: #include "param.h"
40: #include "proc.h"
41: #include "buf.h"
42: #include "uio.h"
43: #include "namei.h"
44: #include "vnode.h"
45: #include "trace.h"
46: #include "mount.h"
47: #include "resourcevar.h"
48:
49: #include "nfsnode.h"
50: #include "nfsv2.h"
51: #include "nfs.h"
52: #include "nfsiom.h"
53: #include "nfsmount.h"
54:
55: /* True and false, how exciting */
56: #define TRUE 1
57: #define FALSE 0
58:
59: /*
60: * Vnode op for read using bio
61: * Any similarity to readip() is purely coincidental
62: */
63: nfs_bioread(vp, uio, ioflag, cred)
64: register struct vnode *vp;
65: register struct uio *uio;
66: int ioflag;
67: struct ucred *cred;
68: {
69: register struct nfsnode *np = VTONFS(vp);
70: register int biosize;
71: struct buf *bp;
72: struct vattr vattr;
73: daddr_t lbn, bn, rablock;
74: int diff, error = 0;
75: long n, on;
76:
77: #ifdef lint
78: ioflag = ioflag;
79: #endif /* lint */
80: #ifdef DIAGNOSTIC
81: if (uio->uio_rw != UIO_READ)
82: panic("nfs_read mode");
83: #endif
84: if (uio->uio_resid == 0)
85: return (0);
86: if (uio->uio_offset < 0 && vp->v_type != VDIR)
87: return (EINVAL);
88: biosize = VFSTONFS(vp->v_mount)->nm_rsize;
89: /*
90: * If the file's modify time on the server has changed since the
91: * last read rpc or you have written to the file,
92: * you may have lost data cache consistency with the
93: * server, so flush all of the file's data out of the cache.
94: * Then force a getattr rpc to ensure that you have up to date
95: * attributes.
96: * NB: This implies that cache data can be read when up to
97: * NFS_ATTRTIMEO seconds out of date. If you find that you need current
98: * attributes this could be forced by setting n_attrstamp to 0 before
99: * the nfs_dogetattr() call.
100: */
101: if (vp->v_type != VLNK) {
102: if (np->n_flag & NMODIFIED) {
103: np->n_flag &= ~NMODIFIED;
104: vinvalbuf(vp, TRUE);
105: np->n_attrstamp = 0;
106: np->n_direofoffset = 0;
107: if (error = nfs_dogetattr(vp, &vattr, cred, 1,
108: uio->uio_procp))
109: return (error);
110: np->n_mtime = vattr.va_mtime.tv_sec;
111: } else {
112: if (error = nfs_dogetattr(vp, &vattr, cred, 1,
113: uio->uio_procp))
114: return (error);
115: if (np->n_mtime != vattr.va_mtime.tv_sec) {
116: np->n_direofoffset = 0;
117: vinvalbuf(vp, TRUE);
118: np->n_mtime = vattr.va_mtime.tv_sec;
119: }
120: }
121: }
122: do {
123: switch (vp->v_type) {
124: case VREG:
125: nfsstats.biocache_reads++;
126: lbn = uio->uio_offset / biosize;
127: on = uio->uio_offset & (biosize-1);
128: n = MIN((unsigned)(biosize - on), uio->uio_resid);
129: diff = np->n_size - uio->uio_offset;
130: if (diff <= 0)
131: return (error);
132: if (diff < n)
133: n = diff;
134: bn = lbn*(biosize/DEV_BSIZE);
135: rablock = (lbn+1)*(biosize/DEV_BSIZE);
136: if (vp->v_lastr + 1 == lbn &&
137: np->n_size > (rablock * DEV_BSIZE))
138: error = breada(vp, bn, biosize, rablock, biosize,
139: cred, &bp);
140: else
141: error = bread(vp, bn, biosize, cred, &bp);
142: vp->v_lastr = lbn;
143: if (bp->b_resid) {
144: diff = (on >= (biosize-bp->b_resid)) ? 0 :
145: (biosize-bp->b_resid-on);
146: n = MIN(n, diff);
147: }
148: break;
149: case VLNK:
150: nfsstats.biocache_readlinks++;
151: on = 0;
152: error = bread(vp, (daddr_t)0, NFS_MAXPATHLEN, cred, &bp);
153: n = MIN(uio->uio_resid, NFS_MAXPATHLEN - bp->b_resid);
154: break;
155: case VDIR:
156: nfsstats.biocache_readdirs++;
157: on = 0;
158: error = bread(vp, uio->uio_offset, NFS_DIRBLKSIZ, cred, &bp);
159: n = MIN(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid);
160: break;
161: };
162: if (error) {
163: brelse(bp);
164: return (error);
165: }
166: if (n > 0)
167: error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
168: switch (vp->v_type) {
169: case VREG:
170: if (n+on == biosize || uio->uio_offset == np->n_size)
171: bp->b_flags |= B_AGE;
172: break;
173: case VLNK:
174: n = 0;
175: break;
176: case VDIR:
177: uio->uio_offset = bp->b_blkno;
178: break;
179: };
180: brelse(bp);
181: } while (error == 0 && uio->uio_resid > 0 && n != 0);
182: return (error);
183: }
184:
185: /*
186: * Vnode op for write using bio
187: */
188: nfs_write(vp, uio, ioflag, cred)
189: register struct vnode *vp;
190: register struct uio *uio;
191: int ioflag;
192: struct ucred *cred;
193: {
194: struct proc *p = uio->uio_procp;
195: register int biosize;
196: struct buf *bp;
197: struct nfsnode *np = VTONFS(vp);
198: struct vattr vattr;
199: daddr_t lbn, bn;
200: int n, on, error = 0;
201:
202: #ifdef DIAGNOSTIC
203: if (uio->uio_rw != UIO_WRITE)
204: panic("nfs_write mode");
205: if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
206: panic("nfs_write proc");
207: #endif
208: if (vp->v_type != VREG)
209: return (EIO);
210: /* Should we try and do this ?? */
211: if (ioflag & (IO_APPEND | IO_SYNC)) {
212: if (np->n_flag & NMODIFIED) {
213: np->n_flag &= ~NMODIFIED;
214: vinvalbuf(vp, TRUE);
215: }
216: if (ioflag & IO_APPEND) {
217: np->n_attrstamp = 0;
218: if (error = nfs_dogetattr(vp, &vattr, cred, 1, p))
219: return (error);
220: uio->uio_offset = np->n_size;
221: }
222: return (nfs_writerpc(vp, uio, cred));
223: }
224: #ifdef notdef
225: cnt = uio->uio_resid;
226: osize = np->n_size;
227: #endif
228: if (uio->uio_offset < 0)
229: return (EINVAL);
230: if (uio->uio_resid == 0)
231: return (0);
232: /*
233: * Maybe this should be above the vnode op call, but so long as
234: * file servers have no limits, i don't think it matters
235: */
236: if (uio->uio_offset + uio->uio_resid >
237: p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
238: psignal(p, SIGXFSZ);
239: return (EFBIG);
240: }
241: /*
242: * I use nm_rsize, not nm_wsize so that all buffer cache blocks
243: * will be the same size within a filesystem. nfs_writerpc will
244: * still use nm_wsize when sizing the rpc's.
245: */
246: biosize = VFSTONFS(vp->v_mount)->nm_rsize;
247: np->n_flag |= NMODIFIED;
248: do {
249: nfsstats.biocache_writes++;
250: lbn = uio->uio_offset / biosize;
251: on = uio->uio_offset & (biosize-1);
252: n = MIN((unsigned)(biosize - on), uio->uio_resid);
253: if (uio->uio_offset+n > np->n_size) {
254: np->n_size = uio->uio_offset+n;
255: vnode_pager_setsize(vp, np->n_size);
256: }
257: bn = lbn*(biosize/DEV_BSIZE);
258: again:
259: bp = getblk(vp, bn, biosize);
260: if (bp->b_wcred == NOCRED) {
261: crhold(cred);
262: bp->b_wcred = cred;
263: }
264: if (bp->b_dirtyend > 0) {
265: /*
266: * If the new write will leave a contiguous dirty
267: * area, just update the b_dirtyoff and b_dirtyend,
268: * otherwise force a write rpc of the old dirty area.
269: */
270: if (on <= bp->b_dirtyend && (on+n) >= bp->b_dirtyoff) {
271: bp->b_dirtyoff = MIN(on, bp->b_dirtyoff);
272: bp->b_dirtyend = MAX((on+n), bp->b_dirtyend);
273: } else {
274: bp->b_proc = p;
275: if (error = bwrite(bp))
276: return (error);
277: goto again;
278: }
279: } else {
280: bp->b_dirtyoff = on;
281: bp->b_dirtyend = on+n;
282: }
283: if (error = uiomove(bp->b_un.b_addr + on, n, uio)) {
284: brelse(bp);
285: return (error);
286: }
287: if ((n+on) == biosize) {
288: bp->b_flags |= B_AGE;
289: bp->b_proc = (struct proc *)0;
290: bawrite(bp);
291: } else {
292: bp->b_proc = (struct proc *)0;
293: bdwrite(bp);
294: }
295: } while (error == 0 && uio->uio_resid > 0 && n != 0);
296: #ifdef notdef
297: /* Should we try and do this for nfs ?? */
298: if (error && (ioflag & IO_UNIT)) {
299: np->n_size = osize;
300: uio->uio_offset -= cnt - uio->uio_resid;
301: uio->uio_resid = cnt;
302: }
303: #endif
304: return (error);
305: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.