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