|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1989, 1993
28: * The Regents of the University of California. All rights reserved.
29: *
30: * This code is derived from software contributed to Berkeley by
31: * Rick Macklem at The University of Guelph.
32: *
33: * Redistribution and use in source and binary forms, with or without
34: * modification, are permitted provided that the following conditions
35: * are met:
36: * 1. Redistributions of source code must retain the above copyright
37: * notice, this list of conditions and the following disclaimer.
38: * 2. Redistributions in binary form must reproduce the above copyright
39: * notice, this list of conditions and the following disclaimer in the
40: * documentation and/or other materials provided with the distribution.
41: * 3. All advertising materials mentioning features or use of this software
42: * must display the following acknowledgement:
43: * This product includes software developed by the University of
44: * California, Berkeley and its contributors.
45: * 4. Neither the name of the University nor the names of its contributors
46: * may be used to endorse or promote products derived from this software
47: * without specific prior written permission.
48: *
49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59: * SUCH DAMAGE.
60: *
61: * @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95
62: * FreeBSD-Id: nfs_bio.c,v 1.44 1997/09/10 19:52:25 phk Exp $
63: */
64:
65: #include <mach_nbc.h>
66: #include <sys/param.h>
67: #include <sys/systm.h>
68: #include <sys/resourcevar.h>
69: #include <sys/signalvar.h>
70: #include <sys/proc.h>
71: #include <sys/buf.h>
72: #include <sys/vnode.h>
73: #include <sys/mount.h>
74: #include <sys/kernel.h>
75: #include <sys/sysctl.h>
76:
77: #include <sys/vm.h>
78: #include <sys/vmparam.h>
79:
80: #include <nfs/rpcv2.h>
81: #include <nfs/nfsproto.h>
82: #include <nfs/nfs.h>
83: #include <nfs/nfsmount.h>
84: #include <nfs/nqnfs.h>
85: #include <nfs/nfsnode.h>
86:
87: #if MACH_NBC
88: #include <kern/mapfs.h>
89: #endif /* MACH_NBC */
90:
91: /* XXX CSM 11/25/97 Revisit when Ramesh merges vm with buffer cache
92: * Ifdef for FreeBSD-current merged buffer cache. It is unfortunate that these
93: * calls are not in getblk() and brelse() so that they would not be necessary
94: * here.
95: */
96: #ifndef B_VMIO
97: #define vfs_busy_pages(bp, f)
98: #define vfs_unbusy_pages(bp)
99: #endif
100:
101: static struct buf *nfs_getcacheblk __P((struct vnode *vp, daddr_t bn, int size,
102: struct proc *p));
103: static struct buf *nfs_getwriteblk __P((struct vnode *vp, daddr_t bn,
104: int size, struct proc *p,
105: struct ucred *cred, int off, int len));
106:
107: extern int nfs_numasync;
108: extern struct nfsstats nfsstats;
109:
110: /* XXX CSM 12/3/97 Revisit when Ramesh merges vm with buffer cache */
111: #ifdef B_VMIO
112: /*
113: * Vnode op for VM getpages.
114: */
115: int
116: nfs_getpages(ap)
117: struct vop_getpages_args *ap;
118: {
119: int i, bsize;
120: vm_object_t obj;
121: int pcount;
122: struct uio auio;
123: struct iovec aiov;
124: int error;
125: vm_page_t m;
126:
127: if (!(ap->a_vp->v_flag & VVMIO)) {
128: printf("nfs_getpages: called with non-VMIO vnode??\n");
129: return EOPNOTSUPP;
130: }
131:
132: pcount = round_page(ap->a_count) / PAGE_SIZE;
133:
134: obj = ap->a_m[ap->a_reqpage]->object;
135: bsize = ap->a_vp->v_mount->mnt_stat.f_iosize;
136:
137: for (i = 0; i < pcount; i++) {
138: if (i != ap->a_reqpage) {
139: vnode_pager_freepage(ap->a_m[i]);
140: }
141: }
142: m = ap->a_m[ap->a_reqpage];
143:
144: m->busy++;
145: m->flags &= ~PG_BUSY;
146:
147: auio.uio_iov = &aiov;
148: auio.uio_iovcnt = 1;
149: aiov.iov_base = 0;
150: aiov.iov_len = PAGE_SIZE;
151: auio.uio_resid = PAGE_SIZE;
152: auio.uio_offset = IDX_TO_OFF(m->pindex);
153: auio.uio_segflg = UIO_NOCOPY;
154: auio.uio_rw = UIO_READ;
155: auio.uio_procp = curproc;
156: error = nfs_bioread(ap->a_vp, &auio, IO_NODELOCKED, curproc->p_ucred, 1);
157:
158: m->flags |= PG_BUSY;
159: m->busy--;
160:
161: if (error && (auio.uio_resid == PAGE_SIZE))
162: return VM_PAGER_ERROR;
163: return 0;
164: }
165: #endif
166:
167: /*
168: * Vnode op for read using bio
169: * Any similarity to readip() is purely coincidental
170: */
171: int
172: nfs_bioread(vp, uio, ioflag, cred, getpages)
173: register struct vnode *vp;
174: register struct uio *uio;
175: int ioflag;
176: struct ucred *cred;
177: int getpages;
178: {
179: register struct nfsnode *np = VTONFS(vp);
180: register int biosize, diff, i;
181: struct buf *bp = 0, *rabp;
182: struct vattr vattr;
183: struct proc *p;
184: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
185: daddr_t lbn, rabn;
186: int bufsize;
187: int nra, error = 0, n = 0, on = 0, not_readin;
188:
189: #if DIAGNOSTIC
190: if (uio->uio_rw != UIO_READ)
191: panic("nfs_read mode");
192: #endif
193: if (uio->uio_resid == 0)
194: return (0);
195: if (uio->uio_offset < 0)
196: return (EINVAL);
197: p = uio->uio_procp;
198: if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3)
199: (void)nfs_fsinfo(nmp, vp, cred, p);
200: biosize = vp->v_mount->mnt_stat.f_iosize;
201: /*
202: * For nfs, cache consistency can only be maintained approximately.
203: * Although RFC1094 does not specify the criteria, the following is
204: * believed to be compatible with the reference port.
205: * For nqnfs, full cache consistency is maintained within the loop.
206: * For nfs:
207: * If the file's modify time on the server has changed since the
208: * last read rpc or you have written to the file,
209: * you may have lost data cache consistency with the
210: * server, so flush all of the file's data out of the cache.
211: * Then force a getattr rpc to ensure that you have up to date
212: * attributes.
213: * NB: This implies that cache data can be read when up to
214: * NFS_ATTRTIMEO seconds out of date. If you find that you need current
215: * attributes this could be forced by setting n_attrstamp to 0 before
216: * the VOP_GETATTR() call.
217: */
218: if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) {
219: if (np->n_flag & NMODIFIED) {
220: if (vp->v_type != VREG) {
221: if (vp->v_type != VDIR)
222: panic("nfs: bioread, not dir");
223: nfs_invaldir(vp);
224: error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
225: if (error)
226: return (error);
227: }
228: np->n_attrstamp = 0;
229: error = VOP_GETATTR(vp, &vattr, cred, p);
230: if (error)
231: return (error);
232: np->n_mtime = vattr.va_mtime.tv_sec;
233: } else {
234: error = VOP_GETATTR(vp, &vattr, cred, p);
235: if (error)
236: return (error);
237: if (np->n_mtime != vattr.va_mtime.tv_sec) {
238: if (vp->v_type == VDIR)
239: nfs_invaldir(vp);
240: error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
241: if (error)
242: return (error);
243: np->n_mtime = vattr.va_mtime.tv_sec;
244: }
245: }
246: }
247: do {
248:
249: /*
250: * Get a valid lease. If cached data is stale, flush it.
251: */
252: if (nmp->nm_flag & NFSMNT_NQNFS) {
253: if (NQNFS_CKINVALID(vp, np, ND_READ)) {
254: do {
255: error = nqnfs_getlease(vp, ND_READ, cred, p);
256: } while (error == NQNFS_EXPIRED);
257: if (error)
258: return (error);
259: if (np->n_lrev != np->n_brev ||
260: (np->n_flag & NQNFSNONCACHE) ||
261: ((np->n_flag & NMODIFIED) && vp->v_type == VDIR)) {
262: if (vp->v_type == VDIR)
263: nfs_invaldir(vp);
264: error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
265: if (error)
266: return (error);
267: np->n_brev = np->n_lrev;
268: }
269: } else if (vp->v_type == VDIR && (np->n_flag & NMODIFIED)) {
270: nfs_invaldir(vp);
271: error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
272: if (error)
273: return (error);
274: }
275: }
276: if (np->n_flag & NQNFSNONCACHE) {
277: switch (vp->v_type) {
278: case VREG:
279: return (nfs_readrpc(vp, uio, cred));
280: case VLNK:
281: return (nfs_readlinkrpc(vp, uio, cred));
282: case VDIR:
283: break;
284: default:
285: printf(" NQNFSNONCACHE: type %x unexpected\n",
286: vp->v_type);
287: };
288: }
289: switch (vp->v_type) {
290: case VREG:
291: nfsstats.biocache_reads++;
292: lbn = uio->uio_offset / biosize;
293: on = uio->uio_offset & (biosize - 1);
294: not_readin = 1;
295:
296: /*
297: * Start the read ahead(s), as required.
298: */
299: if (nfs_numasync > 0 && nmp->nm_readahead > 0) {
300: for (nra = 0; nra < nmp->nm_readahead &&
301: (off_t)(lbn + 1 + nra) * biosize < np->n_size; nra++) {
302: rabn = lbn + 1 + nra;
303: if (!incore(vp, rabn)) {
304: rabp = nfs_getcacheblk(vp, rabn, biosize, p);
305: if (!rabp)
306: return (EINTR);
307: if ((rabp->b_flags & (B_CACHE|B_DELWRI)) == 0) {
308: rabp->b_flags |= (B_READ | B_ASYNC);
309: vfs_busy_pages(rabp, 0);
310: if (nfs_asyncio(rabp, cred)) {
311: rabp->b_flags |= B_INVAL|B_ERROR;
312: vfs_unbusy_pages(rabp);
313: brelse(rabp);
314: }
315: } else
316: brelse(rabp);
317: }
318: }
319: }
320:
321: /*
322: * If the block is in the cache and has the required data
323: * in a valid region, just copy it out.
324: * Otherwise, get the block and write back/read in,
325: * as required.
326: */
327: again:
328: bufsize = biosize;
329: if ((off_t)(lbn + 1) * biosize > np->n_size &&
330: (off_t)(lbn + 1) * biosize - np->n_size < biosize) {
331: bufsize = np->n_size - lbn * biosize;
332: bufsize = (bufsize + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
333: }
334: bp = nfs_getcacheblk(vp, lbn, bufsize, p);
335: if (!bp)
336: return (EINTR);
337: /* XXX CSM 12/3/97 Revisit when Ramesh merges vm with buffer cache */
338: #ifdef B_VMIO
339: /*
340: * If we are being called from nfs_getpages, we must
341: * make sure the buffer is a vmio buffer. The vp will
342: * already be setup for vmio but there may be some old
343: * non-vmio buffers attached to it.
344: */
345: if (getpages && !(bp->b_flags & B_VMIO)) {
346: #if DIAGNOSTIC
347: printf("nfs_bioread: non vmio buf found, discarding\n");
348: #endif
349: bp->b_flags |= B_NOCACHE;
350: bp->b_flags |= B_INVAFTERWRITE;
351: if (bp->b_dirtyend > 0) {
352: if ((bp->b_flags & B_DELWRI) == 0)
353: panic("nfsbioread");
354: if (VOP_BWRITE(bp) == EINTR)
355: return (EINTR);
356: } else
357: brelse(bp);
358: goto again;
359: }
360: #endif /* B_VMIO */
361: if ((bp->b_flags & B_CACHE) == 0) {
362: bp->b_flags |= B_READ;
363: bp->b_flags &= ~(B_DONE | B_ERROR | B_INVAL);
364: not_readin = 0;
365: vfs_busy_pages(bp, 0);
366: error = nfs_doio(bp, cred, p);
367: if (error) {
368: brelse(bp);
369: return (error);
370: }
371: }
372: if (bufsize > on) {
373: n = min((unsigned)(bufsize - on), uio->uio_resid);
374: } else {
375: n = 0;
376: }
377: diff = np->n_size - uio->uio_offset;
378: if (diff < n)
379: n = diff;
380: if (not_readin && n > 0) {
381: if (on < bp->b_validoff || (on + n) > bp->b_validend) {
382: bp->b_flags |= B_NOCACHE;
383: bp->b_flags |= B_INVAFTERWRITE;
384: if (bp->b_dirtyend > 0) {
385: if ((bp->b_flags & B_DELWRI) == 0)
386: panic("nfsbioread");
387: if (VOP_BWRITE(bp) == EINTR)
388: return (EINTR);
389: } else
390: brelse(bp);
391: goto again;
392: }
393: }
394: vp->v_lastr = lbn;
395: diff = (on >= bp->b_validend) ? 0 : (bp->b_validend - on);
396: if (diff < n)
397: n = diff;
398: break;
399: case VLNK:
400: nfsstats.biocache_readlinks++;
401: bp = nfs_getcacheblk(vp, (daddr_t)0, NFS_MAXPATHLEN, p);
402: if (!bp)
403: return (EINTR);
404: if ((bp->b_flags & B_CACHE) == 0) {
405: bp->b_flags |= B_READ;
406: vfs_busy_pages(bp, 0);
407: error = nfs_doio(bp, cred, p);
408: if (error) {
409: bp->b_flags |= B_ERROR;
410: brelse(bp);
411: return (error);
412: }
413: }
414: n = min(uio->uio_resid, NFS_MAXPATHLEN - bp->b_resid);
415: on = 0;
416: break;
417: case VDIR:
418: nfsstats.biocache_readdirs++;
419: if (np->n_direofoffset
420: && uio->uio_offset >= np->n_direofoffset) {
421: return (0);
422: }
423: lbn = uio->uio_offset / NFS_DIRBLKSIZ;
424: on = uio->uio_offset & (NFS_DIRBLKSIZ - 1);
425: bp = nfs_getcacheblk(vp, lbn, NFS_DIRBLKSIZ, p);
426: if (!bp)
427: return (EINTR);
428: if ((bp->b_flags & B_CACHE) == 0) {
429: bp->b_flags |= B_READ;
430: vfs_busy_pages(bp, 0);
431: error = nfs_doio(bp, cred, p);
432: if (error) {
433: vfs_unbusy_pages(bp);
434: brelse(bp);
435: while (error == NFSERR_BAD_COOKIE) {
436: nfs_invaldir(vp);
437: error = nfs_vinvalbuf(vp, 0, cred, p, 1);
438: /*
439: * Yuck! The directory has been modified on the
440: * server. The only way to get the block is by
441: * reading from the beginning to get all the
442: * offset cookies.
443: */
444: for (i = 0; i <= lbn && !error; i++) {
445: if (np->n_direofoffset
446: && (i * NFS_DIRBLKSIZ) >= np->n_direofoffset)
447: return (0);
448: bp = nfs_getcacheblk(vp, i, NFS_DIRBLKSIZ, p);
449: if (!bp)
450: return (EINTR);
451: if ((bp->b_flags & B_DONE) == 0) {
452: bp->b_flags |= B_READ;
453: vfs_busy_pages(bp, 0);
454: error = nfs_doio(bp, cred, p);
455: if (error) {
456: vfs_unbusy_pages(bp);
457: brelse(bp);
458: } else if (i < lbn)
459: brelse(bp);
460: }
461: }
462: }
463: if (error)
464: return (error);
465: }
466: }
467:
468: /*
469: * If not eof and read aheads are enabled, start one.
470: * (You need the current block first, so that you have the
471: * directory offset cookie of the next block.)
472: */
473: if (nfs_numasync > 0 && nmp->nm_readahead > 0 &&
474: (np->n_direofoffset == 0 ||
475: (lbn + 1) * NFS_DIRBLKSIZ < np->n_direofoffset) &&
476: !(np->n_flag & NQNFSNONCACHE) &&
477: !incore(vp, lbn + 1)) {
478: rabp = nfs_getcacheblk(vp, lbn + 1, NFS_DIRBLKSIZ, p);
479: if (rabp) {
480: if ((rabp->b_flags & (B_CACHE|B_DELWRI)) == 0) {
481: rabp->b_flags |= (B_READ | B_ASYNC);
482: vfs_busy_pages(rabp, 0);
483: if (nfs_asyncio(rabp, cred)) {
484: rabp->b_flags |= B_INVAL|B_ERROR;
485: vfs_unbusy_pages(rabp);
486: brelse(rabp);
487: }
488: } else {
489: brelse(rabp);
490: }
491: }
492: }
493: /*
494: * Make sure we use a signed variant of min() since
495: * the second term may be negative.
496: */
497: n = lmin(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid - on);
498: break;
499: default:
500: printf(" nfs_bioread: type %x unexpected\n",vp->v_type);
501: break;
502: };
503:
504: if (n > 0) {
505: error = uiomove(bp->b_data + on, (int)n, uio);
506: }
507: switch (vp->v_type) {
508: case VREG:
509: break;
510: case VLNK:
511: n = 0;
512: break;
513: case VDIR:
514: if (np->n_flag & NQNFSNONCACHE)
515: bp->b_flags |= B_INVAL;
516: break;
517: default:
518: printf(" nfs_bioread: type %x unexpected\n",vp->v_type);
519: }
520: brelse(bp);
521: } while (error == 0 && uio->uio_resid > 0 && n > 0);
522: return (error);
523: }
524:
525: /*
526: * Vnode op for write using bio
527: */
528: int
529: nfs_write(ap)
530: struct vop_write_args /* {
531: struct vnode *a_vp;
532: struct uio *a_uio;
533: int a_ioflag;
534: struct ucred *a_cred;
535: } */ *ap;
536: {
537: register int biosize;
538: register struct uio *uio = ap->a_uio;
539: struct proc *p = uio->uio_procp;
540: register struct vnode *vp = ap->a_vp;
541: struct nfsnode *np = VTONFS(vp);
542: register struct ucred *cred = ap->a_cred;
543: int ioflag = ap->a_ioflag;
544: struct buf *bp;
545: struct vattr vattr;
546: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
547: daddr_t lbn;
548: int bufsize;
549: int n, on, error = 0, iomode, must_commit;
550:
551: #if DIAGNOSTIC
552: if (uio->uio_rw != UIO_WRITE)
553: panic("nfs_write mode");
554: if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != current_proc())
555: panic("nfs_write proc");
556: #endif
557: if (vp->v_type != VREG)
558: return (EIO);
559: if (np->n_flag & NWRITEERR) {
560: np->n_flag &= ~NWRITEERR;
561: return (np->n_error);
562: }
563: if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3)
564: (void)nfs_fsinfo(nmp, vp, cred, p);
565: if (ioflag & (IO_APPEND | IO_SYNC)) {
566: if (np->n_flag & NMODIFIED) {
567: np->n_attrstamp = 0;
568: error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
569: if (error)
570: return (error);
571: }
572: if (ioflag & IO_APPEND) {
573: np->n_attrstamp = 0;
574: error = VOP_GETATTR(vp, &vattr, cred, p);
575: if (error)
576: return (error);
577: uio->uio_offset = np->n_size;
578: }
579: }
580: if (uio->uio_offset < 0)
581: return (EINVAL);
582: if (uio->uio_resid == 0)
583: return (0);
584: /*
585: * Maybe this should be above the vnode op call, but so long as
586: * file servers have no limits, i don't think it matters
587: */
588: if (p && uio->uio_offset + uio->uio_resid >
589: p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
590: psignal(p, SIGXFSZ);
591: return (EFBIG);
592: }
593: /*
594: * I use nm_rsize, not nm_wsize so that all buffer cache blocks
595: * will be the same size within a filesystem. nfs_writerpc will
596: * still use nm_wsize when sizing the rpc's.
597: */
598: biosize = vp->v_mount->mnt_stat.f_iosize;
599: do {
600: /*
601: * Check for a valid write lease.
602: */
603: if ((nmp->nm_flag & NFSMNT_NQNFS) &&
604: NQNFS_CKINVALID(vp, np, ND_WRITE)) {
605: do {
606: error = nqnfs_getlease(vp, ND_WRITE, cred, p);
607: } while (error == NQNFS_EXPIRED);
608: if (error)
609: return (error);
610: if (np->n_lrev != np->n_brev ||
611: (np->n_flag & NQNFSNONCACHE)) {
612: error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
613: if (error)
614: return (error);
615: np->n_brev = np->n_lrev;
616: }
617: }
618: if ((np->n_flag & NQNFSNONCACHE) && uio->uio_iovcnt == 1) {
619: iomode = NFSV3WRITE_FILESYNC;
620: error = nfs_writerpc(vp, uio, cred, &iomode, &must_commit);
621: if (must_commit)
622: nfs_clearcommit(vp->v_mount);
623: return (error);
624: }
625: nfsstats.biocache_writes++;
626: lbn = uio->uio_offset / biosize;
627: on = uio->uio_offset & (biosize-1);
628: n = min((unsigned)(biosize - on), uio->uio_resid);
629: again:
630: if (uio->uio_offset + n > np->n_size) {
631: np->n_size = uio->uio_offset + n;
632: np->n_flag |= NMODIFIED;
633: #if MACH_NBC
634: if ((vp->v_type == VREG) && (vp->v_vm_info && !(vp->v_vm_info->mapped))) {
635: #endif /* MACH_NBC */
636: vnode_pager_setsize(vp, (u_long)np->n_size);
637: #if MACH_NBC
638: }
639: #endif /* MACH_NBC */
640:
641: }
642: bufsize = biosize;
643: if ((lbn + 1) * biosize > np->n_size) {
644: bufsize = np->n_size - lbn * biosize;
645: bufsize = (bufsize + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
646: }
647: bp = nfs_getwriteblk(vp, lbn, bufsize, p, cred, on, n);
648: if (!bp)
649: return (EINTR);
650: if (bp->b_wcred == NOCRED) {
651: crhold(cred);
652: bp->b_wcred = cred;
653: }
654: np->n_flag |= NMODIFIED;
655:
656: /*
657: * Check for valid write lease and get one as required.
658: * In case getblk() and/or bwrite() delayed us.
659: */
660: if ((nmp->nm_flag & NFSMNT_NQNFS) &&
661: NQNFS_CKINVALID(vp, np, ND_WRITE)) {
662: do {
663: error = nqnfs_getlease(vp, ND_WRITE, cred, p);
664: } while (error == NQNFS_EXPIRED);
665: if (error) {
666: brelse(bp);
667: return (error);
668: }
669: if (np->n_lrev != np->n_brev ||
670: (np->n_flag & NQNFSNONCACHE)) {
671: brelse(bp);
672: error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
673: if (error)
674: return (error);
675: np->n_brev = np->n_lrev;
676: goto again;
677: }
678: }
679: error = uiomove((char *)bp->b_data + on, n, uio);
680: if (error) {
681: bp->b_flags |= B_ERROR;
682: brelse(bp);
683: return (error);
684: }
685: if (bp->b_dirtyend > 0) {
686: bp->b_dirtyoff = min(on, bp->b_dirtyoff);
687: bp->b_dirtyend = max((on + n), bp->b_dirtyend);
688: } else {
689: bp->b_dirtyoff = on;
690: bp->b_dirtyend = on + n;
691: }
692: if (bp->b_validend == 0 || bp->b_validend < bp->b_dirtyoff ||
693: bp->b_validoff > bp->b_dirtyend) {
694: bp->b_validoff = bp->b_dirtyoff;
695: bp->b_validend = bp->b_dirtyend;
696: } else {
697: bp->b_validoff = min(bp->b_validoff, bp->b_dirtyoff);
698: bp->b_validend = max(bp->b_validend, bp->b_dirtyend);
699: }
700:
701: /*
702: * Since this block is being modified, it must be written
703: * again and not just committed.
704: */
705: bp->b_flags &= ~B_NEEDCOMMIT;
706:
707: /*
708: * If the lease is non-cachable or IO_SYNC do bwrite().
709: */
710: if ((np->n_flag & NQNFSNONCACHE) || (ioflag & IO_SYNC)) {
711: bp->b_proc = p;
712: error = VOP_BWRITE(bp);
713: if (error)
714: return (error);
715: if (np->n_flag & NQNFSNONCACHE) {
716: error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
717: if (error)
718: return (error);
719: }
720: } else if ((n + on) == biosize &&
721: (nmp->nm_flag & NFSMNT_NQNFS) == 0) {
722: bp->b_proc = (struct proc *)0;
723: bp->b_flags |= B_ASYNC;
724: (void)nfs_writebp(bp, 0);
725: } else
726: bdwrite(bp);
727: } while (uio->uio_resid > 0 && n > 0);
728: return (0);
729: }
730:
731: /*
732: * Get a cache block for writing. The range to be written is
733: * (off..off+len) within the block. This routine ensures that the
734: * block is either has no dirty region or that the given range is
735: * contiguous with the existing dirty region.
736: */
737: static struct buf *
738: nfs_getwriteblk(vp, bn, size, p, cred, off, len)
739: struct vnode *vp;
740: daddr_t bn;
741: int size;
742: struct proc *p;
743: struct ucred *cred;
744: int off, len;
745: {
746: struct nfsnode *np = VTONFS(vp);
747: struct buf *bp;
748: int error;
749:
750: again:
751: bp = nfs_getcacheblk(vp, bn, size, p);
752: if (!bp)
753: return (NULL);
754: if (bp->b_wcred == NOCRED) {
755: crhold(cred);
756: bp->b_wcred = cred;
757: }
758:
759: if ((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend > np->n_size) {
760: bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);
761: }
762:
763: /*
764: * If the new write will leave a contiguous dirty
765: * area, just update the b_dirtyoff and b_dirtyend,
766: * otherwise try to extend the dirty region.
767: */
768: if (bp->b_dirtyend > 0 &&
769: (off > bp->b_dirtyend || (off + len) < bp->b_dirtyoff)) {
770: struct iovec iov;
771: struct uio uio;
772: off_t boff, start, end;
773:
774: boff = ((off_t)bp->b_blkno) * DEV_BSIZE;
775: if (off > bp->b_dirtyend) {
776: start = boff + bp->b_validend;
777: end = boff + off;
778: } else {
779: start = boff + off + len;
780: end = boff + bp->b_validoff;
781: }
782:
783: /*
784: * It may be that the valid region in the buffer
785: * covers the region we want, in which case just
786: * extend the dirty region. Otherwise we try to
787: * extend the valid region.
788: */
789: if (end > start) {
790: uio.uio_iov = &iov;
791: uio.uio_iovcnt = 1;
792: uio.uio_offset = start;
793: uio.uio_resid = end - start;
794: uio.uio_segflg = UIO_SYSSPACE;
795: uio.uio_rw = UIO_READ;
796: uio.uio_procp = p;
797: iov.iov_base = bp->b_data + (start - boff);
798: iov.iov_len = end - start;
799: error = nfs_readrpc(vp, &uio, cred);
800: if (error) {
801: /*
802: * If we couldn't read, fall back to writing
803: * out the old dirty region.
804: */
805: bp->b_proc = p;
806: if (VOP_BWRITE(bp) == EINTR)
807: return (NULL);
808: goto again;
809: } else {
810: /*
811: * The read worked.
812: */
813: if (uio.uio_resid > 0) {
814: /*
815: * If there was a short read,
816: * just zero fill.
817: */
818: bzero(iov.iov_base,
819: uio.uio_resid);
820: }
821: if (off > bp->b_dirtyend)
822: bp->b_validend = off;
823: else
824: bp->b_validoff = off + len;
825: }
826: }
827:
828: /*
829: * We now have a valid region which extends up to the
830: * dirty region which we want.
831: */
832: if (off > bp->b_dirtyend)
833: bp->b_dirtyend = off;
834: else
835: bp->b_dirtyoff = off + len;
836: }
837:
838: return bp;
839: }
840:
841: /*
842: * Get an nfs cache block.
843: * Allocate a new one if the block isn't currently in the cache
844: * and return the block marked busy. If the calling process is
845: * interrupted by a signal for an interruptible mount point, return
846: * NULL.
847: */
848: static struct buf *
849: nfs_getcacheblk(vp, bn, size, p)
850: struct vnode *vp;
851: daddr_t bn;
852: int size;
853: struct proc *p;
854: {
855: register struct buf *bp;
856: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
857: int biosize = vp->v_mount->mnt_stat.f_iosize;
858:
859: if (nmp->nm_flag & NFSMNT_INT) {
860: bp = getblk(vp, bn, size, PCATCH, 0);
861: while (bp == (struct buf *)0) {
862: if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
863: return ((struct buf *)0);
864: bp = getblk(vp, bn, size, 0, 2 * hz);
865: }
866: } else
867: bp = getblk(vp, bn, size, 0, 0);
868:
869: if( vp->v_type == VREG)
870: bp->b_blkno = (bn * biosize) / DEV_BSIZE;
871:
872: return (bp);
873: }
874:
875: /*
876: * Flush and invalidate all dirty buffers. If another process is already
877: * doing the flush, just wait for completion.
878: */
879: int
880: nfs_vinvalbuf(vp, flags, cred, p, intrflg)
881: struct vnode *vp;
882: int flags;
883: struct ucred *cred;
884: struct proc *p;
885: int intrflg;
886: {
887: register struct nfsnode *np = VTONFS(vp);
888: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
889: int error = 0, slpflag, slptimeo;
890:
891: if ((nmp->nm_flag & NFSMNT_INT) == 0)
892: intrflg = 0;
893: if (intrflg) {
894: slpflag = PCATCH;
895: slptimeo = 2 * hz;
896: } else {
897: slpflag = 0;
898: slptimeo = 0;
899: }
900: /*
901: * First wait for any other process doing a flush to complete.
902: */
903: while (np->n_flag & NFLUSHINPROG) {
904: np->n_flag |= NFLUSHWANT;
905: error = tsleep((caddr_t)&np->n_flag, PRIBIO + 2, "nfsvinval",
906: slptimeo);
907: if (error && intrflg && nfs_sigintr(nmp, (struct nfsreq *)0, p))
908: return (EINTR);
909: }
910:
911: /*
912: * Now, flush as required.
913: */
914: np->n_flag |= NFLUSHINPROG;
915: error = vinvalbuf(vp, flags, cred, p, slpflag, 0);
916: while (error) {
917: if (intrflg && nfs_sigintr(nmp, (struct nfsreq *)0, p)) {
918: np->n_flag &= ~NFLUSHINPROG;
919: if (np->n_flag & NFLUSHWANT) {
920: np->n_flag &= ~NFLUSHWANT;
921: wakeup((caddr_t)&np->n_flag);
922: }
923: return (EINTR);
924: }
925: error = vinvalbuf(vp, flags, cred, p, 0, slptimeo);
926: }
927: np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
928: if (np->n_flag & NFLUSHWANT) {
929: np->n_flag &= ~NFLUSHWANT;
930: wakeup((caddr_t)&np->n_flag);
931: }
932: return (0);
933: }
934:
935: /*
936: * Initiate asynchronous I/O. Return an error if no nfsiods are available.
937: * This is mainly to avoid queueing async I/O requests when the nfsiods
938: * are all hung on a dead server.
939: */
940: int
941: nfs_asyncio(bp, cred)
942: register struct buf *bp;
943: struct ucred *cred;
944: {
945: struct nfsmount *nmp;
946: int i;
947: int gotiod;
948: int slpflag = 0;
949: int slptimeo = 0;
950: int error;
951:
952: if (nfs_numasync == 0)
953: return (EIO);
954:
955: nmp = VFSTONFS(bp->b_vp->v_mount);
956: again:
957: if (nmp->nm_flag & NFSMNT_INT)
958: slpflag = PCATCH;
959: gotiod = FALSE;
960:
961: /*
962: * Find a free iod to process this request.
963: */
964: for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
965: if (nfs_iodwant[i]) {
966: /*
967: * Found one, so wake it up and tell it which
968: * mount to process.
969: */
970: NFS_DPF(ASYNCIO,
971: ("nfs_asyncio: waking iod %d for mount %p\n",
972: i, nmp));
973: nfs_iodwant[i] = (struct proc *)0;
974: nfs_iodmount[i] = nmp;
975: nmp->nm_bufqiods++;
976: wakeup((caddr_t)&nfs_iodwant[i]);
977: gotiod = TRUE;
978: break;
979: }
980:
981: /*
982: * If none are free, we may already have an iod working on this mount
983: * point. If so, it will process our request.
984: */
985: if (!gotiod) {
986: if (nmp->nm_bufqiods > 0) {
987: NFS_DPF(ASYNCIO,
988: ("nfs_asyncio: %d iods are already processing mount %p\n",
989: nmp->nm_bufqiods, nmp));
990: gotiod = TRUE;
991: }
992: }
993:
994: /*
995: * If we have an iod which can process the request, then queue
996: * the buffer.
997: */
998: if (gotiod) {
999: /*
1000: * Ensure that the queue never grows too large.
1001: */
1002: while (nmp->nm_bufqlen >= 2*nfs_numasync) {
1003: NFS_DPF(ASYNCIO,
1004: ("nfs_asyncio: waiting for mount %p queue to drain\n", nmp));
1005: nmp->nm_bufqwant = TRUE;
1006: error = tsleep(&nmp->nm_bufq, slpflag | PRIBIO,
1007: "nfsaio", slptimeo);
1008: if (error) {
1009: if (nfs_sigintr(nmp, NULL, bp->b_proc))
1010: return (EINTR);
1011: if (slpflag == PCATCH) {
1012: slpflag = 0;
1013: slptimeo = 2 * hz;
1014: }
1015: }
1016: /*
1017: * We might have lost our iod while sleeping,
1018: * so check and loop if nescessary.
1019: */
1020: if (nmp->nm_bufqiods == 0) {
1021: NFS_DPF(ASYNCIO,
1022: ("nfs_asyncio: no iods after mount %p queue was drained, looping\n", nmp));
1023: goto again;
1024: }
1025: }
1026:
1027: if (bp->b_flags & B_READ) {
1028: if (bp->b_rcred == NOCRED && cred != NOCRED) {
1029: crhold(cred);
1030: bp->b_rcred = cred;
1031: }
1032: } else {
1033: bp->b_flags |= B_WRITEINPROG;
1034: if (bp->b_wcred == NOCRED && cred != NOCRED) {
1035: crhold(cred);
1036: bp->b_wcred = cred;
1037: }
1038: }
1039:
1040: TAILQ_INSERT_TAIL(&nmp->nm_bufq, bp, b_freelist);
1041: nmp->nm_bufqlen++;
1042: return (0);
1043: }
1044:
1045: /*
1046: * All the iods are busy on other mounts, so return EIO to
1047: * force the caller to process the i/o synchronously.
1048: */
1049: NFS_DPF(ASYNCIO, ("nfs_asyncio: no iods available, i/o is synchronous\n"));
1050: return (EIO);
1051: }
1052:
1053: /*
1054: * Do an I/O operation to/from a cache block. This may be called
1055: * synchronously or from an nfsiod.
1056: */
1057: int
1058: nfs_doio(bp, cr, p)
1059: register struct buf *bp;
1060: struct ucred *cr;
1061: struct proc *p;
1062: {
1063: register struct uio *uiop;
1064: register struct vnode *vp;
1065: struct nfsnode *np;
1066: struct nfsmount *nmp;
1067: int error = 0, diff, len, iomode, must_commit = 0;
1068: struct uio uio;
1069: struct iovec io;
1070:
1071: vp = bp->b_vp;
1072: NFSTRACE(NFSTRC_DIO, vp);
1073: np = VTONFS(vp);
1074: nmp = VFSTONFS(vp->v_mount);
1075: uiop = &uio;
1076: uiop->uio_iov = &io;
1077: uiop->uio_iovcnt = 1;
1078: uiop->uio_segflg = UIO_SYSSPACE;
1079: uiop->uio_procp = p;
1080:
1081: /*
1082: * Historically, paging was done with physio, but no more.
1083: */
1084: if (bp->b_flags & B_PHYS) {
1085: /*
1086: * ...though reading /dev/drum still gets us here.
1087: */
1088: io.iov_len = uiop->uio_resid = bp->b_bcount;
1089: /* mapping was done by vmapbuf() */
1090: io.iov_base = bp->b_data;
1091: uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
1092: if (bp->b_flags & B_READ) {
1093: uiop->uio_rw = UIO_READ;
1094: nfsstats.read_physios++;
1095: error = nfs_readrpc(vp, uiop, cr);
1096: } else {
1097: int com;
1098:
1099: iomode = NFSV3WRITE_DATASYNC;
1100: uiop->uio_rw = UIO_WRITE;
1101: nfsstats.write_physios++;
1102: error = nfs_writerpc(vp, uiop, cr, &iomode, &com);
1103: }
1104: if (error) {
1105: bp->b_flags |= B_ERROR;
1106: bp->b_error = error;
1107: }
1108: } else if (bp->b_flags & B_READ) {
1109: io.iov_len = uiop->uio_resid = bp->b_bcount;
1110: io.iov_base = bp->b_data;
1111: uiop->uio_rw = UIO_READ;
1112: switch (vp->v_type) {
1113: case VREG:
1114: uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
1115: nfsstats.read_bios++;
1116: error = nfs_readrpc(vp, uiop, cr);
1117: if (!error) {
1118: bp->b_validoff = 0;
1119: if (uiop->uio_resid) {
1120: /*
1121: * If len > 0, there is a hole in the file and
1122: * no writes after the hole have been pushed to
1123: * the server yet.
1124: * Just zero fill the rest of the valid area.
1125: */
1126: diff = bp->b_bcount - uiop->uio_resid;
1127: len = np->n_size - (((u_quad_t)bp->b_blkno) * DEV_BSIZE
1128: + diff);
1129: if (len > 0) {
1130: len = min(len, uiop->uio_resid);
1131: bzero((char *)bp->b_data + diff, len);
1132: bp->b_validend = diff + len;
1133: } else
1134: bp->b_validend = diff;
1135: } else
1136: bp->b_validend = bp->b_bcount;
1137: }
1138: if (p && (vp->v_flag & VTEXT) &&
1139: (((nmp->nm_flag & NFSMNT_NQNFS) &&
1140: NQNFS_CKINVALID(vp, np, ND_READ) &&
1141: np->n_lrev != np->n_brev) ||
1142: (!(nmp->nm_flag & NFSMNT_NQNFS) &&
1143: np->n_mtime != np->n_vattr.va_mtime.tv_sec))) {
1144: uprintf("Process killed due to text file modification\n");
1145: psignal(p, SIGKILL);
1146: p->p_flag |= P_NOSWAP;
1147: }
1148: break;
1149: case VLNK:
1150: uiop->uio_offset = (off_t)0;
1151: nfsstats.readlink_bios++;
1152: error = nfs_readlinkrpc(vp, uiop, cr);
1153: break;
1154: case VDIR:
1155: nfsstats.readdir_bios++;
1156: uiop->uio_offset = ((u_quad_t)bp->b_lblkno) * NFS_DIRBLKSIZ;
1157: if (!(nmp->nm_flag & NFSMNT_NFSV3))
1158: nmp->nm_flag &= ~NFSMNT_RDIRPLUS; /* [email protected] */
1159: if (nmp->nm_flag & NFSMNT_RDIRPLUS) {
1160: error = nfs_readdirplusrpc(vp, uiop, cr);
1161: if (error == NFSERR_NOTSUPP)
1162: nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
1163: }
1164: if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0)
1165: error = nfs_readdirrpc(vp, uiop, cr);
1166: break;
1167: default:
1168: printf("nfs_doio: type %x unexpected\n",vp->v_type);
1169: break;
1170: };
1171: if (error) {
1172: bp->b_flags |= B_ERROR;
1173: bp->b_error = error;
1174: }
1175: } else {
1176: if (((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend) > np->n_size)
1177: bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);
1178:
1179: if (bp->b_dirtyend > bp->b_dirtyoff) {
1180: io.iov_len = uiop->uio_resid = bp->b_dirtyend
1181: - bp->b_dirtyoff;
1182: uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE
1183: + bp->b_dirtyoff;
1184: io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
1185: uiop->uio_rw = UIO_WRITE;
1186: nfsstats.write_bios++;
1187: /* XXX CSM 12/3/97 Revisit when buffer cache upgraded */
1188: #ifdef notyet
1189: if ((bp->b_flags & (B_ASYNC | B_NEEDCOMMIT | B_NOCACHE | B_CLUSTER)) == B_ASYNC)
1190: #else
1191: if ((bp->b_flags & (B_ASYNC | B_NEEDCOMMIT | B_NOCACHE)) == B_ASYNC)
1192: #endif
1193: iomode = NFSV3WRITE_UNSTABLE;
1194: else
1195: iomode = NFSV3WRITE_FILESYNC;
1196: bp->b_flags |= B_WRITEINPROG;
1197: error = nfs_writerpc(vp, uiop, cr, &iomode, &must_commit);
1198: if (!error && iomode == NFSV3WRITE_UNSTABLE) {
1199: bp->b_flags |= B_NEEDCOMMIT;
1200: /* XXX CSM 12/3/97 Revisit when buffer cache upgraded */
1201: #ifdef notyet
1202: if (bp->b_dirtyoff == 0
1203: && bp->b_dirtyend == bp->b_bufsize)
1204: bp->b_flags |= B_CLUSTEROK;
1205: #endif
1206: } else
1207: bp->b_flags &= ~B_NEEDCOMMIT;
1208: bp->b_flags &= ~B_WRITEINPROG;
1209:
1210: /*
1211: * For an interrupted write, the buffer is still valid
1212: * and the write hasn't been pushed to the server yet,
1213: * so we can't set B_ERROR and report the interruption
1214: * by setting B_EINTR. For the B_ASYNC case, B_EINTR
1215: * is not relevant, so the rpc attempt is essentially
1216: * a noop. For the case of a V3 write rpc not being
1217: * committed to stable storage, the block is still
1218: * dirty and requires either a commit rpc or another
1219: * write rpc with iomode == NFSV3WRITE_FILESYNC before
1220: * the block is reused. This is indicated by setting
1221: * the B_DELWRI and B_NEEDCOMMIT flags.
1222: */
1223: if (error == EINTR
1224: || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
1225: int s;
1226:
1227: bp->b_flags &= ~(B_INVAL|B_NOCACHE);
1228: /* XXX CSM 12/3/97 Revisit when buffer cache upgraded */
1229: #ifdef notyet
1230: ++numdirtybuffers;
1231: #endif
1232: bp->b_flags |= B_DELWRI;
1233:
1234: /*
1235: * Since for the B_ASYNC case, nfs_bwrite() has reassigned the
1236: * buffer to the clean list, we have to reassign it back to the
1237: * dirty one. Ugh.
1238: */
1239: if (bp->b_flags & B_ASYNC) {
1240: s = splbio();
1241: reassignbuf(bp, vp);
1242: splx(s);
1243: } else
1244: bp->b_flags |= B_EINTR;
1245: } else {
1246: if (error) {
1247: bp->b_flags |= B_ERROR;
1248: bp->b_error = np->n_error = error;
1249: np->n_flag |= NWRITEERR;
1250: }
1251: bp->b_dirtyoff = bp->b_dirtyend = 0;
1252: }
1253: } else {
1254: bp->b_resid = 0;
1255: biodone(bp);
1256: NFSTRACE(NFSTRC_DIO_DONE, vp);
1257: return (0);
1258: }
1259: }
1260: bp->b_resid = uiop->uio_resid;
1261: if (must_commit)
1262: nfs_clearcommit(vp->v_mount);
1263: biodone(bp);
1264: NFSTRACE(NFSTRC_DIO_DONE, vp);
1265: return (error);
1266: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.