|
|
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.