update from Rick Macklem (including leases)
authorKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Wed, 15 Jan 1992 04:41:38 +0000 (20:41 -0800)
committerKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Wed, 15 Jan 1992 04:41:38 +0000 (20:41 -0800)
SCCS-vsn: sys/nfs/xdr_subs.h 7.4
SCCS-vsn: sys/nfs/nfsproto.h 7.9
SCCS-vsn: sys/nfs/nfsrvcache.h 7.4
SCCS-vsn: sys/nfs/nfsnode.h 7.16
SCCS-vsn: sys/nfs/nfsm_subs.h 7.12
SCCS-vsn: sys/nfs/nfsmount.h 7.9
SCCS-vsn: sys/nfs/nfs_subs.c 7.45
SCCS-vsn: sys/nfs/rpcv2.h 7.5
SCCS-vsn: sys/nfs/nfs_serv.c 7.43
SCCS-vsn: sys/nfs/nfs_srvcache.c 7.12
SCCS-vsn: sys/nfs/nfs_node.c 7.36
SCCS-vsn: sys/nfs/nfs_syscalls.c 7.27
SCCS-vsn: sys/nfs/nfs_vfsops.c 7.36
SCCS-vsn: sys/nfs/nfs_vnops.c 7.65
SCCS-vsn: sys/nfs/nfs_socket.c 7.24
SCCS-vsn: sys/nfs/nfsdiskless.h 7.2
SCCS-vsn: sys/nfs/nfs_bio.c 7.21
SCCS-vsn: sys/nfs/nfs_nqlease.c 7.2

18 files changed:
usr/src/sys/nfs/nfs_bio.c
usr/src/sys/nfs/nfs_node.c
usr/src/sys/nfs/nfs_nqlease.c
usr/src/sys/nfs/nfs_serv.c
usr/src/sys/nfs/nfs_socket.c
usr/src/sys/nfs/nfs_srvcache.c
usr/src/sys/nfs/nfs_subs.c
usr/src/sys/nfs/nfs_syscalls.c
usr/src/sys/nfs/nfs_vfsops.c
usr/src/sys/nfs/nfs_vnops.c
usr/src/sys/nfs/nfsdiskless.h
usr/src/sys/nfs/nfsm_subs.h
usr/src/sys/nfs/nfsmount.h
usr/src/sys/nfs/nfsnode.h
usr/src/sys/nfs/nfsproto.h
usr/src/sys/nfs/nfsrvcache.h
usr/src/sys/nfs/rpcv2.h
usr/src/sys/nfs/xdr_subs.h

index 04c825e..9c999cd 100644 (file)
@@ -7,24 +7,24 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_bio.c   7.20 (Berkeley) %G%
+ *     @(#)nfs_bio.c   7.21 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
+#include "resourcevar.h"
 #include "proc.h"
 #include "buf.h"
 #include "proc.h"
 #include "buf.h"
-#include "uio.h"
-#include "namei.h"
 #include "vnode.h"
 #include "trace.h"
 #include "mount.h"
 #include "vnode.h"
 #include "trace.h"
 #include "mount.h"
-#include "resourcevar.h"
-
+#include "kernel.h"
+#include "machine/endian.h"
+#include "nfsnode.h"
+#include "rpcv2.h"
 #include "nfsv2.h"
 #include "nfs.h"
 #include "nfsv2.h"
 #include "nfs.h"
-#include "nfsnode.h"
-#include "nfsiom.h"
 #include "nfsmount.h"
 #include "nfsmount.h"
+#include "nqnfs.h"
 
 /* True and false, how exciting */
 #define        TRUE    1
 
 /* True and false, how exciting */
 #define        TRUE    1
@@ -44,9 +44,10 @@ nfs_bioread(vp, uio, ioflag, cred)
        register int biosize;
        struct buf *bp;
        struct vattr vattr;
        register int biosize;
        struct buf *bp;
        struct vattr vattr;
-       daddr_t lbn, bn, rablock;
-       int diff, error = 0;
-       long n, on;
+       struct nfsmount *nmp;
+       daddr_t lbn, bn, rablock[NFS_MAXRAHEAD];
+       int rasize[NFS_MAXRAHEAD], nra, diff, error = 0;
+       int n, on;
 
 #ifdef lint
        ioflag = ioflag;
 
 #ifdef lint
        ioflag = ioflag;
@@ -59,32 +60,40 @@ nfs_bioread(vp, uio, ioflag, cred)
                return (0);
        if (uio->uio_offset < 0 && vp->v_type != VDIR)
                return (EINVAL);
                return (0);
        if (uio->uio_offset < 0 && vp->v_type != VDIR)
                return (EINVAL);
-       biosize = VFSTONFS(vp->v_mount)->nm_rsize;
+       nmp = VFSTONFS(vp->v_mount);
+       biosize = nmp->nm_rsize;
        /*
        /*
+        * For nfs, cache consistency can only be maintained approximately.
+        * Although RFC1094 does not specify the criteria, the following is
+        * believed to be compatible with the reference port.
+        * For nqnfs, full cache consistency is maintained within the loop.
+        * For nfs:
         * If the file's modify time on the server has changed since the
         * last read rpc or you have written to the file,
         * you may have lost data cache consistency with the
         * server, so flush all of the file's data out of the cache.
         * Then force a getattr rpc to ensure that you have up to date
         * attributes.
         * If the file's modify time on the server has changed since the
         * last read rpc or you have written to the file,
         * you may have lost data cache consistency with the
         * server, so flush all of the file's data out of the cache.
         * Then force a getattr rpc to ensure that you have up to date
         * attributes.
+        * The mount flag NFSMNT_MYWRITE says "Assume that my writes are
+        * the ones changing the modify time.
         * NB: This implies that cache data can be read when up to
         * NFS_ATTRTIMEO seconds out of date. If you find that you need current
         * attributes this could be forced by setting n_attrstamp to 0 before
         * NB: This implies that cache data can be read when up to
         * NFS_ATTRTIMEO seconds out of date. If you find that you need current
         * attributes this could be forced by setting n_attrstamp to 0 before
-        * the nfs_dogetattr() call.
+        * the nfs_getattr() call.
         */
         */
-       if (vp->v_type != VLNK) {
+       if ((nmp->nm_flag & NFSMNT_NQNFS) == 0 && vp->v_type != VLNK) {
                if (np->n_flag & NMODIFIED) {
                        np->n_flag &= ~NMODIFIED;
                if (np->n_flag & NMODIFIED) {
                        np->n_flag &= ~NMODIFIED;
-                       vinvalbuf(vp, TRUE);
+                       if ((nmp->nm_flag & NFSMNT_MYWRITE) == 0 ||
+                            vp->v_type != VREG)
+                               vinvalbuf(vp, TRUE);
                        np->n_attrstamp = 0;
                        np->n_direofoffset = 0;
                        np->n_attrstamp = 0;
                        np->n_direofoffset = 0;
-                       if (error = nfs_dogetattr(vp, &vattr, cred, 1,
-                           uio->uio_procp))
+                       if (error = nfs_getattr(vp, &vattr, cred, uio->uio_procp))
                                return (error);
                        np->n_mtime = vattr.va_mtime.tv_sec;
                } else {
                                return (error);
                        np->n_mtime = vattr.va_mtime.tv_sec;
                } else {
-                       if (error = nfs_dogetattr(vp, &vattr, cred, 1,
-                           uio->uio_procp))
+                       if (error = nfs_getattr(vp, &vattr, cred, uio->uio_procp))
                                return (error);
                        if (np->n_mtime != vattr.va_mtime.tv_sec) {
                                np->n_direofoffset = 0;
                                return (error);
                        if (np->n_mtime != vattr.va_mtime.tv_sec) {
                                np->n_direofoffset = 0;
@@ -94,6 +103,42 @@ nfs_bioread(vp, uio, ioflag, cred)
                }
        }
        do {
                }
        }
        do {
+
+           /*
+            * Get a valid lease. If cached data is stale, flush it.
+            */
+           if ((nmp->nm_flag & NFSMNT_NQNFS) &&
+               NQNFS_CKINVALID(vp, np, NQL_READ)) {
+               do {
+                       error = nqnfs_getlease(vp, NQL_READ, cred, uio->uio_procp);
+               } while (error == NQNFS_EXPIRED);
+               if (error)
+                       return (error);
+               if (QUADNE(np->n_lrev, np->n_brev) ||
+                   ((np->n_flag & NMODIFIED) && vp->v_type == VDIR)) {
+                       if (vp->v_type == VDIR) {
+                               np->n_direofoffset = 0;
+                               cache_purge(vp);
+                       }
+                       np->n_flag &= ~NMODIFIED;
+                       vinvalbuf(vp, TRUE);
+                       np->n_brev = np->n_lrev;
+               }
+           }
+           if (np->n_flag & NQNFSNONCACHE) {
+               switch (vp->v_type) {
+               case VREG:
+                       error = nfs_readrpc(vp, uio, cred);
+                       break;
+               case VLNK:
+                       error = nfs_readlinkrpc(vp, uio, cred);
+                       break;
+               case VDIR:
+                       error = nfs_readdirrpc(vp, uio, cred);
+                       break;
+               };
+               return (error);
+           }
            switch (vp->v_type) {
            case VREG:
                nfsstats.biocache_reads++;
            switch (vp->v_type) {
            case VREG:
                nfsstats.biocache_reads++;
@@ -106,13 +151,32 @@ nfs_bioread(vp, uio, ioflag, cred)
                if (diff < n)
                        n = diff;
                bn = lbn*(biosize/DEV_BSIZE);
                if (diff < n)
                        n = diff;
                bn = lbn*(biosize/DEV_BSIZE);
-               rablock = (lbn+1)*(biosize/DEV_BSIZE);
-               if (vp->v_lastr + 1 == lbn &&
-                   np->n_size > (rablock * DEV_BSIZE))
-                       error = breada(vp, bn, biosize, rablock, biosize,
+               for (nra = 0; nra < nmp->nm_readahead &&
+                       (lbn + 1 + nra) * biosize < np->n_size; nra++) {
+                       rablock[nra] = (lbn + 1 + nra) * (biosize / DEV_BSIZE);
+                       rasize[nra] = biosize;
+               }
+again:
+               if (nra > 0 && lbn >= vp->v_lastr)
+                       error = breadn(vp, bn, biosize, rablock, rasize, nra,
                                cred, &bp);
                else
                        error = bread(vp, bn, biosize, cred, &bp);
                                cred, &bp);
                else
                        error = bread(vp, bn, biosize, cred, &bp);
+               if (bp->b_validend > 0) {
+                       if (on < bp->b_validoff || (on+n) > bp->b_validend) {
+                               bp->b_flags |= B_INVAL;
+                               if (bp->b_dirtyend > 0) {
+                                       if ((bp->b_flags & B_DELWRI) == 0)
+                                               panic("nfsbioread");
+                                       (void) bwrite(bp);
+                               } else
+                                       brelse(bp);
+                               goto again;
+                       }
+               } else {
+                       bp->b_validoff = 0;
+                       bp->b_validend = biosize - bp->b_resid;
+               }
                vp->v_lastr = lbn;
                if (bp->b_resid) {
                   diff = (on >= (biosize-bp->b_resid)) ? 0 :
                vp->v_lastr = lbn;
                if (bp->b_resid) {
                   diff = (on >= (biosize-bp->b_resid)) ? 0 :
@@ -137,6 +201,47 @@ nfs_bioread(vp, uio, ioflag, cred)
                brelse(bp);
                return (error);
            }
                brelse(bp);
                return (error);
            }
+
+           /*
+            * For nqnfs:
+            * Must check for valid lease, since it may have expired while in
+            * bread(). If expired, get a lease.
+            * If data is stale, flush and try again.
+            * nb: If a read rpc is done by bread() or breada() and there is
+            *     no valid lease, a get_lease request will be piggy backed.
+            */
+           if (nmp->nm_flag & NFSMNT_NQNFS) {
+               if (NQNFS_CKINVALID(vp, np, NQL_READ)) {
+                       do {
+                               error = nqnfs_getlease(vp, NQL_READ, cred, uio->uio_procp);
+                       } while (error == NQNFS_EXPIRED);
+                       if (error) {
+                               brelse(bp);
+                               return (error);
+                       }
+                       if ((np->n_flag & NQNFSNONCACHE) ||
+                           QUADNE(np->n_lrev, np->n_brev) ||
+                           ((np->n_flag & NMODIFIED) && vp->v_type == VDIR)) {
+                               if (vp->v_type == VDIR) {
+                                       np->n_direofoffset = 0;
+                                       cache_purge(vp);
+                               }
+                               brelse(bp);
+                               np->n_flag &= ~NMODIFIED;
+                               vinvalbuf(vp, TRUE);
+                               np->n_brev = np->n_lrev;
+                               continue;
+                       }
+               } else if ((np->n_flag & NQNFSNONCACHE) ||
+                   ((np->n_flag & NMODIFIED) && vp->v_type == VDIR)) {
+                       np->n_direofoffset = 0;
+                       brelse(bp);
+                       np->n_flag &= ~NMODIFIED;
+                       vinvalbuf(vp, TRUE);
+                       np->n_brev = np->n_lrev;
+                       continue;
+               }
+           }
            if (n > 0)
                error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
            switch (vp->v_type) {
            if (n > 0)
                error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
            switch (vp->v_type) {
@@ -165,11 +270,12 @@ nfs_write(vp, uio, ioflag, cred)
        int ioflag;
        struct ucred *cred;
 {
        int ioflag;
        struct ucred *cred;
 {
-       struct proc *p = uio->uio_procp;
        register int biosize;
        register int biosize;
+       struct proc *p = uio->uio_procp;
        struct buf *bp;
        struct nfsnode *np = VTONFS(vp);
        struct vattr vattr;
        struct buf *bp;
        struct nfsnode *np = VTONFS(vp);
        struct vattr vattr;
+       struct nfsmount *nmp;
        daddr_t lbn, bn;
        int n, on, error = 0;
 
        daddr_t lbn, bn;
        int n, on, error = 0;
 
@@ -181,24 +287,7 @@ nfs_write(vp, uio, ioflag, cred)
 #endif
        if (vp->v_type != VREG)
                return (EIO);
 #endif
        if (vp->v_type != VREG)
                return (EIO);
-       /* Should we try and do this ?? */
-       if (ioflag & (IO_APPEND | IO_SYNC)) {
-               if (np->n_flag & NMODIFIED) {
-                       np->n_flag &= ~NMODIFIED;
-                       vinvalbuf(vp, TRUE);
-               }
-               if (ioflag & IO_APPEND) {
-                       np->n_attrstamp = 0;
-                       if (error = nfs_dogetattr(vp, &vattr, cred, 1, p))
-                               return (error);
-                       uio->uio_offset = np->n_size;
-               }
-               return (nfs_writerpc(vp, uio, cred));
-       }
-#ifdef notdef
-       cnt = uio->uio_resid;
-       osize = np->n_size;
-#endif
+       nmp = VFSTONFS(vp->v_mount);
        if (uio->uio_offset < 0)
                return (EINVAL);
        if (uio->uio_resid == 0)
        if (uio->uio_offset < 0)
                return (EINVAL);
        if (uio->uio_resid == 0)
@@ -207,7 +296,7 @@ nfs_write(vp, uio, ioflag, cred)
         * Maybe this should be above the vnode op call, but so long as
         * file servers have no limits, i don't think it matters
         */
         * Maybe this should be above the vnode op call, but so long as
         * file servers have no limits, i don't think it matters
         */
-       if (uio->uio_offset + uio->uio_resid >
+       if (p && uio->uio_offset + uio->uio_resid >
              p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
                psignal(p, SIGXFSZ);
                return (EFBIG);
              p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
                psignal(p, SIGXFSZ);
                return (EFBIG);
@@ -217,48 +306,105 @@ nfs_write(vp, uio, ioflag, cred)
         * will be the same size within a filesystem. nfs_writerpc will
         * still use nm_wsize when sizing the rpc's.
         */
         * will be the same size within a filesystem. nfs_writerpc will
         * still use nm_wsize when sizing the rpc's.
         */
-       biosize = VFSTONFS(vp->v_mount)->nm_rsize;
+       biosize = nmp->nm_rsize;
        np->n_flag |= NMODIFIED;
        do {
        np->n_flag |= NMODIFIED;
        do {
+
+               /*
+                * Check for a valid write lease.
+                * If non-cachable, just do the rpc
+                */
+               if ((nmp->nm_flag & NFSMNT_NQNFS) &&
+                   NQNFS_CKINVALID(vp, np, NQL_WRITE)) {
+                       do {
+                               error = nqnfs_getlease(vp, NQL_WRITE, cred, p);
+                       } while (error == NQNFS_EXPIRED);
+                       if (error)
+                               return (error);
+                       if (QUADNE(np->n_lrev, np->n_brev) ||
+                           (np->n_flag & NQNFSNONCACHE)) {
+                               vinvalbuf(vp, TRUE);
+                               np->n_brev = np->n_lrev;
+                       }
+               }
+               if (np->n_flag & NQNFSNONCACHE)
+                       return (nfs_writerpc(vp, uio, cred));
                nfsstats.biocache_writes++;
                lbn = uio->uio_offset / biosize;
                on = uio->uio_offset & (biosize-1);
                n = MIN((unsigned)(biosize - on), uio->uio_resid);
                nfsstats.biocache_writes++;
                lbn = uio->uio_offset / biosize;
                on = uio->uio_offset & (biosize-1);
                n = MIN((unsigned)(biosize - on), uio->uio_resid);
-               if (uio->uio_offset+n > np->n_size) {
-                       np->n_size = uio->uio_offset+n;
+               if (uio->uio_offset + n > np->n_size) {
+                       np->n_size = uio->uio_offset + n;
                        vnode_pager_setsize(vp, np->n_size);
                }
                        vnode_pager_setsize(vp, np->n_size);
                }
-               bn = lbn*(biosize/DEV_BSIZE);
+               bn = lbn * (biosize / DEV_BSIZE);
 again:
                bp = getblk(vp, bn, biosize);
                if (bp->b_wcred == NOCRED) {
                        crhold(cred);
                        bp->b_wcred = cred;
                }
 again:
                bp = getblk(vp, bn, biosize);
                if (bp->b_wcred == NOCRED) {
                        crhold(cred);
                        bp->b_wcred = cred;
                }
-               if (bp->b_dirtyend > 0) {
-                       /*
-                        * If the new write will leave a contiguous dirty
-                        * area, just update the b_dirtyoff and b_dirtyend,
-                        * otherwise force a write rpc of the old dirty area.
-                        */
-                       if (on <= bp->b_dirtyend && (on+n) >= bp->b_dirtyoff) {
-                               bp->b_dirtyoff = MIN(on, bp->b_dirtyoff);
-                               bp->b_dirtyend = MAX((on+n), bp->b_dirtyend);
-                       } else {
-                               bp->b_proc = p;
-                               if (error = bwrite(bp))
-                                       return (error);
-                               goto again;
+
+               /*
+                * If the new write will leave a contiguous dirty
+                * area, just update the b_dirtyoff and b_dirtyend,
+                * otherwise force a write rpc of the old dirty area.
+                */
+               if (bp->b_dirtyend > 0 &&
+                   (on > bp->b_dirtyend || (on + n) < bp->b_dirtyoff)) {
+                       bp->b_proc = p;
+                       if (error = bwrite(bp))
+                               return (error);
+                       goto again;
+               }
+
+               /*
+                * Check for valid write lease and get one as required.
+                * In case getblk() and/or bwrite() delayed us.
+                */
+               if ((nmp->nm_flag & NFSMNT_NQNFS) &&
+                   NQNFS_CKINVALID(vp, np, NQL_WRITE)) {
+                       do {
+                               error = nqnfs_getlease(vp, NQL_WRITE, cred, p);
+                       } while (error == NQNFS_EXPIRED);
+                       if (error) {
+                               brelse(bp);
+                               return (error);
+                       }
+                       if (QUADNE(np->n_lrev, np->n_brev) ||
+                           (np->n_flag & NQNFSNONCACHE)) {
+                               vinvalbuf(vp, TRUE);
+                               np->n_brev = np->n_lrev;
                        }
                        }
-               } else {
-                       bp->b_dirtyoff = on;
-                       bp->b_dirtyend = on+n;
                }
                if (error = uiomove(bp->b_un.b_addr + on, n, uio)) {
                        brelse(bp);
                        return (error);
                }
                }
                if (error = uiomove(bp->b_un.b_addr + on, n, uio)) {
                        brelse(bp);
                        return (error);
                }
-               if ((n+on) == biosize) {
+               if (bp->b_dirtyend > 0) {
+                       bp->b_dirtyoff = MIN(on, bp->b_dirtyoff);
+                       bp->b_dirtyend = MAX((on+n), bp->b_dirtyend);
+               } else {
+                       bp->b_dirtyoff = on;
+                       bp->b_dirtyend = on+n;
+               }
+               if (bp->b_validend == 0 || bp->b_validend < bp->b_dirtyoff ||
+                   bp->b_validoff > bp->b_dirtyend) {
+                       bp->b_validoff = bp->b_dirtyoff;
+                       bp->b_validend = bp->b_dirtyend;
+               } else {
+                       bp->b_validoff = MIN(bp->b_validoff, bp->b_dirtyoff);
+                       bp->b_validend = MAX(bp->b_validend, bp->b_dirtyend);
+               }
+
+               /*
+                * If the lease is non-cachable or IO_SYNC do bwrite().
+                */
+               if ((np->n_flag & NQNFSNONCACHE) || (ioflag & IO_SYNC)) {
+                       bp->b_proc = p;
+                       bwrite(bp);
+               } else if ((n+on) == biosize &&
+                        (nmp->nm_flag & NFSMNT_NQNFS) == 0) {
                        bp->b_flags |= B_AGE;
                        bp->b_proc = (struct proc *)0;
                        bawrite(bp);
                        bp->b_flags |= B_AGE;
                        bp->b_proc = (struct proc *)0;
                        bawrite(bp);
@@ -267,13 +413,5 @@ again:
                        bdwrite(bp);
                }
        } while (error == 0 && uio->uio_resid > 0 && n != 0);
                        bdwrite(bp);
                }
        } while (error == 0 && uio->uio_resid > 0 && n != 0);
-#ifdef notdef
-       /* Should we try and do this for nfs ?? */
-       if (error && (ioflag & IO_UNIT)) {
-               np->n_size = osize;
-               uio->uio_offset -= cnt - uio->uio_resid;
-               uio->uio_resid = cnt;
-       }
-#endif
        return (error);
 }
        return (error);
 }
index 6da6ea6..e6d411e 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_node.c  7.35 (Berkeley) %G%
+ *     @(#)nfs_node.c  7.36 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
 #include "kernel.h"
 #include "malloc.h"
 
 #include "kernel.h"
 #include "malloc.h"
 
+#include "rpcv2.h"
 #include "nfsv2.h"
 #include "nfs.h"
 #include "nfsnode.h"
 #include "nfsmount.h"
 #include "nfsv2.h"
 #include "nfs.h"
 #include "nfsnode.h"
 #include "nfsmount.h"
+#include "nqnfs.h"
 
 /* The request list head */
 extern struct nfsreq nfsreqh;
 
 /* The request list head */
 extern struct nfsreq nfsreqh;
@@ -103,11 +105,6 @@ loop:
                if (mntp != NFSTOV(np)->v_mount ||
                    bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH))
                        continue;
                if (mntp != NFSTOV(np)->v_mount ||
                    bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH))
                        continue;
-               if ((np->n_flag & NLOCKED) != 0) {
-                       np->n_flag |= NWANT;
-                       (void) tsleep((caddr_t)np, PINOD, "nfsnode", 0);
-                       goto loop;
-               }
                vp = NFSTOV(np);
                if (vget(vp))
                        goto loop;
                vp = NFSTOV(np);
                if (vget(vp))
                        goto loop;
@@ -127,13 +124,18 @@ loop:
         */
        np->n_flag = 0;
        insque(np, nh);
         */
        np->n_flag = 0;
        insque(np, nh);
-       nfs_lock(vp);
        bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
        np->n_attrstamp = 0;
        np->n_direofoffset = 0;
        np->n_sillyrename = (struct sillyrename *)0;
        np->n_size = 0;
        bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
        np->n_attrstamp = 0;
        np->n_direofoffset = 0;
        np->n_sillyrename = (struct sillyrename *)0;
        np->n_size = 0;
-       np->n_mtime = 0;
+       if (VFSTONFS(mntp)->nm_flag & NFSMNT_NQNFS) {
+               ZEROQUAD(np->n_brev);
+               ZEROQUAD(np->n_lrev);
+               np->n_expiry = (time_t)0;
+               np->n_tnext = (struct nfsnode *)0;
+       } else
+               np->n_mtime = 0;
        *npp = np;
        return (0);
 }
        *npp = np;
        return (0);
 }
@@ -144,52 +146,25 @@ nfs_inactive(vp, p)
 {
        register struct nfsnode *np;
        register struct sillyrename *sp;
 {
        register struct nfsnode *np;
        register struct sillyrename *sp;
-       struct nfsnode *dnp;
        extern int prtactive;
 
        np = VTONFS(vp);
        if (prtactive && vp->v_usecount != 0)
                vprint("nfs_inactive: pushing active", vp);
        extern int prtactive;
 
        np = VTONFS(vp);
        if (prtactive && vp->v_usecount != 0)
                vprint("nfs_inactive: pushing active", vp);
-       nfs_lock(vp);
        sp = np->n_sillyrename;
        np->n_sillyrename = (struct sillyrename *)0;
        if (sp) {
                /*
                 * Remove the silly file that was rename'd earlier
                 */
        sp = np->n_sillyrename;
        np->n_sillyrename = (struct sillyrename *)0;
        if (sp) {
                /*
                 * Remove the silly file that was rename'd earlier
                 */
-               if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
-                       sp->s_dvp = NFSTOV(dnp);
-                       nfs_removeit(sp, p);
-                       nfs_nput(sp->s_dvp);
-               }
+               nfs_removeit(sp, p);
                crfree(sp->s_cred);
                vrele(sp->s_dvp);
 #ifdef SILLYSEPARATE
                free((caddr_t)sp, M_NFSREQ);
 #endif
        }
                crfree(sp->s_cred);
                vrele(sp->s_dvp);
 #ifdef SILLYSEPARATE
                free((caddr_t)sp, M_NFSREQ);
 #endif
        }
-       nfs_unlock(vp);
        np->n_flag &= NMODIFIED;
        np->n_flag &= NMODIFIED;
-#ifdef notdef
-       /*
-        * Scan the request list for any requests left hanging about
-        */
-       s = splnet();
-       rep = nfsreqh.r_next;
-       while (rep && rep != &nfsreqh) {
-               if (rep->r_vp == vp) {
-                       rep->r_prev->r_next = rep2 = rep->r_next;
-                       rep->r_next->r_prev = rep->r_prev;
-                       m_freem(rep->r_mreq);
-                       if (rep->r_mrep != NULL)
-                               m_freem(rep->r_mrep);
-                       free((caddr_t)rep, M_NFSREQ);
-                       rep = rep2;
-               } else
-                       rep = rep->r_next;
-       }
-       splx(s);
-#endif
        return (0);
 }
 
        return (0);
 }
 
@@ -200,6 +175,7 @@ nfs_reclaim(vp)
        register struct vnode *vp;
 {
        register struct nfsnode *np = VTONFS(vp);
        register struct vnode *vp;
 {
        register struct nfsnode *np = VTONFS(vp);
+       register struct nfsmount *nmp = VFSTONFS(vp->v_mount);
        extern int prtactive;
 
        if (prtactive && vp->v_usecount != 0)
        extern int prtactive;
 
        if (prtactive && vp->v_usecount != 0)
@@ -208,38 +184,34 @@ nfs_reclaim(vp)
         * Remove the nfsnode from its hash chain.
         */
        remque(np);
         * Remove the nfsnode from its hash chain.
         */
        remque(np);
+
+       /*
+        * For nqnfs, take it off the timer queue as required.
+        */
+       if ((nmp->nm_flag & NFSMNT_NQNFS) && np->n_tnext) {
+               if (np->n_tnext == (struct nfsnode *)nmp)
+                       nmp->nm_tprev = np->n_tprev;
+               else
+                       np->n_tnext->n_tprev = np->n_tprev;
+               if (np->n_tprev == (struct nfsnode *)nmp)
+                       nmp->nm_tnext = np->n_tnext;
+               else
+                       np->n_tprev->n_tnext = np->n_tnext;
+       }
        cache_purge(vp);
        FREE(vp->v_data, M_NFSNODE);
        cache_purge(vp);
        FREE(vp->v_data, M_NFSNODE);
-       vp->v_data = NULL;
+       vp->v_data = (void *)0;
        return (0);
 }
 
        return (0);
 }
 
-/*
- * In theory, NFS does not need locking, but we make provision
- * for doing it just in case it is needed.
- */
-int donfslocking = 0;
 /*
  * Lock an nfsnode
  */
 /*
  * Lock an nfsnode
  */
-
 nfs_lock(vp)
        struct vnode *vp;
 {
 nfs_lock(vp)
        struct vnode *vp;
 {
-       register struct nfsnode *np = VTONFS(vp);
 
 
-       if (!donfslocking)
-               return;
-       while (np->n_flag & NLOCKED) {
-               np->n_flag |= NWANT;
-               if (np->n_lockholder == curproc->p_pid)
-                       panic("locking against myself");
-               np->n_lockwaiter = curproc->p_pid;
-               (void) tsleep((caddr_t)np, PINOD, "nfslock", 0);
-       }
-       np->n_lockwaiter = 0;
-       np->n_lockholder = curproc->p_pid;
-       np->n_flag |= NLOCKED;
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -248,14 +220,8 @@ nfs_lock(vp)
 nfs_unlock(vp)
        struct vnode *vp;
 {
 nfs_unlock(vp)
        struct vnode *vp;
 {
-       register struct nfsnode *np = VTONFS(vp);
 
 
-       np->n_lockholder = 0;
-       np->n_flag &= ~NLOCKED;
-       if (np->n_flag & NWANT) {
-               np->n_flag &= ~NWANT;
-               wakeup((caddr_t)np);
-       }
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -265,26 +231,9 @@ nfs_islocked(vp)
        struct vnode *vp;
 {
 
        struct vnode *vp;
 {
 
-       if (VTONFS(vp)->n_flag & NLOCKED)
-               return (1);
        return (0);
 }
 
        return (0);
 }
 
-/*
- * Unlock and vrele()
- * since I can't decide if dirs. should be locked, I will check for
- * the lock and be flexible
- */
-nfs_nput(vp)
-       struct vnode *vp;
-{
-       register struct nfsnode *np = VTONFS(vp);
-
-       if (np->n_flag & NLOCKED)
-               nfs_unlock(vp);
-       vrele(vp);
-}
-
 /*
  * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
  * done. Currently nothing to do.
 /*
  * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
  * done. Currently nothing to do.
index 0bea8f1..a86537c 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_nqlease.c       7.1 (Berkeley) %G%
+ *     @(#)nfs_nqlease.c       7.2 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -175,7 +175,8 @@ nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred)
                lhp = &nqfhead[NQFHHASH(fh.fh_fid.fid_data)];
                for (lp = lhp->th_chain[0]; lp != (struct nqlease *)lhp;
                        lp = lp->lc_fhnext)
                lhp = &nqfhead[NQFHHASH(fh.fh_fid.fid_data)];
                for (lp = lhp->th_chain[0]; lp != (struct nqlease *)lhp;
                        lp = lp->lc_fhnext)
-                       if (QUADEQ(fh.fh_fsid, lp->lc_fsid) &&
+                       if (fh.fh_fsid.val[0] == lp->lc_fsid.val[0] &&
+                           fh.fh_fsid.val[1] == lp->lc_fsid.val[1] &&
                            !bcmp(fh.fh_fid.fid_data, lp->lc_fiddata,
                                  fh.fh_fid.fid_len - sizeof (long))) {
                                /* Found it */
                            !bcmp(fh.fh_fid.fid_data, lp->lc_fiddata,
                                  fh.fh_fid.fid_len - sizeof (long))) {
                                /* Found it */
@@ -753,7 +754,8 @@ nqnfsrv_vacated(nfsd, mrep, md, dpos, cred, nam, mrq)
                lhp = &nqfhead[NQFHHASH(fhp->fh_fid.fid_data)];
                for (lp = lhp->th_chain[0]; lp != (struct nqlease *)lhp;
                        lp = lp->lc_fhnext)
                lhp = &nqfhead[NQFHHASH(fhp->fh_fid.fid_data)];
                for (lp = lhp->th_chain[0]; lp != (struct nqlease *)lhp;
                        lp = lp->lc_fhnext)
-                       if (QUADEQ(fhp->fh_fsid, lp->lc_fsid) &&
+                       if (fhp->fh_fsid.val[0] == lp->lc_fsid.val[0] &&
+                           fhp->fh_fsid.val[1] == lp->lc_fsid.val[1] &&
                            !bcmp(fhp->fh_fid.fid_data, lp->lc_fiddata,
                                  MAXFIDSZ)) {
                                /* Found it */
                            !bcmp(fhp->fh_fid.fid_data, lp->lc_fiddata,
                                  MAXFIDSZ)) {
                                /* Found it */
index 3e730a4..6a81420 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_serv.c  7.42 (Berkeley) %G%
+ *     @(#)nfs_serv.c  7.43 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
 #include "ufs/ufs/dir.h"
 
 #include "nfsv2.h"
 #include "ufs/ufs/dir.h"
 
 #include "nfsv2.h"
+#include "rpcv2.h"
 #include "nfs.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 #include "nfs.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
+#include "nqnfs.h"
 
 /* Defs */
 #define        TRUE    1
 
 /* Defs */
 #define        TRUE    1
 extern u_long nfs_procids[NFS_NPROCS];
 extern u_long nfs_xdrneg1;
 extern u_long nfs_false, nfs_true;
 extern u_long nfs_procids[NFS_NPROCS];
 extern u_long nfs_xdrneg1;
 extern u_long nfs_false, nfs_true;
-nfstype nfs_type[9]={ NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
+nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
                      NFCHR, NFNON };
 
 /*
  * nfs getattr service
  */
                      NFCHR, NFNON };
 
 /*
  * nfs getattr service
  */
-nfsrv_getattr(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf **mrq;
+nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        register struct nfsv2_fattr *fp;
        struct vattr va;
 {
        register struct nfsv2_fattr *fp;
        struct vattr va;
@@ -77,15 +77,17 @@ nfsrv_getattr(mrep, md, dpos, cred, xid, mrq, repstat, p)
        register u_long *tl;
        register long t1;
        caddr_t bpos;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, rdonly, cache;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
+       u_quad_t frev;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
-       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
                nfsm_reply(0);
                nfsm_reply(0);
-       error = VOP_GETATTR(vp, vap, cred, p);
+       nqsrv_getl(vp, NQL_READ);
+       error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
        vput(vp);
        nfsm_reply(NFSX_FATTR);
        nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
        vput(vp);
        nfsm_reply(NFSX_FATTR);
        nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
@@ -96,14 +98,12 @@ nfsrv_getattr(mrep, md, dpos, cred, xid, mrq, repstat, p)
 /*
  * nfs setattr service
  */
 /*
  * nfs setattr service
  */
-nfsrv_setattr(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf **mrq;
+nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        struct vattr va;
        register struct vattr *vap = &va;
 {
        struct vattr va;
        register struct vattr *vap = &va;
@@ -115,16 +115,18 @@ nfsrv_setattr(mrep, md, dpos, cred, xid, mrq, repstat, p)
        register u_long *tl;
        register long t1;
        caddr_t bpos;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, rdonly, cache, duration2, cache2;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
+       u_quad_t frev, frev2;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
-       nfsm_disect(sp, struct nfsv2_sattr *, NFSX_SATTR);
-       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
+       nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR);
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
                nfsm_reply(0);
                nfsm_reply(0);
-       if (error = nfsrv_access(vp, VWRITE, cred, p))
+       nqsrv_getl(vp, NQL_WRITE);
+       if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp))
                goto out;
        VATTR_NULL(vap);
        /*
                goto out;
        VATTR_NULL(vap);
        /*
@@ -155,30 +157,32 @@ nfsrv_setattr(mrep, md, dpos, cred, xid, mrq, repstat, p)
                vap->va_flags = fxdr_unsigned(u_long, sp->sa_atime.tv_usec);
        if (sp->sa_mtime.tv_sec != nfs_xdrneg1)
                fxdr_time(&sp->sa_mtime, &vap->va_mtime);
                vap->va_flags = fxdr_unsigned(u_long, sp->sa_atime.tv_usec);
        if (sp->sa_mtime.tv_sec != nfs_xdrneg1)
                fxdr_time(&sp->sa_mtime, &vap->va_mtime);
-       if (error = VOP_SETATTR(vp, vap, cred, p)) {
+       if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) {
                vput(vp);
                nfsm_reply(0);
        }
                vput(vp);
                nfsm_reply(0);
        }
-       error = VOP_GETATTR(vp, vap, cred, p);
+       error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
 out:
        vput(vp);
 out:
        vput(vp);
-       nfsm_reply(NFSX_FATTR);
+       nfsm_reply(NFSX_FATTR + 2*NFSX_UNSIGNED);
        nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
        nfsm_srvfillattr;
        nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
        nfsm_srvfillattr;
+       if (nfsd->nd_nqlflag != NQL_NOVAL) {
+               nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
+               txdr_hyper(&frev2, tl);
+       }
        nfsm_srvdone;
 }
 
 /*
  * nfs lookup rpc
  */
        nfsm_srvdone;
 }
 
 /*
  * nfs lookup rpc
  */
-nfsrv_lookup(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf **mrq;
+nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        register struct nfsv2_fattr *fp;
        struct nameidata nd;
 {
        register struct nfsv2_fattr *fp;
        struct nameidata nd;
@@ -189,19 +193,29 @@ nfsrv_lookup(mrep, md, dpos, cred, xid, mrq, repstat, p)
        register u_long *tl;
        register long t1;
        caddr_t bpos;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, lflag = 0, rdonly, cache, duration2, cache2, len;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
-       long len;
        struct vattr va, *vap = &va;
        struct vattr va, *vap = &va;
+       u_quad_t frev, frev2;
 
        fhp = &nfh.fh_generic;
 
        fhp = &nfh.fh_generic;
+       if (nfsd->nd_nqlflag != NQL_NOVAL) {
+               nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+               if (*tl) {
+                       lflag = fxdr_unsigned(int, *tl);
+                       nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+                       duration2 = fxdr_unsigned(int, *tl);
+               }
+       }
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        nd.ni_cred = cred;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        nd.ni_cred = cred;
-       nd.ni_nameiop = LOOKUP | LOCKLEAF;
-       if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p))
+       nd.ni_nameiop = LOOKUP | LOCKLEAF | SAVESTART;
+       if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp))
                nfsm_reply(0);
                nfsm_reply(0);
+       nqsrv_getl(nd.ni_startdir, NQL_READ);
+       vrele(nd.ni_startdir);
        vp = nd.ni_vp;
        bzero((caddr_t)fhp, sizeof(nfh));
        fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
        vp = nd.ni_vp;
        bzero((caddr_t)fhp, sizeof(nfh));
        fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
@@ -209,9 +223,24 @@ nfsrv_lookup(mrep, md, dpos, cred, xid, mrq, repstat, p)
                vput(vp);
                nfsm_reply(0);
        }
                vput(vp);
                nfsm_reply(0);
        }
-       error = VOP_GETATTR(vp, vap, cred, p);
+       if (lflag)
+               (void) nqsrv_getlease(vp, &duration2, lflag, nfsd,
+                       nam, &cache2, &frev2, cred);
+       error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
        vput(vp);
        vput(vp);
-       nfsm_reply(NFSX_FH+NFSX_FATTR);
+       nfsm_reply(NFSX_FH + NFSX_FATTR + 5*NFSX_UNSIGNED);
+       if (nfsd->nd_nqlflag != NQL_NOVAL) {
+               if (lflag) {
+                       nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED);
+                       *tl++ = txdr_unsigned(lflag);
+                       *tl++ = txdr_unsigned(cache2);
+                       *tl++ = txdr_unsigned(duration2);
+                       txdr_hyper(&frev2, tl);
+               } else {
+                       nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+                       *tl = 0;
+               }
+       }
        nfsm_srvfhtom(fhp);
        nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
        nfsm_srvfillattr;
        nfsm_srvfhtom(fhp);
        nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
        nfsm_srvfillattr;
@@ -221,14 +250,12 @@ nfsrv_lookup(mrep, md, dpos, cred, xid, mrq, repstat, p)
 /*
  * nfs readlink service
  */
 /*
  * nfs readlink service
  */
-nfsrv_readlink(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf **mrq;
+nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
        register struct iovec *ivp = iv;
 {
        struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
        register struct iovec *ivp = iv;
@@ -236,14 +263,14 @@ nfsrv_readlink(mrep, md, dpos, cred, xid, mrq, repstat, p)
        register u_long *tl;
        register long t1;
        caddr_t bpos;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, rdonly, cache, i, tlen, len;
        char *cp2;
        struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        struct uio io, *uiop = &io;
        char *cp2;
        struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        struct uio io, *uiop = &io;
-       int i, tlen, len;
+       u_quad_t frev;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
@@ -276,7 +303,7 @@ nfsrv_readlink(mrep, md, dpos, cred, xid, mrq, repstat, p)
        uiop->uio_rw = UIO_READ;
        uiop->uio_segflg = UIO_SYSSPACE;
        uiop->uio_procp = (struct proc *)0;
        uiop->uio_rw = UIO_READ;
        uiop->uio_segflg = UIO_SYSSPACE;
        uiop->uio_procp = (struct proc *)0;
-       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) {
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) {
                m_freem(mp3);
                nfsm_reply(0);
        }
                m_freem(mp3);
                nfsm_reply(0);
        }
@@ -284,6 +311,7 @@ nfsrv_readlink(mrep, md, dpos, cred, xid, mrq, repstat, p)
                error = EINVAL;
                goto out;
        }
                error = EINVAL;
                goto out;
        }
+       nqsrv_getl(vp, NQL_READ);
        error = VOP_READLINK(vp, uiop, cred);
 out:
        vput(vp);
        error = VOP_READLINK(vp, uiop, cred);
 out:
        vput(vp);
@@ -304,14 +332,12 @@ out:
 /*
  * nfs read service
  */
 /*
  * nfs read service
  */
-nfsrv_read(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf **mrq;
+nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        register struct iovec *iv;
        struct iovec *iv2;
 {
        register struct iovec *iv;
        struct iovec *iv2;
@@ -320,106 +346,106 @@ nfsrv_read(mrep, md, dpos, cred, xid, mrq, repstat, p)
        register u_long *tl;
        register long t1;
        caddr_t bpos;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
-       struct mbuf *m2, *m3;
+       struct mbuf *m2;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        struct uio io, *uiop = &io;
        struct vattr va, *vap = &va;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        struct uio io, *uiop = &io;
        struct vattr va, *vap = &va;
-       int i, cnt, len, left, siz, tlen;
        off_t off;
        off_t off;
+       u_quad_t frev;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
-       nfsm_disect(tl, u_long *, NFSX_UNSIGNED);
+       nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
        off = fxdr_unsigned(off_t, *tl);
        nfsm_srvstrsiz(cnt, NFS_MAXDATA);
        off = fxdr_unsigned(off_t, *tl);
        nfsm_srvstrsiz(cnt, NFS_MAXDATA);
-       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
                nfsm_reply(0);
                nfsm_reply(0);
-       if (error = nfsrv_access(vp, VREAD | VEXEC, cred, p)) {
+       nqsrv_getl(vp, NQL_READ);
+       if (error = nfsrv_access(vp, VREAD | VEXEC, cred, rdonly, nfsd->nd_procp)) {
                vput(vp);
                nfsm_reply(0);
        }
                vput(vp);
                nfsm_reply(0);
        }
-       len = left = cnt;
-       /*
-        * Generate the mbuf list with the uio_iov ref. to it.
-        */
-       i = 0;
-       m3 = (struct mbuf *)0;
-#ifdef lint
-       m2 = (struct mbuf *)0;
-#endif /* lint */
-       MALLOC(iv, struct iovec *,
-              ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), M_TEMP,
-              M_WAITOK);
-       iv2 = iv;
-       while (left > 0) {
-               MGET(m, M_WAIT, MT_DATA);
-               if (left > MINCLSIZE)
-                       MCLGET(m, M_WAIT);
-               m->m_len = 0;
-               siz = min(M_TRAILINGSPACE(m), left);
-               m->m_len = siz;
-               iv->iov_base = mtod(m, caddr_t);
-               iv->iov_len = siz;
-               iv++;
-               i++;
-               left -= siz;
-               if (m3) {
-                       m2->m_next = m;
-                       m2 = m;
-               } else
-                       m3 = m2 = m;
-       }
-       uiop->uio_iov = iv2;
-       uiop->uio_iovcnt = i;
-       uiop->uio_offset = off;
-       uiop->uio_resid = cnt;
-       uiop->uio_rw = UIO_READ;
-       uiop->uio_segflg = UIO_SYSSPACE;
-       uiop->uio_procp = (struct proc *)0;
-       error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
-       off = uiop->uio_offset;
-       FREE((caddr_t)iv2, M_TEMP);
-       if (error) {
-               m_freem(m3);
+       if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) {
                vput(vp);
                nfsm_reply(0);
        }
                vput(vp);
                nfsm_reply(0);
        }
-       if (error = VOP_GETATTR(vp, vap, cred, p))
-               m_freem(m3);
-       vput(vp);
-       nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED);
+       if (off >= vap->va_size)
+               cnt = 0;
+       else if ((off + cnt) > vap->va_size)
+               cnt = nfsm_rndup(vap->va_size - off);
+       nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED+nfsm_rndup(cnt));
        nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
        nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+       len = left = cnt;
+       if (cnt > 0) {
+               /*
+                * Generate the mbuf list with the uio_iov ref. to it.
+                */
+               i = 0;
+               m = m2 = mb;
+               MALLOC(iv, struct iovec *,
+                      ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec),
+                      M_TEMP, M_WAITOK);
+               iv2 = iv;
+               while (left > 0) {
+                       siz = MIN(M_TRAILINGSPACE(m), left);
+                       if (siz > 0) {
+                               m->m_len += siz;
+                               iv->iov_base = bpos;
+                               iv->iov_len = siz;
+                               iv++;
+                               i++;
+                               left -= siz;
+                       }
+                       if (left > 0) {
+                               MGET(m, M_WAIT, MT_DATA);
+                               MCLGET(m, M_WAIT);
+                               m->m_len = 0;
+                               m2->m_next = m;
+                               m2 = m;
+                               bpos = mtod(m, caddr_t);
+                       }
+               }
+               uiop->uio_iov = iv2;
+               uiop->uio_iovcnt = i;
+               uiop->uio_offset = off;
+               uiop->uio_resid = cnt;
+               uiop->uio_rw = UIO_READ;
+               uiop->uio_segflg = UIO_SYSSPACE;
+               error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
+               off = uiop->uio_offset;
+               FREE((caddr_t)iv2, M_TEMP);
+               if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) {
+                       m_freem(mreq);
+                       vput(vp);
+                       nfsm_reply(0);
+               }
+       } else
+               uiop->uio_resid = 0;
+       vput(vp);
        nfsm_srvfillattr;
        len -= uiop->uio_resid;
        nfsm_srvfillattr;
        len -= uiop->uio_resid;
-       if (len > 0) {
-               tlen = nfsm_rndup(len);
-               if (cnt != tlen || tlen != len)
-                       nfsm_adj(m3, cnt-tlen, tlen-len);
-       } else {
-               m_freem(m3);
-               m3 = (struct mbuf *)0;
-       }
-       nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+       tlen = nfsm_rndup(len);
+       if (cnt != tlen || tlen != len)
+               nfsm_adj(mb, cnt-tlen, tlen-len);
        *tl = txdr_unsigned(len);
        *tl = txdr_unsigned(len);
-       mb->m_next = m3;
        nfsm_srvdone;
 }
 
 /*
  * nfs write service
  */
        nfsm_srvdone;
 }
 
 /*
  * nfs write service
  */
-nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf *mrep, *md, **mrq;
+nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
+       struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        register struct iovec *ivp;
        register struct mbuf *mp;
 {
        register struct iovec *ivp;
        register struct mbuf *mp;
@@ -430,7 +456,7 @@ nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat, p)
        register u_long *tl;
        register long t1;
        caddr_t bpos;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, rdonly, cache, siz, len, xfer;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        struct vnode *vp;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        struct vnode *vp;
@@ -438,11 +464,11 @@ nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat, p)
        fhandle_t *fhp;
        struct uio io, *uiop = &io;
        off_t off;
        fhandle_t *fhp;
        struct uio io, *uiop = &io;
        off_t off;
-       long siz, len, xfer;
+       u_quad_t frev;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
-       nfsm_disect(tl, u_long *, 4*NFSX_UNSIGNED);
+       nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
        off = fxdr_unsigned(off_t, *++tl);
        tl += 2;
        len = fxdr_unsigned(long, *tl);
        off = fxdr_unsigned(off_t, *++tl);
        tl += 2;
        len = fxdr_unsigned(long, *tl);
@@ -462,9 +488,10 @@ nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat, p)
                mp->m_len -= siz;
                NFSMADV(mp, siz);
        }
                mp->m_len -= siz;
                NFSMADV(mp, siz);
        }
-       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
                nfsm_reply(0);
                nfsm_reply(0);
-       if (error = nfsrv_access(vp, VWRITE, cred, p)) {
+       nqsrv_getl(vp, NQL_WRITE);
+       if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) {
                vput(vp);
                nfsm_reply(0);
        }
                vput(vp);
                nfsm_reply(0);
        }
@@ -514,7 +541,7 @@ nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat, p)
                }
                off = uiop->uio_offset;
        }
                }
                off = uiop->uio_offset;
        }
-       error = VOP_GETATTR(vp, vap, cred, p);
+       error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
        vput(vp);
        nfsm_reply(NFSX_FATTR);
        nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
        vput(vp);
        nfsm_reply(NFSX_FATTR);
        nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
@@ -526,13 +553,12 @@ nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat, p)
  * nfs create service
  * now does a truncate to 0 length via. setattr if it already exists
  */
  * nfs create service
  * now does a truncate to 0 length via. setattr if it already exists
  */
-nfsrv_create(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf *mrep, *md, **mrq;
+nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
+       struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        register struct nfsv2_fattr *fp;
        struct vattr va;
 {
        register struct nfsv2_fattr *fp;
        struct vattr va;
@@ -542,14 +568,13 @@ nfsrv_create(mrep, md, dpos, cred, xid, mrq, repstat, p)
        register u_long *tl;
        register long t1;
        caddr_t bpos;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       long rdev;
-       int error = 0;
+       int error = 0, rdev, cache, len;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
-       long len;
+       u_quad_t frev;
 
        nd.ni_nameiop = 0;
        fhp = &nfh.fh_generic;
 
        nd.ni_nameiop = 0;
        fhp = &nfh.fh_generic;
@@ -557,10 +582,10 @@ nfsrv_create(mrep, md, dpos, cred, xid, mrq, repstat, p)
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        nd.ni_cred = cred;
        nd.ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF | SAVESTART;
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        nd.ni_cred = cred;
        nd.ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF | SAVESTART;
-       if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p))
+       if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp))
                nfsm_reply(0);
        VATTR_NULL(vap);
                nfsm_reply(0);
        VATTR_NULL(vap);
-       nfsm_disect(tl, u_long *, NFSX_SATTR);
+       nfsm_dissect(tl, u_long *, NFSX_SATTR);
        /*
         * Iff doesn't exist, create it
         * otherwise just truncate to 0 length
        /*
         * Iff doesn't exist, create it
         * otherwise just truncate to 0 length
@@ -575,7 +600,8 @@ nfsrv_create(mrep, md, dpos, cred, xid, mrq, repstat, p)
                if (vap->va_type == VREG || vap->va_type == VSOCK) {
                        p->p_spare[1]--;
                        vrele(nd.ni_startdir);
                if (vap->va_type == VREG || vap->va_type == VSOCK) {
                        p->p_spare[1]--;
                        vrele(nd.ni_startdir);
-                       if (error = VOP_CREATE(&nd, vap, p))
+                       nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+                       if (error = VOP_CREATE(&nd, vap, nfsd->nd_procp))
                                nfsm_reply(0);
                        FREE(nd.ni_pnbuf, M_NAMEI);
                } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
                                nfsm_reply(0);
                        FREE(nd.ni_pnbuf, M_NAMEI);
                } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
@@ -589,13 +615,14 @@ nfsrv_create(mrep, md, dpos, cred, xid, mrq, repstat, p)
                                error = ENXIO;
                                goto out;
 #endif /* FIFO */
                                error = ENXIO;
                                goto out;
 #endif /* FIFO */
-                       } else if (error = suser(cred, (short *)0)) {
+                       } else if (error = suser(cred, (u_short *)0)) {
                                VOP_ABORTOP(&nd);
                                vput(nd.ni_dvp);
                                goto out;
                        } else
                                vap->va_rdev = (dev_t)rdev;
                                VOP_ABORTOP(&nd);
                                vput(nd.ni_dvp);
                                goto out;
                        } else
                                vap->va_rdev = (dev_t)rdev;
-                       if (error = VOP_MKNOD(&nd, vap, cred, p)) {
+                       nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+                       if (error = VOP_MKNOD(&nd, vap, cred, nfsd->nd_procp)) {
                                p->p_spare[1]--;
                                vrele(nd.ni_startdir);
                                nfsm_reply(0);
                                p->p_spare[1]--;
                                vrele(nd.ni_startdir);
                                nfsm_reply(0);
@@ -603,7 +630,7 @@ nfsrv_create(mrep, md, dpos, cred, xid, mrq, repstat, p)
                        nd.ni_nameiop &= ~(OPMASK | LOCKPARENT | SAVESTART);
                        nd.ni_nameiop |= LOOKUP;
                        p->p_spare[1]--;
                        nd.ni_nameiop &= ~(OPMASK | LOCKPARENT | SAVESTART);
                        nd.ni_nameiop |= LOOKUP;
                        p->p_spare[1]--;
-                       if (error = lookup(&nd, p)) {
+                       if (error = lookup(&nd, nfsd->nd_procp)) {
                                free(nd.ni_pnbuf, M_NAMEI);
                                nfsm_reply(0);
                        }
                                free(nd.ni_pnbuf, M_NAMEI);
                                nfsm_reply(0);
                        }
@@ -633,7 +660,8 @@ nfsrv_create(mrep, md, dpos, cred, xid, mrq, repstat, p)
                        vput(nd.ni_dvp);
                VOP_ABORTOP(&nd);
                vap->va_size = 0;
                        vput(nd.ni_dvp);
                VOP_ABORTOP(&nd);
                vap->va_size = 0;
-               if (error = VOP_SETATTR(vp, vap, cred, p)) {
+               nqsrv_getl(vp, NQL_WRITE);
+               if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) {
                        vput(vp);
                        nfsm_reply(0);
                }
                        vput(vp);
                        nfsm_reply(0);
                }
@@ -644,7 +672,7 @@ nfsrv_create(mrep, md, dpos, cred, xid, mrq, repstat, p)
                vput(vp);
                nfsm_reply(0);
        }
                vput(vp);
                nfsm_reply(0);
        }
-       error = VOP_GETATTR(vp, vap, cred, p);
+       error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
        vput(vp);
        nfsm_reply(NFSX_FH+NFSX_FATTR);
        nfsm_srvfhtom(fhp);
        vput(vp);
        nfsm_reply(NFSX_FH+NFSX_FATTR);
        nfsm_srvfhtom(fhp);
@@ -673,36 +701,35 @@ out:
 /*
  * nfs remove service
  */
 /*
  * nfs remove service
  */
-nfsrv_remove(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf *mrep, *md, **mrq;
+nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
+       struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        struct nameidata nd;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
 {
        struct nameidata nd;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, cache, len;
        char *cp2;
        struct mbuf *mb, *mreq;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        char *cp2;
        struct mbuf *mb, *mreq;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
-       long len;
+       u_quad_t frev;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        nd.ni_cred = cred;
        nd.ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        nd.ni_cred = cred;
        nd.ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
-       if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p))
+       if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp))
                nfsm_reply(0);
        vp = nd.ni_vp;
        if (vp->v_type == VDIR &&
                nfsm_reply(0);
        vp = nd.ni_vp;
        if (vp->v_type == VDIR &&
-               (error = suser(cred, (short *)0)))
+               (error = suser(cred, (u_short *)0)))
                goto out;
        /*
         * The root of a mounted filesystem cannot be deleted.
                goto out;
        /*
         * The root of a mounted filesystem cannot be deleted.
@@ -715,7 +742,9 @@ nfsrv_remove(mrep, md, dpos, cred, xid, mrq, repstat, p)
                (void) vnode_pager_uncache(vp);
 out:
        if (!error) {
                (void) vnode_pager_uncache(vp);
 out:
        if (!error) {
-               error = VOP_REMOVE(&nd, p);
+               nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+               nqsrv_getl(vp, NQL_WRITE);
+               error = VOP_REMOVE(&nd, nfsd->nd_procp);
        } else {
                VOP_ABORTOP(&nd);
                if (nd.ni_dvp == vp)
        } else {
                VOP_ABORTOP(&nd);
                if (nd.ni_dvp == vp)
@@ -731,26 +760,25 @@ out:
 /*
  * nfs rename service
  */
 /*
  * nfs rename service
  */
-nfsrv_rename(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf *mrep, *md, **mrq;
+nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
+       struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        register u_long *tl;
        register long t1;
        caddr_t bpos;
 {
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, rdonly, cache, len, len2;
        char *cp2;
        struct mbuf *mb, *mreq;
        struct nameidata fromnd, tond;
        struct vnode *fvp, *tvp, *tdvp;
        nfsv2fh_t fnfh, tnfh;
        fhandle_t *ffhp, *tfhp;
        char *cp2;
        struct mbuf *mb, *mreq;
        struct nameidata fromnd, tond;
        struct vnode *fvp, *tvp, *tdvp;
        nfsv2fh_t fnfh, tnfh;
        fhandle_t *ffhp, *tfhp;
-       long len, len2;
-       int rootflg = 0;
+       u_quad_t frev;
+       uid_t saved_uid;
 
        ffhp = &fnfh.fh_generic;
        tfhp = &tnfh.fh_generic;
 
        ffhp = &fnfh.fh_generic;
        tfhp = &tnfh.fh_generic;
@@ -759,24 +787,22 @@ nfsrv_rename(mrep, md, dpos, cred, xid, mrq, repstat, p)
        nfsm_srvmtofh(ffhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        /*
        nfsm_srvmtofh(ffhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        /*
-        * Remember if we are root so that we can reset cr_uid before
-        * the second nfs_namei() call
+        * Remember our original uid so that we can reset cr_uid before
+        * the second nfs_namei() call, in case it is remapped.
         */
         */
-       if (cred->cr_uid == 0)
-               rootflg++;
+       saved_uid = cred->cr_uid;
        fromnd.ni_cred = cred;
        fromnd.ni_nameiop = DELETE | WANTPARENT | SAVESTART;
        fromnd.ni_cred = cred;
        fromnd.ni_nameiop = DELETE | WANTPARENT | SAVESTART;
-       if (error = nfs_namei(&fromnd, ffhp, len, &md, &dpos, p))
+       if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp))
                nfsm_reply(0);
        fvp = fromnd.ni_vp;
        nfsm_srvmtofh(tfhp);
        nfsm_strsiz(len2, NFS_MAXNAMLEN);
                nfsm_reply(0);
        fvp = fromnd.ni_vp;
        nfsm_srvmtofh(tfhp);
        nfsm_strsiz(len2, NFS_MAXNAMLEN);
-       if (rootflg)
-               cred->cr_uid = 0;
+       cred->cr_uid = saved_uid;
        tond.ni_cred = cred;
        tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE
                | SAVESTART;
        tond.ni_cred = cred;
        tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE
                | SAVESTART;
-       if (error = nfs_namei(&tond, tfhp, len2, &md, &dpos, p)) {
+       if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) {
                VOP_ABORTOP(&fromnd);
                vrele(fromnd.ni_dvp);
                vrele(fvp);
                VOP_ABORTOP(&fromnd);
                vrele(fromnd.ni_dvp);
                vrele(fvp);
@@ -792,6 +818,14 @@ nfsrv_rename(mrep, md, dpos, cred, xid, mrq, repstat, p)
                        error = ENOTDIR;
                        goto out;
                }
                        error = ENOTDIR;
                        goto out;
                }
+               if (tvp->v_type == VDIR && tvp->v_mountedhere) {
+                       error = EXDEV;
+                       goto out;
+               }
+       }
+       if (fvp->v_type == VDIR && fvp->v_mountedhere) {
+               error = EBUSY;
+               goto out;
        }
        if (fvp->v_mount != tdvp->v_mount) {
                error = EXDEV;
        }
        if (fvp->v_mount != tdvp->v_mount) {
                error = EXDEV;
@@ -810,7 +844,11 @@ nfsrv_rename(mrep, md, dpos, cred, xid, mrq, repstat, p)
                error = -1;
 out:
        if (!error) {
                error = -1;
 out:
        if (!error) {
-               error = VOP_RENAME(&fromnd, &tond, p);
+               nqsrv_getl(fromnd.ni_dvp, NQL_WRITE);
+               nqsrv_getl(tdvp, NQL_WRITE);
+               if (tvp)
+                       nqsrv_getl(tvp, NQL_WRITE);
+               error = VOP_RENAME(&fromnd, &tond, nfsd->nd_procp);
        } else {
                VOP_ABORTOP(&tond);
                if (tdvp == tvp)
        } else {
                VOP_ABORTOP(&tond);
                if (tdvp == tvp)
@@ -853,38 +891,37 @@ nfsmout:
 /*
  * nfs link service
  */
 /*
  * nfs link service
  */
-nfsrv_link(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf *mrep, *md, **mrq;
+nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
+       struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        struct nameidata nd;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
 {
        struct nameidata nd;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, rdonly, cache, len;
        char *cp2;
        struct mbuf *mb, *mreq;
        struct vnode *vp, *xp;
        nfsv2fh_t nfh, dnfh;
        fhandle_t *fhp, *dfhp;
        char *cp2;
        struct mbuf *mb, *mreq;
        struct vnode *vp, *xp;
        nfsv2fh_t nfh, dnfh;
        fhandle_t *fhp, *dfhp;
-       long len;
+       u_quad_t frev;
 
        fhp = &nfh.fh_generic;
        dfhp = &dnfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvmtofh(dfhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
 
        fhp = &nfh.fh_generic;
        dfhp = &dnfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvmtofh(dfhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
-       if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred))
+       if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
                nfsm_reply(0);
                nfsm_reply(0);
-       if (vp->v_type == VDIR && (error = suser(cred, NULL)))
+       if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0)))
                goto out1;
        nd.ni_cred = cred;
        nd.ni_nameiop = CREATE | LOCKPARENT;
                goto out1;
        nd.ni_cred = cred;
        nd.ni_nameiop = CREATE | LOCKPARENT;
-       if (error = nfs_namei(&nd, dfhp, len, &md, &dpos, p))
+       if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp))
                goto out1;
        xp = nd.ni_vp;
        if (xp != NULL) {
                goto out1;
        xp = nd.ni_vp;
        if (xp != NULL) {
@@ -896,7 +933,9 @@ nfsrv_link(mrep, md, dpos, cred, xid, mrq, repstat, p)
                error = EXDEV;
 out:
        if (!error) {
                error = EXDEV;
 out:
        if (!error) {
-               error = VOP_LINK(vp, &nd, p);
+               nqsrv_getl(vp, NQL_WRITE);
+               nqsrv_getl(xp, NQL_WRITE);
+               error = VOP_LINK(vp, &nd, nfsd->nd_procp);
        } else {
                VOP_ABORTOP(&nd);
                if (nd.ni_dvp == nd.ni_vp)
        } else {
                VOP_ABORTOP(&nd);
                if (nd.ni_dvp == nd.ni_vp)
@@ -915,13 +954,12 @@ out1:
 /*
  * nfs symbolic link service
  */
 /*
  * nfs symbolic link service
  */
-nfsrv_symlink(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf *mrep, *md, **mrq;
+nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
+       struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        struct vattr va;
        struct nameidata nd;
 {
        struct vattr va;
        struct nameidata nd;
@@ -932,12 +970,12 @@ nfsrv_symlink(mrep, md, dpos, cred, xid, mrq, repstat, p)
        caddr_t bpos;
        struct uio io;
        struct iovec iv;
        caddr_t bpos;
        struct uio io;
        struct iovec iv;
-       int error = 0;
+       int error = 0, rdonly, cache, len, len2;
        char *pathcp, *cp2;
        struct mbuf *mb, *mreq;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        char *pathcp, *cp2;
        struct mbuf *mb, *mreq;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
-       long len, len2;
+       u_quad_t frev;
 
        pathcp = (char *)0;
        fhp = &nfh.fh_generic;
 
        pathcp = (char *)0;
        fhp = &nfh.fh_generic;
@@ -945,7 +983,7 @@ nfsrv_symlink(mrep, md, dpos, cred, xid, mrq, repstat, p)
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        nd.ni_cred = cred;
        nd.ni_nameiop = CREATE | LOCKPARENT;
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        nd.ni_cred = cred;
        nd.ni_nameiop = CREATE | LOCKPARENT;
-       if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p))
+       if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp))
                goto out;
        nfsm_strsiz(len2, NFS_MAXPATHLEN);
        MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
                goto out;
        nfsm_strsiz(len2, NFS_MAXPATHLEN);
        MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
@@ -959,7 +997,7 @@ nfsrv_symlink(mrep, md, dpos, cred, xid, mrq, repstat, p)
        io.uio_rw = UIO_READ;
        io.uio_procp = (struct proc *)0;
        nfsm_mtouio(&io, len2);
        io.uio_rw = UIO_READ;
        io.uio_procp = (struct proc *)0;
        nfsm_mtouio(&io, len2);
-       nfsm_disect(sp, struct nfsv2_sattr *, NFSX_SATTR);
+       nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR);
        *(pathcp + len2) = '\0';
        if (nd.ni_vp) {
                VOP_ABORTOP(&nd);
        *(pathcp + len2) = '\0';
        if (nd.ni_vp) {
                VOP_ABORTOP(&nd);
@@ -973,7 +1011,8 @@ nfsrv_symlink(mrep, md, dpos, cred, xid, mrq, repstat, p)
        }
        VATTR_NULL(vap);
        vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
        }
        VATTR_NULL(vap);
        vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
-       error = VOP_SYMLINK(&nd, vap, pathcp, p);
+       nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+       error = VOP_SYMLINK(&nd, vap, pathcp, nfsd->nd_procp);
 out:
        if (pathcp)
                FREE(pathcp, M_TEMP);
 out:
        if (pathcp)
                FREE(pathcp, M_TEMP);
@@ -995,13 +1034,12 @@ nfsmout:
 /*
  * nfs mkdir service
  */
 /*
  * nfs mkdir service
  */
-nfsrv_mkdir(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf *mrep, *md, **mrq;
+nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
+       struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        struct vattr va;
        register struct vattr *vap = &va;
 {
        struct vattr va;
        register struct vattr *vap = &va;
@@ -1011,22 +1049,22 @@ nfsrv_mkdir(mrep, md, dpos, cred, xid, mrq, repstat, p)
        register u_long *tl;
        register long t1;
        caddr_t bpos;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, rdonly, cache, len;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
-       long len;
+       u_quad_t frev;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        nd.ni_cred = cred;
        nd.ni_nameiop = CREATE | LOCKPARENT;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        nd.ni_cred = cred;
        nd.ni_nameiop = CREATE | LOCKPARENT;
-       if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p))
+       if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp))
                nfsm_reply(0);
                nfsm_reply(0);
-       nfsm_disect(tl, u_long *, NFSX_UNSIGNED);
+       nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
        VATTR_NULL(vap);
        vap->va_type = VDIR;
        vap->va_mode = nfstov_mode(*tl++);
        VATTR_NULL(vap);
        vap->va_type = VDIR;
        vap->va_mode = nfstov_mode(*tl++);
@@ -1041,7 +1079,8 @@ nfsrv_mkdir(mrep, md, dpos, cred, xid, mrq, repstat, p)
                error = EEXIST;
                nfsm_reply(0);
        }
                error = EEXIST;
                nfsm_reply(0);
        }
-       if (error = VOP_MKDIR(&nd, vap, p))
+       nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+       if (error = VOP_MKDIR(&nd, vap, nfsd->nd_procp))
                nfsm_reply(0);
        vp = nd.ni_vp;
        bzero((caddr_t)fhp, sizeof(nfh));
                nfsm_reply(0);
        vp = nd.ni_vp;
        bzero((caddr_t)fhp, sizeof(nfh));
@@ -1050,7 +1089,7 @@ nfsrv_mkdir(mrep, md, dpos, cred, xid, mrq, repstat, p)
                vput(vp);
                nfsm_reply(0);
        }
                vput(vp);
                nfsm_reply(0);
        }
-       error = VOP_GETATTR(vp, vap, cred, p);
+       error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
        vput(vp);
        nfsm_reply(NFSX_FH+NFSX_FATTR);
        nfsm_srvfhtom(fhp);
        vput(vp);
        nfsm_reply(NFSX_FH+NFSX_FATTR);
        nfsm_srvfhtom(fhp);
@@ -1071,32 +1110,31 @@ nfsmout:
 /*
  * nfs rmdir service
  */
 /*
  * nfs rmdir service
  */
-nfsrv_rmdir(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf *mrep, *md, **mrq;
+nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
+       struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        register u_long *tl;
        register long t1;
        caddr_t bpos;
 {
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, rdonly, cache, len;
        char *cp2;
        struct mbuf *mb, *mreq;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        char *cp2;
        struct mbuf *mb, *mreq;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
-       long len;
        struct nameidata nd;
        struct nameidata nd;
+       u_quad_t frev;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        nd.ni_cred = cred;
        nd.ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        nd.ni_cred = cred;
        nd.ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
-       if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p))
+       if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp))
                nfsm_reply(0);
        vp = nd.ni_vp;
        if (vp->v_type != VDIR) {
                nfsm_reply(0);
        vp = nd.ni_vp;
        if (vp->v_type != VDIR) {
@@ -1117,7 +1155,9 @@ nfsrv_rmdir(mrep, md, dpos, cred, xid, mrq, repstat, p)
                error = EBUSY;
 out:
        if (!error) {
                error = EBUSY;
 out:
        if (!error) {
-               error = VOP_RMDIR(&nd, p);
+               nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+               nqsrv_getl(vp, NQL_WRITE);
+               error = VOP_RMDIR(&nd, nfsd->nd_procp);
        } else {
                VOP_ABORTOP(&nd);
                if (nd.ni_dvp == nd.ni_vp)
        } else {
                VOP_ABORTOP(&nd);
                if (nd.ni_dvp == nd.ni_vp)
@@ -1150,6 +1190,7 @@ out:
  *     than requested, but this may not apply to all filesystems. For
  *     example, client NFS does not { although it is never remote mounted
  *     anyhow }
  *     than requested, but this may not apply to all filesystems. For
  *     example, client NFS does not { although it is never remote mounted
  *     anyhow }
+ *     The alternate call nqnfsrv_readdirlook() does lookups as well.
  * PS: The NFS protocol spec. does not clarify what the "count" byte
  *     argument is a count of.. just name strings and file id's or the
  *     entire reply rpc or ...
  * PS: The NFS protocol spec. does not clarify what the "count" byte
  *     argument is a count of.. just name strings and file id's or the
  *     entire reply rpc or ...
@@ -1158,14 +1199,20 @@ out:
  *     to including the status longwords that are not a part of the dir.
  *     "entry" structures, but are in the rpc.
  */
  *     to including the status longwords that are not a part of the dir.
  *     "entry" structures, but are in the rpc.
  */
-nfsrv_readdir(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf **mrq;
+struct flrep {
+       u_long fl_cachable;
+       u_long fl_duration;
+       u_quad_t fl_frev;
+       nfsv2fh_t fl_nfh;
+       struct nfsv2_fattr fl_fattr;
+};
+
+nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        register char *bp, *be;
        register struct mbuf *mp;
 {
        register char *bp, *be;
        register struct mbuf *mp;
@@ -1174,25 +1221,23 @@ nfsrv_readdir(mrep, md, dpos, cred, xid, mrq, repstat, p)
        register u_long *tl;
        register long t1;
        caddr_t bpos;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       int error = 0;
-       char *cp2;
-       struct mbuf *mb, *mb2, *mreq;
-       char *cpos, *cend;
-       int len, nlen, rem, xfer, tsiz, i;
+       struct mbuf *mb, *mb2, *mreq, *mp2;
+       char *cpos, *cend, *cp2, *rbuf;
        struct vnode *vp;
        struct vnode *vp;
-       struct mbuf *mp2, *mp3;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        struct uio io;
        struct iovec iv;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        struct uio io;
        struct iovec iv;
-       int siz, cnt, fullsiz, eofflag;
+       struct vattr va;
+       int len, nlen, rem, xfer, tsiz, i, error = 0;
+       int siz, cnt, fullsiz, eofflag, rdonly, cache;
+       u_quad_t frev;
        u_long on;
        u_long on;
-       char *rbuf;
        off_t off, toff;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        off_t off, toff;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
-       nfsm_disect(tl, u_long *, 2*NFSX_UNSIGNED);
+       nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
        toff = fxdr_unsigned(off_t, *tl++);
        off = (toff & ~(NFS_DIRBLKSIZ-1));
        on = (toff & (NFS_DIRBLKSIZ-1));
        toff = fxdr_unsigned(off_t, *tl++);
        off = (toff & ~(NFS_DIRBLKSIZ-1));
        on = (toff & (NFS_DIRBLKSIZ-1));
@@ -1201,9 +1246,10 @@ nfsrv_readdir(mrep, md, dpos, cred, xid, mrq, repstat, p)
        if (cnt > NFS_MAXREADDIR)
                siz = NFS_MAXREADDIR;
        fullsiz = siz;
        if (cnt > NFS_MAXREADDIR)
                siz = NFS_MAXREADDIR;
        fullsiz = siz;
-       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
                nfsm_reply(0);
                nfsm_reply(0);
-       if (error = nfsrv_access(vp, VEXEC, cred, p)) {
+       nqsrv_getl(vp, NQL_READ);
+       if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) {
                vput(vp);
                nfsm_reply(0);
        }
                vput(vp);
                nfsm_reply(0);
        }
@@ -1265,11 +1311,197 @@ again:
        cpos = rbuf + on;
        cend = rbuf + siz;
        dp = (struct direct *)cpos;
        cpos = rbuf + on;
        cend = rbuf + siz;
        dp = (struct direct *)cpos;
+       len = 3*NFSX_UNSIGNED;  /* paranoia, probably can be 0 */
+       nfsm_reply(siz);
+       mp = mp2 = mb;
+       bp = bpos;
+       be = bp + M_TRAILINGSPACE(mp);
+
+       /* Loop through the records and build reply */
+       while (cpos < cend) {
+               if (dp->d_ino != 0) {
+                       nlen = dp->d_namlen;
+                       rem = nfsm_rndup(nlen)-nlen;
+                       len += (4*NFSX_UNSIGNED + nlen + rem);
+                       if (len > cnt) {
+                               eofflag = 0;
+                               break;
+                       }
+       
+                       /* Build the directory record xdr from the direct entry */
+                       nfsm_clget;
+                       *tl = nfs_true;
+                       bp += NFSX_UNSIGNED;
+                       nfsm_clget;
+                       *tl = txdr_unsigned(dp->d_ino);
+                       bp += NFSX_UNSIGNED;
+                       nfsm_clget;
+                       *tl = txdr_unsigned(nlen);
+                       bp += NFSX_UNSIGNED;
+       
+                       /* And loop around copying the name */
+                       xfer = nlen;
+                       cp = dp->d_name;
+                       while (xfer > 0) {
+                               nfsm_clget;
+                               if ((bp+xfer) > be)
+                                       tsiz = be-bp;
+                               else
+                                       tsiz = xfer;
+                               bcopy(cp, bp, tsiz);
+                               bp += tsiz;
+                               xfer -= tsiz;
+                               if (xfer > 0)
+                                       cp += tsiz;
+                       }
+                       /* And null pad to a long boundary */
+                       for (i = 0; i < rem; i++)
+                               *bp++ = '\0';
+                       nfsm_clget;
+       
+                       /* Finish off the record */
+                       toff += dp->d_reclen;
+                       *tl = txdr_unsigned(toff);
+                       bp += NFSX_UNSIGNED;
+               } else
+                       toff += dp->d_reclen;
+               cpos += dp->d_reclen;
+               dp = (struct direct *)cpos;
+       }
        vrele(vp);
        vrele(vp);
+       nfsm_clget;
+       *tl = nfs_false;
+       bp += NFSX_UNSIGNED;
+       nfsm_clget;
+       if (eofflag)
+               *tl = nfs_true;
+       else
+               *tl = nfs_false;
+       bp += NFSX_UNSIGNED;
+       if (mp != mb) {
+               if (bp < be)
+                       mp->m_len = bp - mtod(mp, caddr_t);
+       } else
+               mp->m_len += bp - bpos;
+       FREE(rbuf, M_TEMP);
+       nfsm_srvdone;
+}
+
+nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
+       struct mbuf *mrep, *md;
+       caddr_t dpos;
+       struct ucred *cred;
+       struct mbuf *nam, **mrq;
+{
+       register char *bp, *be;
+       register struct mbuf *mp;
+       register struct direct *dp;
+       register caddr_t cp;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       struct mbuf *mb, *mb2, *mreq, *mp2;
+       char *cpos, *cend, *cp2, *rbuf;
+       struct vnode *vp, *nvp;
+       struct flrep fl;
+       struct ufid *ufp = (struct ufid *)&fl.fl_nfh.fh_generic.fh_fid;
+       struct mount *mntp;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       struct uio io;
+       struct iovec iv;
+       struct vattr va, *vap = &va;
+       struct nfsv2_fattr *fp;
+       int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2;
+       int siz, cnt, fullsiz, eofflag, rdonly, cache;
+       u_quad_t frev, frev2;
+       u_long on;
+       off_t off, toff;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED);
+       toff = fxdr_unsigned(off_t, *tl++);
+       off = (toff & ~(NFS_DIRBLKSIZ-1));
+       on = (toff & (NFS_DIRBLKSIZ-1));
+       cnt = fxdr_unsigned(int, *tl++);
+       duration2 = fxdr_unsigned(int, *tl);
+       siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1));
+       if (cnt > NFS_MAXREADDIR)
+               siz = NFS_MAXREADDIR;
+       fullsiz = siz;
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
+               nfsm_reply(0);
+       nqsrv_getl(vp, NQL_READ);
+       if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) {
+               vput(vp);
+               nfsm_reply(0);
+       }
+       VOP_UNLOCK(vp);
+       MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
+again:
+       iv.iov_base = rbuf;
+       iv.iov_len = fullsiz;
+       io.uio_iov = &iv;
+       io.uio_iovcnt = 1;
+       io.uio_offset = off;
+       io.uio_resid = fullsiz;
+       io.uio_segflg = UIO_SYSSPACE;
+       io.uio_rw = UIO_READ;
+       io.uio_procp = (struct proc *)0;
+       error = VOP_READDIR(vp, &io, cred, &eofflag);
+       off = io.uio_offset;
+       if (error) {
+               vrele(vp);
+               free((caddr_t)rbuf, M_TEMP);
+               nfsm_reply(0);
+       }
+       if (io.uio_resid) {
+               siz -= io.uio_resid;
+
+               /*
+                * If nothing read, return eof
+                * rpc reply
+                */
+               if (siz == 0) {
+                       vrele(vp);
+                       nfsm_reply(2*NFSX_UNSIGNED);
+                       nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
+                       *tl++ = nfs_false;
+                       *tl = nfs_true;
+                       FREE((caddr_t)rbuf, M_TEMP);
+                       return (0);
+               }
+       }
+
+       /*
+        * Check for degenerate cases of nothing useful read.
+        * If so go try again
+        */
+       cpos = rbuf + on;
+       cend = rbuf + siz;
+       dp = (struct direct *)cpos;
+       while (cpos < cend && dp->d_ino == 0) {
+               cpos += dp->d_reclen;
+               dp = (struct direct *)cpos;
+       }
+       if (cpos >= cend) {
+               toff = off;
+               siz = fullsiz;
+               on = 0;
+               goto again;
+       }
+
+       cpos = rbuf + on;
+       cend = rbuf + siz;
+       dp = (struct direct *)cpos;
        len = 3*NFSX_UNSIGNED;  /* paranoia, probably can be 0 */
        len = 3*NFSX_UNSIGNED;  /* paranoia, probably can be 0 */
-       bp = be = (caddr_t)0;
-       mp3 = (struct mbuf *)0;
        nfsm_reply(siz);
        nfsm_reply(siz);
+       mp = mp2 = mb;
+       bp = bpos;
+       be = bp + M_TRAILINGSPACE(mp);
+       mntp = vp->v_mount;
 
        /* Loop through the records and build reply */
        while (cpos < cend) {
 
        /* Loop through the records and build reply */
        while (cpos < cend) {
@@ -1278,11 +1510,29 @@ again:
                        rem = nfsm_rndup(nlen)-nlen;
        
                        /*
                        rem = nfsm_rndup(nlen)-nlen;
        
                        /*
-                        * As noted above, the NFS spec. is not clear about what
-                        * should be included in "count" as totalled up here in
-                        * "len".
+                        * For readdir_and_lookup get the vnode using
+                        * the file number.
                         */
                         */
-                       len += (4*NFSX_UNSIGNED+nlen+rem);
+                       bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t));
+                       ufp->ufid_len = sizeof (struct ufid);
+                       ufp->ufid_ino = dp->d_ino;
+                       fl.fl_nfh.fh_generic.fh_fsid = mntp->mnt_stat.f_fsid;
+                       if (VFS_FHTOVP(mntp, (struct fid *)ufp, 1, &nvp))
+                               goto invalid;
+                       (void) nqsrv_getlease(nvp, &duration2, NQL_READ, nfsd,
+                               nam, &cache2, &frev2, cred);
+                       fl.fl_duration = txdr_unsigned(duration2);
+                       fl.fl_cachable = txdr_unsigned(cache2);
+                       txdr_hyper(&frev2, &fl.fl_frev);
+                       if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) {
+                               vput(nvp);
+                               goto invalid;
+                       }
+                       vput(nvp);
+                       fp = &fl.fl_fattr;
+                       nfsm_srvfillattr;
+                       len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH
+                               + NFSX_FATTR);
                        if (len > cnt) {
                                eofflag = 0;
                                break;
                        if (len > cnt) {
                                eofflag = 0;
                                break;
@@ -1292,6 +1542,24 @@ again:
                        nfsm_clget;
                        *tl = nfs_true;
                        bp += NFSX_UNSIGNED;
                        nfsm_clget;
                        *tl = nfs_true;
                        bp += NFSX_UNSIGNED;
+
+                       /*
+                        * For readdir_and_lookup copy the stuff out.
+                        */
+                       xfer = sizeof (struct flrep);
+                       cp = (caddr_t)&fl;
+                       while (xfer > 0) {
+                               nfsm_clget;
+                               if ((bp+xfer) > be)
+                                       tsiz = be-bp;
+                               else
+                                       tsiz = xfer;
+                               bcopy(cp, bp, tsiz);
+                               bp += tsiz;
+                               xfer -= tsiz;
+                               if (xfer > 0)
+                                       cp += tsiz;
+                       }
                        nfsm_clget;
                        *tl = txdr_unsigned(dp->d_ino);
                        bp += NFSX_UNSIGNED;
                        nfsm_clget;
                        *tl = txdr_unsigned(dp->d_ino);
                        bp += NFSX_UNSIGNED;
@@ -1299,7 +1567,7 @@ again:
                        *tl = txdr_unsigned(nlen);
                        bp += NFSX_UNSIGNED;
        
                        *tl = txdr_unsigned(nlen);
                        bp += NFSX_UNSIGNED;
        
-                       /* And loop arround copying the name */
+                       /* And loop around copying the name */
                        xfer = nlen;
                        cp = dp->d_name;
                        while (xfer > 0) {
                        xfer = nlen;
                        cp = dp->d_name;
                        while (xfer > 0) {
@@ -1324,10 +1592,12 @@ again:
                        *tl = txdr_unsigned(toff);
                        bp += NFSX_UNSIGNED;
                } else
                        *tl = txdr_unsigned(toff);
                        bp += NFSX_UNSIGNED;
                } else
+invalid:
                        toff += dp->d_reclen;
                cpos += dp->d_reclen;
                dp = (struct direct *)cpos;
        }
                        toff += dp->d_reclen;
                cpos += dp->d_reclen;
                dp = (struct direct *)cpos;
        }
+       vrele(vp);
        nfsm_clget;
        *tl = nfs_false;
        bp += NFSX_UNSIGNED;
        nfsm_clget;
        *tl = nfs_false;
        bp += NFSX_UNSIGNED;
@@ -1337,9 +1607,11 @@ again:
        else
                *tl = nfs_false;
        bp += NFSX_UNSIGNED;
        else
                *tl = nfs_false;
        bp += NFSX_UNSIGNED;
-       if (bp < be)
-               mp->m_len = bp-mtod(mp, caddr_t);
-       mb->m_next = mp3;
+       if (mp != mb) {
+               if (bp < be)
+                       mp->m_len = bp - mtod(mp, caddr_t);
+       } else
+               mp->m_len += bp - bpos;
        FREE(rbuf, M_TEMP);
        nfsm_srvdone;
 }
        FREE(rbuf, M_TEMP);
        nfsm_srvdone;
 }
@@ -1347,34 +1619,33 @@ again:
 /*
  * nfs statfs service
  */
 /*
  * nfs statfs service
  */
-nfsrv_statfs(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf **mrq;
+nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        register struct statfs *sf;
        register struct nfsv2_statfs *sfp;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
 {
        register struct statfs *sf;
        register struct nfsv2_statfs *sfp;
        register u_long *tl;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, rdonly, cache;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        struct statfs statfs;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        struct statfs statfs;
+       u_quad_t frev;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
-       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
                nfsm_reply(0);
        sf = &statfs;
                nfsm_reply(0);
        sf = &statfs;
-       error = VFS_STATFS(vp->v_mount, sf, p);
+       error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp);
        vput(vp);
        nfsm_reply(NFSX_STATFS);
        nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS);
        vput(vp);
        nfsm_reply(NFSX_STATFS);
        nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS);
@@ -1390,20 +1661,18 @@ nfsrv_statfs(mrep, md, dpos, cred, xid, mrq, repstat, p)
  * Null operation, used by clients to ping server
  */
 /* ARGSUSED */
  * Null operation, used by clients to ping server
  */
 /* ARGSUSED */
-nfsrv_null(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf **mrq;
+nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        caddr_t bpos;
 {
        caddr_t bpos;
-       int error = 0;
+       int error = VNOVAL, cache;
        struct mbuf *mb, *mreq;
        struct mbuf *mb, *mreq;
+       u_quad_t frev;
 
 
-       error = VNOVAL;
        nfsm_reply(0);
        return (error);
 }
        nfsm_reply(0);
        return (error);
 }
@@ -1412,20 +1681,22 @@ nfsrv_null(mrep, md, dpos, cred, xid, mrq, repstat, p)
  * No operation, used for obsolete procedures
  */
 /* ARGSUSED */
  * No operation, used for obsolete procedures
  */
 /* ARGSUSED */
-nfsrv_noop(mrep, md, dpos, cred, xid, mrq, repstat, p)
-       struct mbuf **mrq;
+nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
        struct mbuf *mrep, *md;
        caddr_t dpos;
        struct ucred *cred;
-       u_long xid;
-       int *repstat;
-       struct proc *p;
+       struct mbuf *nam, **mrq;
 {
        caddr_t bpos;
 {
        caddr_t bpos;
-       int error = 0;
+       int error, cache;
        struct mbuf *mb, *mreq;
        struct mbuf *mb, *mreq;
+       u_quad_t frev;
 
 
-       error = EPROCUNAVAIL;
+       if (nfsd->nd_repstat)
+               error = nfsd->nd_repstat;
+       else
+               error = EPROCUNAVAIL;
        nfsm_reply(0);
        return (error);
 }
        nfsm_reply(0);
        return (error);
 }
@@ -1434,28 +1705,29 @@ nfsrv_noop(mrep, md, dpos, cred, xid, mrq, repstat, p)
  * Perform access checking for vnodes obtained from file handles that would
  * refer to files already opened by a Unix client. You cannot just use
  * vn_writechk() and VOP_ACCESS() for two reasons.
  * Perform access checking for vnodes obtained from file handles that would
  * refer to files already opened by a Unix client. You cannot just use
  * vn_writechk() and VOP_ACCESS() for two reasons.
- * 1 - You must check for MNT_EXRDONLY as well as MNT_RDONLY for the write case
+ * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
  * 2 - The owner is to be given access irrespective of mode bits so that
  *     processes that chmod after opening a file don't break. I don't like
  *     this because it opens a security hole, but since the nfs server opens
  *     a security hole the size of a barn door anyhow, what the heck.
  */
  * 2 - The owner is to be given access irrespective of mode bits so that
  *     processes that chmod after opening a file don't break. I don't like
  *     this because it opens a security hole, but since the nfs server opens
  *     a security hole the size of a barn door anyhow, what the heck.
  */
-nfsrv_access(vp, flags, cred, p)
+nfsrv_access(vp, flags, cred, rdonly, p)
        register struct vnode *vp;
        int flags;
        register struct ucred *cred;
        register struct vnode *vp;
        int flags;
        register struct ucred *cred;
+       int rdonly;
        struct proc *p;
 {
        struct vattr vattr;
        int error;
        if (flags & VWRITE) {
        struct proc *p;
 {
        struct vattr vattr;
        int error;
        if (flags & VWRITE) {
-               /* Just vn_writechk() changed to check MNT_EXRDONLY */
+               /* Just vn_writechk() changed to check rdonly */
                /*
                 * Disallow write attempts on read-only file systems;
                 * unless the file is a socket or a block or character
                 * device resident on the file system.
                 */
                /*
                 * Disallow write attempts on read-only file systems;
                 * unless the file is a socket or a block or character
                 * device resident on the file system.
                 */
-               if (vp->v_mount->mnt_flag & (MNT_RDONLY | MNT_EXRDONLY)) {
+               if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
                        switch (vp->v_type) {
                        case VREG: case VDIR: case VLNK:
                                return (EROFS);
                        switch (vp->v_type) {
                        case VREG: case VDIR: case VLNK:
                                return (EROFS);
index 1cce8ab..5e3e0b8 100644 (file)
@@ -7,20 +7,22 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_socket.c        7.23 (Berkeley) %G%
+ *     @(#)nfs_socket.c        7.24 (Berkeley) %G%
  */
 
 /*
  * Socket operations for use by nfs
  */
 
  */
 
 /*
  * Socket operations for use by nfs
  */
 
+#include "types.h"
 #include "param.h"
 #include "param.h"
+#include "uio.h"
 #include "proc.h"
 #include "proc.h"
+#include "signal.h"
 #include "mount.h"
 #include "kernel.h"
 #include "malloc.h"
 #include "mbuf.h"
 #include "mount.h"
 #include "kernel.h"
 #include "malloc.h"
 #include "mbuf.h"
-#include "namei.h"
 #include "vnode.h"
 #include "domain.h"
 #include "protosw.h"
 #include "vnode.h"
 #include "domain.h"
 #include "protosw.h"
 #include "socketvar.h"
 #include "syslog.h"
 #include "tprintf.h"
 #include "socketvar.h"
 #include "syslog.h"
 #include "tprintf.h"
-#include "../netinet/in.h"
-#include "../netinet/tcp.h"
-
+#include "machine/endian.h"
+#include "netinet/in.h"
+#include "netinet/tcp.h"
+#ifdef ISO
+#include "netiso/iso.h"
+#endif
+#include "ufs/ufs/quota.h"
+#include "ufs/ufs/ufsmount.h"
 #include "rpcv2.h"
 #include "nfsv2.h"
 #include "nfs.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 #include "nfsmount.h"
 #include "rpcv2.h"
 #include "nfsv2.h"
 #include "nfs.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 #include "nfsmount.h"
+#include "nfsnode.h"
+#include "nfsrtt.h"
+#include "nqnfs.h"
+
+#include "syslog.h"
 
 #define        TRUE    1
 #define        FALSE   0
 
 
 #define        TRUE    1
 #define        FALSE   0
 
+int netnetnet = sizeof (struct netaddrhash);
+/*
+ * Estimate rto for an nfs rpc sent via. an unreliable datagram.
+ * Use the mean and mean deviation of rtt for the appropriate type of rpc
+ * for the frequent rpcs and a default for the others.
+ * The justification for doing "other" this way is that these rpcs
+ * happen so infrequently that timer est. would probably be stale.
+ * Also, since many of these rpcs are
+ * non-idempotent, a conservative timeout is desired.
+ * getattr, lookup - A+2D
+ * read, write     - A+4D
+ * other           - nm_timeo
+ */
+#define        NFS_RTO(n, t) \
+       ((t) == 0 ? (n)->nm_timeo : \
+        ((t) < 3 ? \
+         (((((n)->nm_srtt[t-1] + 3) >> 2) + (n)->nm_sdrtt[t-1] + 1) >> 1) : \
+         ((((n)->nm_srtt[t-1] + 7) >> 3) + (n)->nm_sdrtt[t-1] + 1)))
+#define        NFS_SRTT(r)     (r)->r_nmp->nm_srtt[proct[(r)->r_procnum] - 1]
+#define        NFS_SDRTT(r)    (r)->r_nmp->nm_sdrtt[proct[(r)->r_procnum] - 1]
 /*
  * External data, mostly RPC constants in XDR form
  */
 extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix,
 /*
  * External data, mostly RPC constants in XDR form
  */
 extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix,
-       rpc_msgaccepted, rpc_call;
-extern u_long nfs_prog, nfs_vers;
-/* Maybe these should be bits in a u_long ?? */
+       rpc_msgaccepted, rpc_call, rpc_autherr, rpc_rejectedcred,
+       rpc_auth_kerb;
+extern u_long nfs_prog, nfs_vers, nqnfs_prog, nqnfs_vers;
+extern time_t nqnfsstarttime;
 extern int nonidempotent[NFS_NPROCS];
 extern int nonidempotent[NFS_NPROCS];
-static int compressrequest[NFS_NPROCS] = {
-       FALSE,
-       TRUE,
-       TRUE,
-       FALSE,
-       TRUE,
-       TRUE,
-       TRUE,
-       FALSE,
-       FALSE,
-       TRUE,
-       TRUE,
-       TRUE,
-       TRUE,
-       TRUE,
-       TRUE,
-       TRUE,
-       TRUE,
-       TRUE,
+
+/*
+ * Maps errno values to nfs error numbers.
+ * Use NFSERR_IO as the catch all for ones not specifically defined in
+ * RFC 1094.
+ */
+static int nfsrv_errmap[ELAST] = {
+  NFSERR_PERM, NFSERR_NOENT,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
+  NFSERR_NXIO, NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
+  NFSERR_IO,   NFSERR_IO,      NFSERR_ACCES,   NFSERR_IO,      NFSERR_IO,
+  NFSERR_IO,   NFSERR_EXIST,   NFSERR_IO,      NFSERR_NODEV,   NFSERR_NOTDIR,
+  NFSERR_ISDIR,        NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
+  NFSERR_IO,   NFSERR_FBIG,    NFSERR_NOSPC,   NFSERR_IO,      NFSERR_ROFS,
+  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
+  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
+  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
+  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
+  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
+  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
+  NFSERR_IO,   NFSERR_IO,      NFSERR_NAMETOL, NFSERR_IO,      NFSERR_IO,
+  NFSERR_NOTEMPTY, NFSERR_IO,  NFSERR_IO,      NFSERR_DQUOT,   NFSERR_STALE,
+  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
+  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
+  NFSERR_IO,
 };
 };
+
+/*
+ * Defines which timer to use for the procnum.
+ * 0 - default
+ * 1 - getattr
+ * 2 - lookup
+ * 3 - read
+ * 4 - write
+ */
+static int proct[NFS_NPROCS] = {
+       0, 1, 0, 0, 2, 3, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0,
+};
+
+/*
+ * There is a congestion window for outstanding rpcs maintained per mount
+ * point. The cwnd size is adjusted in roughly the way that:
+ * Van Jacobson, Congestion avoidance and Control, In "Proceedings of
+ * SIGCOMM '88". ACM, August 1988.
+ * describes for TCP. The cwnd size is chopped in half on a retransmit timeout
+ * and incremented by 1/cwnd when each rpc reply is received and a full cwnd
+ * of rpcs is in progress.
+ * (The sent count and cwnd are scaled for integer arith.)
+ * Variants of "slow start" were tried and were found to be too much of a
+ * performance hit (ave. rtt 3 times larger),
+ * I suspect due to the large rtt that nfs rpcs have.
+ */
+#define        NFS_CWNDSCALE   256
+#define        NFS_MAXCWND     (NFS_CWNDSCALE * 32)
+static int nfs_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, };
 int    nfs_sbwait();
 int    nfs_sbwait();
-void   nfs_disconnect();
-struct mbuf *nfs_compress(), *nfs_uncompress();
+void   nfs_disconnect(), nfs_realign(), nfsrv_wakenfsd(), nfs_sndunlock();
+void   nfs_rcvunlock(), nqnfs_serverd();
+struct mbuf *nfsm_rpchead();
+int nfsrtton = 0;
+struct nfsrtt nfsrtt;
+struct nfsd nfsd_head;
 
 int    nfsrv_null(),
        nfsrv_getattr(),
 
 int    nfsrv_null(),
        nfsrv_getattr(),
@@ -89,7 +160,10 @@ int nfsrv_null(),
        nfsrv_rmdir(),
        nfsrv_readdir(),
        nfsrv_statfs(),
        nfsrv_rmdir(),
        nfsrv_readdir(),
        nfsrv_statfs(),
-       nfsrv_noop();
+       nfsrv_noop(),
+       nqnfsrv_readdirlook(),
+       nqnfsrv_getlease(),
+       nqnfsrv_vacated();
 
 int (*nfsrv_procs[NFS_NPROCS])() = {
        nfsrv_null,
 
 int (*nfsrv_procs[NFS_NPROCS])() = {
        nfsrv_null,
@@ -110,21 +184,23 @@ int (*nfsrv_procs[NFS_NPROCS])() = {
        nfsrv_rmdir,
        nfsrv_readdir,
        nfsrv_statfs,
        nfsrv_rmdir,
        nfsrv_readdir,
        nfsrv_statfs,
+       nqnfsrv_readdirlook,
+       nqnfsrv_getlease,
+       nqnfsrv_vacated,
 };
 
 struct nfsreq nfsreqh;
 };
 
 struct nfsreq nfsreqh;
-int nfsrexmtthresh = NFS_FISHY;
-int nfs_tcpnodelay = 1;
 
 /*
  * Initialize sockets and congestion for a new NFS connection.
  * We do not free the sockaddr if error.
  */
 
 /*
  * Initialize sockets and congestion for a new NFS connection.
  * We do not free the sockaddr if error.
  */
-nfs_connect(nmp)
+nfs_connect(nmp, rep)
        register struct nfsmount *nmp;
        register struct nfsmount *nmp;
+       struct nfsreq *rep;
 {
        register struct socket *so;
 {
        register struct socket *so;
-       int s, error, bufsize;
+       int s, error, rcvreserve, sndreserve;
        struct mbuf *m;
 
        nmp->nm_so = (struct socket *)0;
        struct mbuf *m;
 
        nmp->nm_so = (struct socket *)0;
@@ -134,15 +210,6 @@ nfs_connect(nmp)
        so = nmp->nm_so;
        nmp->nm_soflags = so->so_proto->pr_flags;
 
        so = nmp->nm_so;
        nmp->nm_soflags = so->so_proto->pr_flags;
 
-       if (nmp->nm_sotype == SOCK_DGRAM)
-               bufsize = min(4 * (nmp->nm_wsize + NFS_MAXPKTHDR),
-                   NFS_MAXPACKET);
-       else
-               bufsize = min(4 * (nmp->nm_wsize + NFS_MAXPKTHDR + sizeof(u_long)),
-                   NFS_MAXPACKET + sizeof(u_long));
-       if (error = soreserve(so, bufsize, bufsize))
-               goto bad;
-
        /*
         * Protocols that do not require connections may be optionally left
         * unconnected for servers that reply from a port other than NFS_PORT.
        /*
         * Protocols that do not require connections may be optionally left
         * unconnected for servers that reply from a port other than NFS_PORT.
@@ -158,59 +225,75 @@ nfs_connect(nmp)
 
                /*
                 * Wait for the connection to complete. Cribbed from the
 
                /*
                 * Wait for the connection to complete. Cribbed from the
-                * connect system call but with the wait at negative prio.
+                * connect system call but with the wait timing out so
+                * that interruptible mounts don't hang here for a long time.
                 */
                s = splnet();
                 */
                s = splnet();
-               while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0)
-                       (void) tsleep((caddr_t)&so->so_timeo, PSOCK, "nfscon", 0);
-               splx(s);
+               while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
+                       (void) tsleep((caddr_t)&so->so_timeo, PSOCK,
+                               "nfscon", 2 * hz);
+                       if ((so->so_state & SS_ISCONNECTING) &&
+                           so->so_error == 0 && rep &&
+                           (error = nfs_sigintr(nmp, rep, rep->r_procp))) {
+                               so->so_state &= ~SS_ISCONNECTING;
+                               splx(s);
+                               goto bad;
+                       }
+               }
                if (so->so_error) {
                        error = so->so_error;
                if (so->so_error) {
                        error = so->so_error;
+                       so->so_error = 0;
+                       splx(s);
                        goto bad;
                }
                        goto bad;
                }
+               splx(s);
+       }
+       if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_INT)) {
+               so->so_rcv.sb_timeo = (5 * hz);
+               so->so_snd.sb_timeo = (5 * hz);
+       } else {
+               so->so_rcv.sb_timeo = 0;
+               so->so_snd.sb_timeo = 0;
        }
        if (nmp->nm_sotype == SOCK_DGRAM) {
        }
        if (nmp->nm_sotype == SOCK_DGRAM) {
-               if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_SPONGY | NFSMNT_INT)) {
-                       so->so_rcv.sb_timeo = (5 * hz);
-                       so->so_snd.sb_timeo = (5 * hz);
-               } else {
-                       so->so_rcv.sb_timeo = 0;
-                       so->so_snd.sb_timeo = 0;
-               }
-               nmp->nm_rto = NFS_TIMEO;
+               sndreserve = nmp->nm_wsize + NFS_MAXPKTHDR;
+               rcvreserve = nmp->nm_rsize + NFS_MAXPKTHDR;
+       } else if (nmp->nm_sotype == SOCK_SEQPACKET) {
+               sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 2;
+               rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR) * 2;
        } else {
        } else {
-               if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_SPONGY | NFSMNT_INT)) {
-                       so->so_rcv.sb_timeo = (5 * hz);
-                       so->so_snd.sb_timeo = (5 * hz);
-               } else {
-                       so->so_rcv.sb_timeo = 0;
-                       so->so_snd.sb_timeo = 0;
-               }
+               if (nmp->nm_sotype != SOCK_STREAM)
+                       panic("nfscon sotype");
                if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
                        MGET(m, M_WAIT, MT_SOOPTS);
                        *mtod(m, int *) = 1;
                        m->m_len = sizeof(int);
                        sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
                }
                if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
                        MGET(m, M_WAIT, MT_SOOPTS);
                        *mtod(m, int *) = 1;
                        m->m_len = sizeof(int);
                        sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
                }
-               if (so->so_proto->pr_domain->dom_family == AF_INET &&
-                   so->so_proto->pr_protocol == IPPROTO_TCP &&
-                   nfs_tcpnodelay) {
+               if (so->so_proto->pr_protocol == IPPROTO_TCP) {
                        MGET(m, M_WAIT, MT_SOOPTS);
                        *mtod(m, int *) = 1;
                        m->m_len = sizeof(int);
                        sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
                }
                        MGET(m, M_WAIT, MT_SOOPTS);
                        *mtod(m, int *) = 1;
                        m->m_len = sizeof(int);
                        sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
                }
-               nmp->nm_rto = 10 * NFS_TIMEO;           /* XXX */
+               sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR + sizeof (u_long))
+                               * 2;
+               rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR + sizeof (u_long))
+                               * 2;
        }
        }
+       if (error = soreserve(so, sndreserve, rcvreserve))
+               goto bad;
        so->so_rcv.sb_flags |= SB_NOINTR;
        so->so_snd.sb_flags |= SB_NOINTR;
 
        /* Initialize other non-zero congestion variables */
        so->so_rcv.sb_flags |= SB_NOINTR;
        so->so_snd.sb_flags |= SB_NOINTR;
 
        /* Initialize other non-zero congestion variables */
-       nmp->nm_window = 2;                     /* Initial send window */
-       nmp->nm_ssthresh = NFS_MAXWINDOW;       /* Slowstart threshold */
-       nmp->nm_rttvar = nmp->nm_rto << 1;
+       nmp->nm_srtt[0] = nmp->nm_srtt[1] = nmp->nm_srtt[2] = nmp->nm_srtt[3] =
+               nmp->nm_srtt[4] = (NFS_TIMEO << 3);
+       nmp->nm_sdrtt[0] = nmp->nm_sdrtt[1] = nmp->nm_sdrtt[2] =
+               nmp->nm_sdrtt[3] = nmp->nm_sdrtt[4] = 0;
+       nmp->nm_cwnd = NFS_MAXCWND / 2;     /* Initial send window */
        nmp->nm_sent = 0;
        nmp->nm_sent = 0;
-       nmp->nm_currexmit = 0;
+       nmp->nm_timeouts = 0;
        return (0);
 
 bad:
        return (0);
 
 bad:
@@ -225,22 +308,20 @@ bad:
  * - nfs_connect() again
  * - set R_MUSTRESEND for all outstanding requests on mount point
  * If this fails the mount point is DEAD!
  * - nfs_connect() again
  * - set R_MUSTRESEND for all outstanding requests on mount point
  * If this fails the mount point is DEAD!
- * nb: Must be called with the nfs_solock() set on the mount point.
+ * nb: Must be called with the nfs_sndlock() set on the mount point.
  */
  */
-nfs_reconnect(rep, nmp)
+nfs_reconnect(rep)
        register struct nfsreq *rep;
        register struct nfsreq *rep;
-       register struct nfsmount *nmp;
 {
        register struct nfsreq *rp;
 {
        register struct nfsreq *rp;
+       register struct nfsmount *nmp = rep->r_nmp;
        int error;
 
        int error;
 
+       nfs_disconnect(nmp);
        nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname,
            "trying reconnect");
        nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname,
            "trying reconnect");
-       while (error = nfs_connect(nmp)) {
-#ifdef lint
-               error = error;
-#endif /* lint */
-               if ((nmp->nm_flag & NFSMNT_INT) && nfs_sigintr(rep->r_procp))
+       while (error = nfs_connect(nmp, rep)) {
+               if (error == EINTR || error == ERESTART)
                        return (EINTR);
                (void) tsleep((caddr_t)&lbolt, PSOCK, "nfscon", 0);
        }
                        return (EINTR);
                (void) tsleep((caddr_t)&lbolt, PSOCK, "nfscon", 0);
        }
@@ -279,8 +360,16 @@ nfs_disconnect(nmp)
 
 /*
  * This is the nfs send routine. For connection based socket types, it
 
 /*
  * This is the nfs send routine. For connection based socket types, it
- * must be called with an nfs_solock() on the socket.
+ * must be called with an nfs_sndlock() on the socket.
  * "rep == NULL" indicates that it has been called from a server.
  * "rep == NULL" indicates that it has been called from a server.
+ * For the client side:
+ * - return EINTR if the RPC is terminated, 0 otherwise
+ * - set R_MUSTRESEND if the send fails for any reason
+ * - do any cleanup required by recoverable socket errors (???)
+ * For the server side:
+ * - return EINTR or ERESTART if interrupted by a signal
+ * - return EPIPE if a connection is lost for connection based sockets (TCP...)
+ * - do any cleanup required by recoverable socket errors (???)
  */
 nfs_send(so, nam, top, rep)
        register struct socket *so;
  */
 nfs_send(so, nam, top, rep)
        register struct socket *so;
@@ -289,18 +378,19 @@ nfs_send(so, nam, top, rep)
        struct nfsreq *rep;
 {
        struct mbuf *sendnam;
        struct nfsreq *rep;
 {
        struct mbuf *sendnam;
-       int error, soflags;
+       int error, soflags, flags;
 
        if (rep) {
                if (rep->r_flags & R_SOFTTERM) {
                        m_freem(top);
                        return (EINTR);
                }
 
        if (rep) {
                if (rep->r_flags & R_SOFTTERM) {
                        m_freem(top);
                        return (EINTR);
                }
-               if (rep->r_nmp->nm_so == NULL &&
-                   (error = nfs_reconnect(rep, rep->r_nmp)))
-                       return (error);
+               if ((so = rep->r_nmp->nm_so) == NULL) {
+                       rep->r_flags |= R_MUSTRESEND;
+                       m_freem(top);
+                       return (0);
+               }
                rep->r_flags &= ~R_MUSTRESEND;
                rep->r_flags &= ~R_MUSTRESEND;
-               so = rep->r_nmp->nm_so;
                soflags = rep->r_nmp->nm_soflags;
        } else
                soflags = so->so_proto->pr_flags;
                soflags = rep->r_nmp->nm_soflags;
        } else
                soflags = so->so_proto->pr_flags;
@@ -308,22 +398,32 @@ nfs_send(so, nam, top, rep)
                sendnam = (struct mbuf *)0;
        else
                sendnam = nam;
                sendnam = (struct mbuf *)0;
        else
                sendnam = nam;
+       if (so->so_type == SOCK_SEQPACKET)
+               flags = MSG_EOR;
+       else
+               flags = 0;
 
        error = sosend(so, sendnam, (struct uio *)0, top,
 
        error = sosend(so, sendnam, (struct uio *)0, top,
-               (struct mbuf *)0, 0);
-       if (error == EWOULDBLOCK && rep) {
-               if (rep->r_flags & R_SOFTTERM)
-                       error = EINTR;
-               else {
-                       rep->r_flags |= R_MUSTRESEND;
-                       error = 0;
+               (struct mbuf *)0, flags);
+if(error) printf("nfssnd err=%d\n",error);
+       if (error) {
+               if (rep) {
+                       /*
+                        * Deal with errors for the client side.
+                        */
+                       if (rep->r_flags & R_SOFTTERM)
+                               error = EINTR;
+                       else
+                               rep->r_flags |= R_MUSTRESEND;
                }
                }
+
+               /*
+                * Handle any recoverable (soft) socket errors here. (???)
+                */
+               if (error != EINTR && error != ERESTART &&
+                       error != EWOULDBLOCK && error != EPIPE)
+                       error = 0;
        }
        }
-       /*
-        * Ignore socket errors??
-        */
-       if (error && error != EINTR && error != ERESTART)
-               error = 0;
        return (error);
 }
 
        return (error);
 }
 
@@ -336,30 +436,26 @@ nfs_send(so, nam, top, rep)
  * For SOCK_STREAM we must be very careful to read an entire record once
  * we have read any of it, even if the system call has been interrupted.
  */
  * For SOCK_STREAM we must be very careful to read an entire record once
  * we have read any of it, even if the system call has been interrupted.
  */
-nfs_receive(so, aname, mp, rep)
-       register struct socket *so;
+nfs_receive(rep, aname, mp)
+       register struct nfsreq *rep;
        struct mbuf **aname;
        struct mbuf **mp;
        struct mbuf **aname;
        struct mbuf **mp;
-       register struct nfsreq *rep;
 {
 {
+       register struct socket *so;
        struct uio auio;
        struct iovec aio;
        register struct mbuf *m;
        struct uio auio;
        struct iovec aio;
        register struct mbuf *m;
-       struct mbuf *m2, *mnew, **mbp;
-       caddr_t fcp, tcp;
+       struct mbuf *control;
        u_long len;
        struct mbuf **getnam;
        u_long len;
        struct mbuf **getnam;
-       int error, siz, mlen, soflags, rcvflg;
+       int error, sotype, rcvflg;
 
        /*
         * Set up arguments for soreceive()
         */
        *mp = (struct mbuf *)0;
        *aname = (struct mbuf *)0;
 
        /*
         * Set up arguments for soreceive()
         */
        *mp = (struct mbuf *)0;
        *aname = (struct mbuf *)0;
-       if (rep)
-               soflags = rep->r_nmp->nm_soflags;
-       else
-               soflags = so->so_proto->pr_flags;
+       sotype = rep->r_nmp->nm_sotype;
 
        /*
         * For reliable protocols, lock against other senders/receivers
 
        /*
         * For reliable protocols, lock against other senders/receivers
@@ -369,49 +465,60 @@ nfs_receive(so, aname, mp, rep)
         * We must lock the socket against other receivers
         * until we have an entire rpc request/reply.
         */
         * We must lock the socket against other receivers
         * until we have an entire rpc request/reply.
         */
-       if (soflags & PR_CONNREQUIRED) {
+       if (sotype != SOCK_DGRAM) {
+               if (error = nfs_sndlock(&rep->r_nmp->nm_flag, rep))
+                       return (error);
 tryagain:
                /*
                 * Check for fatal errors and resending request.
                 */
 tryagain:
                /*
                 * Check for fatal errors and resending request.
                 */
-               if (rep) {
-                       /*
-                        * Ugh: If a reconnect attempt just happened, nm_so
-                        * would have changed. NULL indicates a failed
-                        * attempt that has essentially shut down this
-                        * mount point.
-                        */
-                       if (rep->r_mrep || (so = rep->r_nmp->nm_so) == NULL ||
-                               (rep->r_flags & R_SOFTTERM))
-                               return (EINTR);
-                       while (rep->r_flags & R_MUSTRESEND) {
-                               m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT);
-                               nfsstats.rpcretries++;
-                               if (error = nfs_send(so, rep->r_nmp->nm_nam, m,
-                                       rep))
-                                       goto errout;
+               /*
+                * Ugh: If a reconnect attempt just happened, nm_so
+                * would have changed. NULL indicates a failed
+                * attempt that has essentially shut down this
+                * mount point.
+                */
+               if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) {
+                       nfs_sndunlock(&rep->r_nmp->nm_flag);
+                       return (EINTR);
+               }
+               if ((so = rep->r_nmp->nm_so) == NULL) {
+                       if (error = nfs_reconnect(rep)) {
+                               nfs_sndunlock(&rep->r_nmp->nm_flag);
+                               return (error);
+                       }
+                       goto tryagain;
+               }
+               while (rep->r_flags & R_MUSTRESEND) {
+                       m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT);
+                       nfsstats.rpcretries++;
+                       if (error = nfs_send(so, rep->r_nmp->nm_nam, m, rep)) {
+                               if (error == EINTR || error == ERESTART ||
+                                   (error = nfs_reconnect(rep))) {
+                                       nfs_sndunlock(&rep->r_nmp->nm_flag);
+                                       return (error);
+                               }
+                               goto tryagain;
                        }
                }
                        }
                }
-               if ((soflags & PR_ATOMIC) == 0) {
+               nfs_sndunlock(&rep->r_nmp->nm_flag);
+               if (sotype == SOCK_STREAM) {
                        aio.iov_base = (caddr_t) &len;
                        aio.iov_len = sizeof(u_long);
                        auio.uio_iov = &aio;
                        auio.uio_iovcnt = 1;
                        auio.uio_segflg = UIO_SYSSPACE;
                        auio.uio_rw = UIO_READ;
                        aio.iov_base = (caddr_t) &len;
                        aio.iov_len = sizeof(u_long);
                        auio.uio_iov = &aio;
                        auio.uio_iovcnt = 1;
                        auio.uio_segflg = UIO_SYSSPACE;
                        auio.uio_rw = UIO_READ;
-                       auio.uio_procp = (struct proc *)0;
                        auio.uio_offset = 0;
                        auio.uio_resid = sizeof(u_long);
                        do {
                        auio.uio_offset = 0;
                        auio.uio_resid = sizeof(u_long);
                        do {
-                           rcvflg = MSG_WAITALL;
-                           error = soreceive(so, (struct mbuf **)0, &auio,
+                          rcvflg = MSG_WAITALL;
+                          error = soreceive(so, (struct mbuf **)0, &auio,
                                (struct mbuf **)0, (struct mbuf **)0, &rcvflg);
                                (struct mbuf **)0, (struct mbuf **)0, &rcvflg);
-                           if (error == EWOULDBLOCK && rep) {
+                          if (error == EWOULDBLOCK && rep) {
                                if (rep->r_flags & R_SOFTTERM)
                                        return (EINTR);
                                if (rep->r_flags & R_SOFTTERM)
                                        return (EINTR);
-                               if (rep->r_flags & R_MUSTRESEND)
-                                       goto tryagain;
-                           }
+                          }
                        } while (error == EWOULDBLOCK);
                        if (!error && auio.uio_resid > 0) {
                            if (rep)
                        } while (error == EWOULDBLOCK);
                        if (!error && auio.uio_resid > 0) {
                            if (rep)
@@ -454,24 +561,35 @@ tryagain:
                            error = EPIPE;
                        }
                } else {
                            error = EPIPE;
                        }
                } else {
-                       auio.uio_resid = len = 1000000; /* Anything Big */
+                       /*
+                        * NB: Since uio_resid is big, MSG_WAITALL is ignored
+                        * and soreceive() will return when it has either a
+                        * control msg or a data msg.
+                        * We have no use for control msg., but must grab them
+                        * and then throw them away so we know what is going
+                        * on.
+                        */
+                       auio.uio_resid = len = 100000000; /* Anything Big */
                        do {
                            rcvflg = 0;
                            error =  soreceive(so, (struct mbuf **)0,
                        do {
                            rcvflg = 0;
                            error =  soreceive(so, (struct mbuf **)0,
-                               &auio, mp, (struct mbuf **)0, &rcvflg);
+                               &auio, mp, &control, &rcvflg);
+                           if (control)
+                               m_freem(control);
                            if (error == EWOULDBLOCK && rep) {
                                if (rep->r_flags & R_SOFTTERM)
                                        return (EINTR);
                            if (error == EWOULDBLOCK && rep) {
                                if (rep->r_flags & R_SOFTTERM)
                                        return (EINTR);
-                               if (rep->r_flags & R_MUSTRESEND)
-                                       goto tryagain;
                            }
                            }
-                       } while (error == EWOULDBLOCK);
+                       } while (error == EWOULDBLOCK ||
+                                (!error && *mp == NULL && control));
+                       if ((rcvflg & MSG_EOR) == 0)
+                               printf("Egad!!\n");
                        if (!error && *mp == NULL)
                                error = EPIPE;
                        len -= auio.uio_resid;
                }
 errout:
                        if (!error && *mp == NULL)
                                error = EPIPE;
                        len -= auio.uio_resid;
                }
 errout:
-               if (error && rep && error != EINTR && error != ERESTART) {
+               if (error && error != EINTR && error != ERESTART) {
                        m_freem(*mp);
                        *mp = (struct mbuf *)0;
                        if (error != EPIPE && rep)
                        m_freem(*mp);
                        *mp = (struct mbuf *)0;
                        if (error != EPIPE && rep)
@@ -479,12 +597,15 @@ errout:
                                    "receive error %d from nfs server %s\n",
                                    error,
                                 rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
                                    "receive error %d from nfs server %s\n",
                                    error,
                                 rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
-                       nfs_disconnect(rep->r_nmp);
-                       error = nfs_reconnect(rep, rep->r_nmp);
+                       error = nfs_sndlock(&rep->r_nmp->nm_flag, rep);
+                       if (!error)
+                               error = nfs_reconnect(rep);
                        if (!error)
                                goto tryagain;
                }
        } else {
                        if (!error)
                                goto tryagain;
                }
        } else {
+               if ((so = rep->r_nmp->nm_so) == NULL)
+                       return (EACCES);
                if (so->so_state & SS_ISCONNECTED)
                        getnam = (struct mbuf **)0;
                else
                if (so->so_state & SS_ISCONNECTED)
                        getnam = (struct mbuf **)0;
                else
@@ -494,7 +615,7 @@ errout:
                        rcvflg = 0;
                        error =  soreceive(so, getnam, &auio, mp,
                                (struct mbuf **)0, &rcvflg);
                        rcvflg = 0;
                        error =  soreceive(so, getnam, &auio, mp,
                                (struct mbuf **)0, &rcvflg);
-                       if (error == EWOULDBLOCK && rep &&
+                       if (error == EWOULDBLOCK &&
                            (rep->r_flags & R_SOFTTERM))
                                return (EINTR);
                } while (error == EWOULDBLOCK);
                            (rep->r_flags & R_SOFTTERM))
                                return (EINTR);
                } while (error == EWOULDBLOCK);
@@ -505,50 +626,12 @@ errout:
                *mp = (struct mbuf *)0;
        }
        /*
                *mp = (struct mbuf *)0;
        }
        /*
-        * Search for any mbufs that are not a multiple of 4 bytes long.
+        * Search for any mbufs that are not a multiple of 4 bytes long
+        * or with m_data not longword aligned.
         * These could cause pointer alignment problems, so copy them to
         * well aligned mbufs.
         */
         * These could cause pointer alignment problems, so copy them to
         * well aligned mbufs.
         */
-       m = *mp;
-       mbp = mp;
-       while (m) {
-               /*
-                * All this for something that may never happen.
-                */
-               if (m->m_next && (m->m_len & 0x3)) {
-                       printf("nfs_rcv odd length!\n");
-                       mlen = 0;
-                       while (m) {
-                               fcp = mtod(m, caddr_t);
-                               while (m->m_len > 0) {
-                                       if (mlen == 0) {
-                                               MGET(m2, M_WAIT, MT_DATA);
-                                               if (len >= MINCLSIZE)
-                                                       MCLGET(m2, M_WAIT);
-                                               m2->m_len = 0;
-                                               mlen = M_TRAILINGSPACE(m2);
-                                               tcp = mtod(m2, caddr_t);
-                                               *mbp = m2;
-                                               mbp = &m2->m_next;
-                                       }
-                                       siz = MIN(mlen, m->m_len);
-                                       bcopy(fcp, tcp, siz);
-                                       m2->m_len += siz;
-                                       mlen -= siz;
-                                       len -= siz;
-                                       tcp += siz;
-                                       m->m_len -= siz;
-                                       fcp += siz;
-                               }
-                               MFREE(m, mnew);
-                               m = mnew;
-                       }
-                       break;
-               }
-               len -= m->m_len;
-               mbp = &m->m_next;
-               m = m->m_next;
-       }
+       nfs_realign(*mp, 5 * NFSX_UNSIGNED);
        return (error);
 }
 
        return (error);
 }
 
@@ -558,17 +641,16 @@ errout:
  * with outstanding requests using the xid, until ours is found.
  */
 /* ARGSUSED */
  * with outstanding requests using the xid, until ours is found.
  */
 /* ARGSUSED */
-nfs_reply(nmp, myrep)
-       struct nfsmount *nmp;
+nfs_reply(myrep)
        struct nfsreq *myrep;
 {
        struct nfsreq *myrep;
 {
-       register struct mbuf *m;
        register struct nfsreq *rep;
        register struct nfsreq *rep;
-       register int error = 0;
-       u_long rxid;
-       struct mbuf *mp, *nam;
-       char *cp;
-       int cnt, xfer;
+       register struct nfsmount *nmp = myrep->r_nmp;
+       register long t1;
+       struct mbuf *mrep, *nam, *md;
+       u_long rxid, *tl;
+       caddr_t dpos, cp2;
+       int error;
 
        /*
         * Loop around until we get our own reply
 
        /*
         * Loop around until we get our own reply
@@ -580,17 +662,20 @@ nfs_reply(nmp, myrep)
                 * Also necessary for connection based protocols to avoid
                 * race conditions during a reconnect.
                 */
                 * Also necessary for connection based protocols to avoid
                 * race conditions during a reconnect.
                 */
-               nfs_solock(&nmp->nm_flag);
+               if (error = nfs_rcvlock(myrep))
+                       return (error);
                /* Already received, bye bye */
                if (myrep->r_mrep != NULL) {
                /* Already received, bye bye */
                if (myrep->r_mrep != NULL) {
-                       nfs_sounlock(&nmp->nm_flag);
+                       nfs_rcvunlock(&nmp->nm_flag);
                        return (0);
                }
                /*
                 * Get the next Rpc reply off the socket
                 */
                        return (0);
                }
                /*
                 * Get the next Rpc reply off the socket
                 */
-               if (error = nfs_receive(nmp->nm_so, &nam, &mp, myrep)) {
-                       nfs_sounlock(&nmp->nm_flag);
+               error = nfs_receive(myrep, &nam, &mrep);
+               nfs_rcvunlock(&nmp->nm_flag);
+if (error) printf("rcv err=%d\n",error);
+               if (error) {
 
                        /*
                         * Ignore routing errors on connectionless protocols??
 
                        /*
                         * Ignore routing errors on connectionless protocols??
@@ -599,70 +684,105 @@ nfs_reply(nmp, myrep)
                                nmp->nm_so->so_error = 0;
                                continue;
                        }
                                nmp->nm_so->so_error = 0;
                                continue;
                        }
-
-                       /*
-                        * Otherwise cleanup and return a fatal error.
-                        */
-                       if (myrep->r_flags & R_TIMING) {
-                               myrep->r_flags &= ~R_TIMING;
-                               nmp->nm_rtt = -1;
-                       }
-                       if (myrep->r_flags & R_SENT) {
-                               myrep->r_flags &= ~R_SENT;
-                               nmp->nm_sent--;
-                       }
                        return (error);
                }
                        return (error);
                }
+               if (nam)
+                       m_freem(nam);
        
                /*
                 * Get the xid and check that it is an rpc reply
                 */
        
                /*
                 * Get the xid and check that it is an rpc reply
                 */
-               m = mp;
-               while (m && m->m_len == 0)
-                       m = m->m_next;
-               if (m == NULL) {
-                       nfsstats.rpcinvalid++;
-                       m_freem(mp);
-                       nfs_sounlock(&nmp->nm_flag);
+               md = mrep;
+               dpos = mtod(md, caddr_t);
+               nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
+               rxid = *tl++;
+               if (*tl != rpc_reply) {
+                       if (nmp->nm_flag & NFSMNT_NQNFS) {
+                               if (nqnfs_callback(nmp, mrep, md, dpos))
+                                       nfsstats.rpcinvalid++;
+                       } else {
+                               nfsstats.rpcinvalid++;
+                               m_freem(mrep);
+                       }
+nfsmout:
                        continue;
                }
                        continue;
                }
-               bcopy(mtod(m, caddr_t), (caddr_t)&rxid, NFSX_UNSIGNED);
+
                /*
                 * Loop through the request list to match up the reply
                 * Iff no match, just drop the datagram
                 */
                /*
                 * Loop through the request list to match up the reply
                 * Iff no match, just drop the datagram
                 */
-               m = mp;
                rep = nfsreqh.r_next;
                while (rep != &nfsreqh) {
                        if (rep->r_mrep == NULL && rxid == rep->r_xid) {
                                /* Found it.. */
                rep = nfsreqh.r_next;
                while (rep != &nfsreqh) {
                        if (rep->r_mrep == NULL && rxid == rep->r_xid) {
                                /* Found it.. */
-                               rep->r_mrep = m;
+                               rep->r_mrep = mrep;
+                               rep->r_md = md;
+                               rep->r_dpos = dpos;
+                               if (nfsrtton) {
+                                       struct rttl *rt;
+
+                                       rt = &nfsrtt.rttl[nfsrtt.pos];
+                                       rt->proc = rep->r_procnum;
+                                       rt->rto = NFS_RTO(nmp, proct[rep->r_procnum]);
+                                       rt->sent = nmp->nm_sent;
+                                       rt->cwnd = nmp->nm_cwnd;
+                                       rt->srtt = nmp->nm_srtt[proct[rep->r_procnum] - 1];
+                                       rt->sdrtt = nmp->nm_sdrtt[proct[rep->r_procnum] - 1];
+                                       rt->fsid = nmp->nm_mountp->mnt_stat.f_fsid;
+                                       rt->tstamp = time;
+                                       if (rep->r_flags & R_TIMING)
+                                               rt->rtt = rep->r_rtt;
+                                       else
+                                               rt->rtt = 1000000;
+                                       nfsrtt.pos = (nfsrtt.pos + 1) % NFSRTTLOGSIZ;
+                               }
                                /*
                                /*
-                                * Update timing
+                                * Update congestion window.
+                                * Do the additive increase of
+                                * one rpc/rtt.
                                 */
                                 */
-                               if (rep->r_flags & R_TIMING) {
-                                       nfs_updatetimer(rep->r_nmp);
-                                       rep->r_flags &= ~R_TIMING;
-                                       rep->r_nmp->nm_rtt = -1;
+                               if (nmp->nm_cwnd <= nmp->nm_sent) {
+                                       nmp->nm_cwnd +=
+                                          (NFS_CWNDSCALE * NFS_CWNDSCALE +
+                                          (nmp->nm_cwnd >> 1)) / nmp->nm_cwnd;
+                                       if (nmp->nm_cwnd > NFS_MAXCWND)
+                                               nmp->nm_cwnd = NFS_MAXCWND;
                                }
                                }
-                               if (rep->r_flags & R_SENT) {
-                                       rep->r_flags &= ~R_SENT;
-                                       rep->r_nmp->nm_sent--;
+                               nmp->nm_sent -= NFS_CWNDSCALE;
+                               /*
+                                * Update rtt using a gain of 0.125 on the mean
+                                * and a gain of 0.25 on the deviation.
+                                */
+                               if (rep->r_flags & R_TIMING) {
+                                       /*
+                                        * Since the timer resolution of
+                                        * NFS_HZ is so course, it can often
+                                        * result in r_rtt == 0. Since
+                                        * r_rtt == N means that the actual
+                                        * rtt is between N+dt and N+2-dt ticks,
+                                        * add 1.
+                                        */
+                                       t1 = rep->r_rtt + 1;
+                                       t1 -= (NFS_SRTT(rep) >> 3);
+                                       NFS_SRTT(rep) += t1;
+                                       if (t1 < 0)
+                                               t1 = -t1;
+                                       t1 -= (NFS_SDRTT(rep) >> 2);
+                                       NFS_SDRTT(rep) += t1;
                                }
                                }
+                               nmp->nm_timeouts = 0;
                                break;
                        }
                        rep = rep->r_next;
                }
                                break;
                        }
                        rep = rep->r_next;
                }
-               nfs_sounlock(&nmp->nm_flag);
-               if (nam)
-                       m_freem(nam);
                /*
                 * If not matched to a request, drop it.
                 * If it's mine, get out.
                 */
                if (rep == &nfsreqh) {
                        nfsstats.rpcunexpected++;
                /*
                 * If not matched to a request, drop it.
                 * If it's mine, get out.
                 */
                if (rep == &nfsreqh) {
                        nfsstats.rpcunexpected++;
-                       m_freem(m);
+                       m_freem(mrep);
                } else if (rep == myrep)
                        return (0);
        }
                } else if (rep == myrep)
                        return (0);
        }
@@ -678,14 +798,12 @@ nfs_reply(nmp, myrep)
  *       by mrep or error
  * nb: always frees up mreq mbuf list
  */
  *       by mrep or error
  * nb: always frees up mreq mbuf list
  */
-nfs_request(vp, mreq, xid, procnum, procp, tryhard, mp, mrp, mdp, dposp)
+nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp)
        struct vnode *vp;
        struct vnode *vp;
-       struct mbuf *mreq;
-       u_long xid;
+       struct mbuf *mrest;
        int procnum;
        struct proc *procp;
        int procnum;
        struct proc *procp;
-       int tryhard;
-       struct mount *mp;
+       struct ucred *cred;
        struct mbuf **mrp;
        struct mbuf **mdp;
        caddr_t *dposp;
        struct mbuf **mrp;
        struct mbuf **mdp;
        caddr_t *dposp;
@@ -693,69 +811,82 @@ nfs_request(vp, mreq, xid, procnum, procp, tryhard, mp, mrp, mdp, dposp)
        register struct mbuf *m, *mrep;
        register struct nfsreq *rep;
        register u_long *tl;
        register struct mbuf *m, *mrep;
        register struct nfsreq *rep;
        register u_long *tl;
-       register int len;
+       register int i;
        struct nfsmount *nmp;
        struct nfsmount *nmp;
-       struct mbuf *md;
+       struct mbuf *md, *mheadend;
        struct nfsreq *reph;
        struct nfsreq *reph;
-       caddr_t dpos;
-       char *cp2;
-       int t1;
-       int s, compressed;
-       int error = 0;
-
-       nmp = VFSTONFS(mp);
-       m = mreq;
+       struct nfsnode *tp, *np;
+       time_t reqtime, waituntil;
+       caddr_t dpos, cp2;
+       int t1, nqlflag, cachable, s, error = 0, mrest_len, auth_len, auth_type;
+       int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0, failed_auth = 0;
+       u_long xid;
+       char *auth_str;
+
+       nmp = VFSTONFS(vp->v_mount);
        MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK);
        MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK);
-       rep->r_xid = xid;
        rep->r_nmp = nmp;
        rep->r_vp = vp;
        rep->r_procp = procp;
        rep->r_nmp = nmp;
        rep->r_vp = vp;
        rep->r_procp = procp;
-       if ((nmp->nm_flag & NFSMNT_SOFT) ||
-           ((nmp->nm_flag & NFSMNT_SPONGY) && !tryhard))
-               rep->r_retry = nmp->nm_retry;
-       else
-               rep->r_retry = NFS_MAXREXMIT + 1;       /* past clip limit */
-       rep->r_flags = rep->r_rexmit = 0;
-       /*
-        * Three cases:
-        * - non-idempotent requests on SOCK_DGRAM use NFS_MINIDEMTIMEO
-        * - idempotent requests on SOCK_DGRAM use 0
-        * - Reliable transports, NFS_RELIABLETIMEO
-        *   Timeouts are still done on reliable transports to ensure detection
-        *   of excessive connection delay.
-        */
-       if (nmp->nm_sotype != SOCK_DGRAM)
-               rep->r_timerinit = -NFS_RELIABLETIMEO;
-       else if (nonidempotent[procnum])
-               rep->r_timerinit = -NFS_MINIDEMTIMEO;
-       else
-               rep->r_timerinit = 0;
-       rep->r_timer = rep->r_timerinit;
-       rep->r_mrep = NULL;
-       len = 0;
+       rep->r_procnum = procnum;
+       i = 0;
+       m = mrest;
        while (m) {
        while (m) {
-               len += m->m_len;
+               i += m->m_len;
                m = m->m_next;
        }
                m = m->m_next;
        }
-       mreq->m_pkthdr.len = len;
-       mreq->m_pkthdr.rcvif = (struct ifnet *)0;
-       compressed = 0;
-       m = mreq;
-       if ((nmp->nm_flag & NFSMNT_COMPRESS) && compressrequest[procnum]) {
-               mreq = nfs_compress(mreq);
-               if (mreq != m) {
-                       len = mreq->m_pkthdr.len;
-                       compressed++;
+       mrest_len = i;
+
+       /*
+        * Get the RPC header with authorization.
+        */
+kerbauth:
+       auth_str = (char *)0;
+       if (nmp->nm_flag & NFSMNT_KERB) {
+               if (failed_auth) {
+                       error = nfs_getauth(nmp, rep, cred, &auth_type,
+                               &auth_str, &auth_len);
+                       if (error) {
+                               free((caddr_t)rep, M_NFSREQ);
+                               m_freem(mrest);
+                               return (error);
+                       }
+               } else {
+                       auth_type = RPCAUTH_UNIX;
+                       auth_len = 5 * NFSX_UNSIGNED;
                }
                }
+       } else {
+               auth_type = RPCAUTH_UNIX;
+               auth_len = ((((cred->cr_ngroups - 1) > nmp->nm_numgrps) ?
+                       nmp->nm_numgrps : (cred->cr_ngroups - 1)) << 2) +
+                       5 * NFSX_UNSIGNED;
        }
        }
+       m = nfsm_rpchead(cred, (nmp->nm_flag & NFSMNT_NQNFS), procnum,
+            auth_type, auth_len, auth_str, mrest, mrest_len, &mheadend, &xid);
+       if (auth_str)
+               free(auth_str, M_TEMP);
+
        /*
        /*
-        * For non-atomic protocols, insert a Sun RPC Record Mark.
+        * For stream protocols, insert a Sun RPC Record Mark.
         */
         */
-       if ((nmp->nm_soflags & PR_ATOMIC) == 0) {
-               M_PREPEND(mreq, sizeof(u_long), M_WAIT);
-               *mtod(mreq, u_long *) = htonl(0x80000000 | len);
+       if (nmp->nm_sotype == SOCK_STREAM) {
+               M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
+               *mtod(m, u_long *) = htonl(0x80000000 |
+                        (m->m_pkthdr.len - NFSX_UNSIGNED));
        }
        }
-       rep->r_mreq = mreq;
+       rep->r_mreq = m;
+       rep->r_xid = xid;
+tryagain:
+       if (nmp->nm_flag & NFSMNT_SOFT)
+               rep->r_retry = nmp->nm_retry;
+       else
+               rep->r_retry = NFS_MAXREXMIT + 1;       /* past clip limit */
+       rep->r_rtt = rep->r_rexmit = 0;
+       if (proct[procnum] > 0)
+               rep->r_flags = R_TIMING;
+       else
+               rep->r_flags = 0;
+       rep->r_mrep = NULL;
 
        /*
         * Do the client side RPC.
 
        /*
         * Do the client side RPC.
@@ -765,47 +896,52 @@ nfs_request(vp, mreq, xid, procnum, procp, tryhard, mp, mrp, mdp, dposp)
         * Chain request into list of outstanding requests. Be sure
         * to put it LAST so timer finds oldest requests first.
         */
         * Chain request into list of outstanding requests. Be sure
         * to put it LAST so timer finds oldest requests first.
         */
-       s = splnet();
+       s = splsoftclock();
        reph = &nfsreqh;
        reph->r_prev->r_next = rep;
        rep->r_prev = reph->r_prev;
        reph->r_prev = rep;
        rep->r_next = reph;
        reph = &nfsreqh;
        reph->r_prev->r_next = rep;
        rep->r_prev = reph->r_prev;
        reph->r_prev = rep;
        rep->r_next = reph;
+
+       /* Get send time for nqnfs */
+       reqtime = time.tv_sec;
+
        /*
         * If backing off another request or avoiding congestion, don't
         * send this one now but let timer do it. If not timing a request,
         * do it now.
         */
        /*
         * If backing off another request or avoiding congestion, don't
         * send this one now but let timer do it. If not timing a request,
         * do it now.
         */
-       if (nmp->nm_sent <= 0 || nmp->nm_sotype != SOCK_DGRAM ||
-           (nmp->nm_currexmit == 0 && nmp->nm_sent < nmp->nm_window)) {
-               nmp->nm_sent++;
-               rep->r_flags |= R_SENT;
-               if (nmp->nm_rtt == -1) {
-                       nmp->nm_rtt = 0;
-                       rep->r_flags |= R_TIMING;
-               }
+       if (nmp->nm_so && (nmp->nm_sotype != SOCK_DGRAM ||
+               (nmp->nm_flag & NFSMNT_DUMBTIMR) ||
+               nmp->nm_sent < nmp->nm_cwnd)) {
                splx(s);
                splx(s);
-               m = m_copym(mreq, 0, M_COPYALL, M_WAIT);
-               if (nmp->nm_soflags & PR_CONNREQUIRED)
-                       nfs_solock(&nmp->nm_flag);
-               error = nfs_send(nmp->nm_so, nmp->nm_nam, m, rep);
                if (nmp->nm_soflags & PR_CONNREQUIRED)
                if (nmp->nm_soflags & PR_CONNREQUIRED)
-                       nfs_sounlock(&nmp->nm_flag);
-               if (error && NFSIGNORE_SOERROR(nmp->nm_soflags, error))
-                       nmp->nm_so->so_error = error = 0;
-       } else
+                       error = nfs_sndlock(&nmp->nm_flag, rep);
+               if (!error) {
+                       m = m_copym(m, 0, M_COPYALL, M_WAIT);
+                       error = nfs_send(nmp->nm_so, nmp->nm_nam, m, rep);
+                       if (nmp->nm_soflags & PR_CONNREQUIRED)
+                               nfs_sndunlock(&nmp->nm_flag);
+               }
+               if (!error && (rep->r_flags & R_MUSTRESEND) == 0) {
+                       nmp->nm_sent += NFS_CWNDSCALE;
+                       rep->r_flags |= R_SENT;
+               }
+       } else {
                splx(s);
                splx(s);
+               rep->r_rtt = -1;
+       }
 
        /*
         * Wait for the reply from our send or the timer's.
         */
        if (!error)
 
        /*
         * Wait for the reply from our send or the timer's.
         */
        if (!error)
-               error = nfs_reply(nmp, rep);
+               error = nfs_reply(rep);
 
        /*
         * RPC done, unlink the request.
         */
 
        /*
         * RPC done, unlink the request.
         */
-       s = splnet();
+       s = splsoftclock();
        rep->r_prev->r_next = rep->r_next;
        rep->r_next->r_prev = rep->r_prev;
        splx(s);
        rep->r_prev->r_next = rep->r_next;
        rep->r_next->r_prev = rep->r_prev;
        splx(s);
@@ -817,179 +953,134 @@ nfs_request(vp, mreq, xid, procnum, procp, tryhard, mp, mrp, mdp, dposp)
        if (!error && (rep->r_flags & R_TPRINTFMSG))
                nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname,
                    "is alive again");
        if (!error && (rep->r_flags & R_TPRINTFMSG))
                nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname,
                    "is alive again");
-       m_freem(rep->r_mreq);
        mrep = rep->r_mrep;
        mrep = rep->r_mrep;
-       FREE((caddr_t)rep, M_NFSREQ);
-       if (error)
+       md = rep->r_md;
+       dpos = rep->r_dpos;
+       if (error) {
+               m_freem(rep->r_mreq);
+               free((caddr_t)rep, M_NFSREQ);
                return (error);
                return (error);
+       }
 
 
-       if (compressed)
-               mrep = nfs_uncompress(mrep);
-       md = mrep;
        /*
         * break down the rpc header and check if ok
         */
        /*
         * break down the rpc header and check if ok
         */
-       dpos = mtod(md, caddr_t);
-       nfsm_disect(tl, u_long *, 5*NFSX_UNSIGNED);
-       tl += 2;
+       nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED);
        if (*tl++ == rpc_msgdenied) {
                if (*tl == rpc_mismatch)
                        error = EOPNOTSUPP;
        if (*tl++ == rpc_msgdenied) {
                if (*tl == rpc_mismatch)
                        error = EOPNOTSUPP;
-               else
+               else if ((nmp->nm_flag & NFSMNT_KERB) && *tl++ == rpc_autherr) {
+                       if (*tl == rpc_rejectedcred && failed_auth == 0) {
+                               failed_auth++;
+                               mheadend->m_next = (struct mbuf *)0;
+                               m_freem(mrep);
+                               m_freem(rep->r_mreq);
+                               goto kerbauth;
+                       } else
+                               error = EAUTH;
+               } else
                        error = EACCES;
                m_freem(mrep);
                        error = EACCES;
                m_freem(mrep);
+               m_freem(rep->r_mreq);
+               free((caddr_t)rep, M_NFSREQ);
                return (error);
        }
                return (error);
        }
+
        /*
         * skip over the auth_verf, someday we may want to cache auth_short's
         * for nfs_reqhead(), but for now just dump it
         */
        if (*++tl != 0) {
        /*
         * skip over the auth_verf, someday we may want to cache auth_short's
         * for nfs_reqhead(), but for now just dump it
         */
        if (*++tl != 0) {
-               len = nfsm_rndup(fxdr_unsigned(long, *tl));
-               nfsm_adv(len);
+               i = nfsm_rndup(fxdr_unsigned(long, *tl));
+               nfsm_adv(i);
        }
        }
-       nfsm_disect(tl, u_long *, NFSX_UNSIGNED);
+       nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
        /* 0 == ok */
        if (*tl == 0) {
        /* 0 == ok */
        if (*tl == 0) {
-               nfsm_disect(tl, u_long *, NFSX_UNSIGNED);
+               nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
                if (*tl != 0) {
                        error = fxdr_unsigned(int, *tl);
                        m_freem(mrep);
                if (*tl != 0) {
                        error = fxdr_unsigned(int, *tl);
                        m_freem(mrep);
+                       if ((nmp->nm_flag & NFSMNT_NQNFS) &&
+                           error == NQNFS_TRYLATER) {
+                               error = 0;
+                               waituntil = time.tv_sec + trylater_delay;
+                               while (time.tv_sec < waituntil)
+                                       (void) tsleep((caddr_t)&lbolt,
+                                               PSOCK, "nqnfstry", 0);
+                               trylater_delay *= nfs_backoff[trylater_cnt];
+                               if (trylater_cnt < 7)
+                                       trylater_cnt++;
+                               goto tryagain;
+                       }
+                       m_freem(rep->r_mreq);
+                       free((caddr_t)rep, M_NFSREQ);
                        return (error);
                }
                        return (error);
                }
+
+               /*
+                * For nqnfs, get any lease in reply
+                */
+               if (nmp->nm_flag & NFSMNT_NQNFS) {
+                       nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+                       if (*tl) {
+                               np = VTONFS(vp);
+                               nqlflag = fxdr_unsigned(int, *tl);
+                               nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
+                               cachable = fxdr_unsigned(int, *tl++);
+                               reqtime += fxdr_unsigned(int, *tl++);
+                               if (reqtime > time.tv_sec) {
+                                   if (np->n_tnext) {
+                                       if (np->n_tnext == (struct nfsnode *)nmp)
+                                           nmp->nm_tprev = np->n_tprev;
+                                       else
+                                           np->n_tnext->n_tprev = np->n_tprev;
+                                       if (np->n_tprev == (struct nfsnode *)nmp)
+                                           nmp->nm_tnext = np->n_tnext;
+                                       else
+                                           np->n_tprev->n_tnext = np->n_tnext;
+                                       if (nqlflag == NQL_WRITE)
+                                           np->n_flag |= NQNFSWRITE;
+                                   } else if (nqlflag == NQL_READ)
+                                       np->n_flag &= ~NQNFSWRITE;
+                                   else
+                                       np->n_flag |= NQNFSWRITE;
+                                   if (cachable)
+                                       np->n_flag &= ~NQNFSNONCACHE;
+                                   else
+                                       np->n_flag |= NQNFSNONCACHE;
+                                   np->n_expiry = reqtime;
+                                   fxdr_hyper(tl, &np->n_lrev);
+                                   tp = nmp->nm_tprev;
+                                   while (tp != (struct nfsnode *)nmp &&
+                                          tp->n_expiry > np->n_expiry)
+                                               tp = tp->n_tprev;
+                                   if (tp == (struct nfsnode *)nmp) {
+                                       np->n_tnext = nmp->nm_tnext;
+                                       nmp->nm_tnext = np;
+                                   } else {
+                                       np->n_tnext = tp->n_tnext;
+                                       tp->n_tnext = np;
+                                   }
+                                   np->n_tprev = tp;
+                                   if (np->n_tnext == (struct nfsnode *)nmp)
+                                       nmp->nm_tprev = np;
+                                   else
+                                       np->n_tnext->n_tprev = np;
+                               }
+                       }
+               }
                *mrp = mrep;
                *mdp = md;
                *dposp = dpos;
                *mrp = mrep;
                *mdp = md;
                *dposp = dpos;
+               m_freem(rep->r_mreq);
+               FREE((caddr_t)rep, M_NFSREQ);
                return (0);
        }
        m_freem(mrep);
                return (0);
        }
        m_freem(mrep);
-       return (EPROTONOSUPPORT);
-nfsmout:
-       return (error);
-}
-
-/*
- * Get a request for the server main loop
- * - receive a request via. nfs_soreceive()
- * - verify it
- * - fill in the cred struct.
- */
-nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, procnum, cr,
-       msk, mtch, wascomp)
-       struct socket *so;
-       u_long prog;
-       u_long vers;
-       int maxproc;
-       struct mbuf **nam;
-       struct mbuf **mrp;
-       struct mbuf **mdp;
-       caddr_t *dposp;
-       u_long *retxid;
-       u_long *procnum;
-       register struct ucred *cr;
-       struct mbuf *msk, *mtch;
-       int *wascomp;
-{
-       register int i;
-       register u_long *tl;
-       register long t1;
-       caddr_t dpos, cp2;
-       int error = 0;
-       struct mbuf *mrep, *md;
-       int len;
-
-       if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
-               error = nfs_receive(so, nam, &mrep, (struct nfsreq *)0);
-       } else {
-               mrep = (struct mbuf *)0;
-               do {
-                       if (mrep) {
-                               m_freem(*nam);
-                               m_freem(mrep);
-                       }
-                       error = nfs_receive(so, nam, &mrep, (struct nfsreq *)0);
-               } while (!error && nfs_badnam(*nam, msk, mtch));
-       }
-       if (error)
-               return (error);
-       md = mrep;
-       mrep = nfs_uncompress(mrep);
-       if (mrep != md) {
-               *wascomp = 1;
-               md = mrep;
-       } else
-               *wascomp = 0;
-       dpos = mtod(mrep, caddr_t);
-       nfsm_disect(tl, u_long *, 10*NFSX_UNSIGNED);
-       *retxid = *tl++;
-       if (*tl++ != rpc_call) {
-               m_freem(mrep);
-               return (ERPCMISMATCH);
-       }
-       if (*tl++ != rpc_vers) {
-               m_freem(mrep);
-               return (ERPCMISMATCH);
-       }
-       if (*tl++ != prog) {
-               m_freem(mrep);
-               return (EPROGUNAVAIL);
-       }
-       if (*tl++ != vers) {
-               m_freem(mrep);
-               return (EPROGMISMATCH);
-       }
-       *procnum = fxdr_unsigned(u_long, *tl++);
-       if (*procnum == NFSPROC_NULL) {
-               *mrp = mrep;
-               return (0);
-       }
-       if (*procnum > maxproc || *tl++ != rpc_auth_unix) {
-               m_freem(mrep);
-               return (EPROCUNAVAIL);
-       }
-       len = fxdr_unsigned(int, *tl++);
-       if (len < 0 || len > RPCAUTH_MAXSIZ) {
-               m_freem(mrep);
-               return (EBADRPC);
-       }
-       len = fxdr_unsigned(int, *++tl);
-       if (len < 0 || len > NFS_MAXNAMLEN) {
-               m_freem(mrep);
-               return (EBADRPC);
-       }
-       nfsm_adv(nfsm_rndup(len));
-       nfsm_disect(tl, u_long *, 3*NFSX_UNSIGNED);
-       cr->cr_uid = fxdr_unsigned(uid_t, *tl++);
-       cr->cr_gid = fxdr_unsigned(gid_t, *tl++);
-       len = fxdr_unsigned(int, *tl);
-       if (len < 0 || len > RPCAUTH_UNIXGIDS) {
-               m_freem(mrep);
-               return (EBADRPC);
-       }
-       nfsm_disect(tl, u_long *, (len + 2)*NFSX_UNSIGNED);
-       for (i = 1; i <= len; i++)
-               if (i < NGROUPS)
-                       cr->cr_groups[i] = fxdr_unsigned(gid_t, *tl++);
-               else
-                       tl++;
-       cr->cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1);
-       /*
-        * Do we have any use for the verifier.
-        * According to the "Remote Procedure Call Protocol Spec." it
-        * should be AUTH_NULL, but some clients make it AUTH_UNIX?
-        * For now, just skip over it
-        */
-       len = fxdr_unsigned(int, *++tl);
-       if (len < 0 || len > RPCAUTH_MAXSIZ) {
-               m_freem(mrep);
-               return (EBADRPC);
-       }
-       if (len > 0)
-               nfsm_adv(nfsm_rndup(len));
-       *mrp = mrep;
-       *mdp = md;
-       *dposp = dpos;
-       return (0);
+       m_freem(rep->r_mreq);
+       free((caddr_t)rep, M_NFSREQ);
+       error = EPROTONOSUPPORT;
 nfsmout:
        return (error);
 }
 nfsmout:
        return (error);
 }
@@ -998,33 +1089,49 @@ nfsmout:
  * Generate the rpc reply header
  * siz arg. is used to decide if adding a cluster is worthwhile
  */
  * Generate the rpc reply header
  * siz arg. is used to decide if adding a cluster is worthwhile
  */
-nfs_rephead(siz, retxid, err, mrq, mbp, bposp)
+nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp)
        int siz;
        int siz;
-       u_long retxid;
+       struct nfsd *nd;
        int err;
        int err;
+       int cache;
+       u_quad_t *frev;
        struct mbuf **mrq;
        struct mbuf **mbp;
        caddr_t *bposp;
 {
        register u_long *tl;
        struct mbuf **mrq;
        struct mbuf **mbp;
        caddr_t *bposp;
 {
        register u_long *tl;
-       register long t1;
+       register struct mbuf *mreq;
        caddr_t bpos;
        caddr_t bpos;
-       struct mbuf *mreq, *mb, *mb2;
+       struct mbuf *mb, *mb2;
 
 
-       NFSMGETHDR(mreq);
+       MGETHDR(mreq, M_WAIT, MT_DATA);
        mb = mreq;
        mb = mreq;
-       if ((siz+RPC_REPLYSIZ) > MHLEN)
+       /*
+        * If this is a big reply, use a cluster else
+        * try and leave leading space for the lower level headers.
+        */
+       siz += RPC_REPLYSIZ;
+       if (siz >= MINCLSIZE) {
                MCLGET(mreq, M_WAIT);
                MCLGET(mreq, M_WAIT);
+       } else
+               mreq->m_data += max_hdr;
        tl = mtod(mreq, u_long *);
        mreq->m_len = 6*NFSX_UNSIGNED;
        bpos = ((caddr_t)tl)+mreq->m_len;
        tl = mtod(mreq, u_long *);
        mreq->m_len = 6*NFSX_UNSIGNED;
        bpos = ((caddr_t)tl)+mreq->m_len;
-       *tl++ = retxid;
+       *tl++ = nd->nd_retxid;
        *tl++ = rpc_reply;
        *tl++ = rpc_reply;
-       if (err == ERPCMISMATCH) {
+       if (err == ERPCMISMATCH || err == NQNFS_AUTHERR) {
                *tl++ = rpc_msgdenied;
                *tl++ = rpc_msgdenied;
-               *tl++ = rpc_mismatch;
-               *tl++ = txdr_unsigned(2);
-               *tl = txdr_unsigned(2);
+               if (err == NQNFS_AUTHERR) {
+                       *tl++ = rpc_autherr;
+                       *tl = rpc_rejectedcred;
+                       mreq->m_len -= NFSX_UNSIGNED;
+                       bpos -= NFSX_UNSIGNED;
+               } else {
+                       *tl++ = rpc_mismatch;
+                       *tl++ = txdr_unsigned(2);
+                       *tl = txdr_unsigned(2);
+               }
        } else {
                *tl++ = rpc_msgaccepted;
                *tl++ = 0;
        } else {
                *tl++ = rpc_msgaccepted;
                *tl++ = 0;
@@ -1046,12 +1153,33 @@ nfs_rephead(siz, retxid, err, mrq, mbp, bposp)
                        *tl = 0;
                        if (err != VNOVAL) {
                                nfsm_build(tl, u_long *, NFSX_UNSIGNED);
                        *tl = 0;
                        if (err != VNOVAL) {
                                nfsm_build(tl, u_long *, NFSX_UNSIGNED);
-                               *tl = txdr_unsigned(err);
+                               if (err)
+                                       *tl = txdr_unsigned(nfsrv_errmap[err - 1]);
+                               else
+                                       *tl = 0;
                        }
                        break;
                };
        }
                        }
                        break;
                };
        }
-       *mrq = mreq;
+
+       /*
+        * For nqnfs, piggyback lease as requested.
+        */
+       if (nd->nd_nqlflag != NQL_NOVAL && err == 0) {
+               if (nd->nd_nqlflag) {
+                       nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED);
+                       *tl++ = txdr_unsigned(nd->nd_nqlflag);
+                       *tl++ = txdr_unsigned(cache);
+                       *tl++ = txdr_unsigned(nd->nd_duration);
+                       txdr_hyper(frev, tl);
+               } else {
+                       if (nd->nd_nqlflag != 0)
+                               panic("nqreph");
+                       nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+                       *tl = 0;
+               }
+       }
+       *mrq = mreq;
        *mbp = mb;
        *bposp = bpos;
        if (err != 0 && err != VNOVAL)
        *mbp = mb;
        *bposp = bpos;
        if (err != 0 && err != VNOVAL)
@@ -1071,46 +1199,37 @@ nfs_timer()
        register struct mbuf *m;
        register struct socket *so;
        register struct nfsmount *nmp;
        register struct mbuf *m;
        register struct socket *so;
        register struct nfsmount *nmp;
+       register int timeo;
+       static long lasttime = 0;
        int s, error;
 
        s = splnet();
        for (rep = nfsreqh.r_next; rep != &nfsreqh; rep = rep->r_next) {
                nmp = rep->r_nmp;
        int s, error;
 
        s = splnet();
        for (rep = nfsreqh.r_next; rep != &nfsreqh; rep = rep->r_next) {
                nmp = rep->r_nmp;
-               if (rep->r_mrep || (rep->r_flags & R_SOFTTERM) ||
-                   (so = nmp->nm_so) == NULL)
+               if (rep->r_mrep || (rep->r_flags & R_SOFTTERM))
                        continue;
                        continue;
-               if ((nmp->nm_flag & NFSMNT_INT) && nfs_sigintr(rep->r_procp)) {
+               if (nfs_sigintr(nmp, rep, rep->r_procp)) {
                        rep->r_flags |= R_SOFTTERM;
                        continue;
                }
                        rep->r_flags |= R_SOFTTERM;
                        continue;
                }
-               if (rep->r_flags & R_TIMING)    /* update rtt in mount */
-                       nmp->nm_rtt++;
-               /* If not timed out */
-               if (++rep->r_timer < nmp->nm_rto)
-                       continue;
-               /* Do backoff and save new timeout in mount */
-               if (rep->r_flags & R_TIMING) {
-                       nfs_backofftimer(nmp);
-                       rep->r_flags &= ~R_TIMING;
-                       nmp->nm_rtt = -1;
-               }
-               if (rep->r_flags & R_SENT) {
-                       rep->r_flags &= ~R_SENT;
-                       nmp->nm_sent--;
+               if (rep->r_rtt >= 0) {
+                       rep->r_rtt++;
+                       if (nmp->nm_flag & NFSMNT_DUMBTIMR)
+                               timeo = nmp->nm_timeo;
+                       else
+                               timeo = NFS_RTO(nmp, proct[rep->r_procnum]);
+                       if (nmp->nm_timeouts > 0)
+                               timeo *= nfs_backoff[nmp->nm_timeouts - 1];
+                       if (rep->r_rtt <= timeo)
+                               continue;
+                       if (nmp->nm_timeouts < 8)
+                               nmp->nm_timeouts++;
                }
                }
-
-               /*
-                * Check for too many retries on soft mount.
-                * nb: For hard mounts, r_retry == NFS_MAXREXMIT+1
-                */
-               if (++rep->r_rexmit > NFS_MAXREXMIT)
-                       rep->r_rexmit = NFS_MAXREXMIT;
-
                /*
                 * Check for server not responding
                 */
                if ((rep->r_flags & R_TPRINTFMSG) == 0 &&
                /*
                 * Check for server not responding
                 */
                if ((rep->r_flags & R_TPRINTFMSG) == 0 &&
-                    rep->r_rexmit > NFS_FISHY) {
+                    rep->r_rexmit > nmp->nm_deadthresh) {
                        nfs_msg(rep->r_procp,
                            nmp->nm_mountp->mnt_stat.f_mntfromname,
                            "not responding");
                        nfs_msg(rep->r_procp,
                            nmp->nm_mountp->mnt_stat.f_mntfromname,
                            "not responding");
@@ -1121,267 +1240,898 @@ nfs_timer()
                        rep->r_flags |= R_SOFTTERM;
                        continue;
                }
                        rep->r_flags |= R_SOFTTERM;
                        continue;
                }
-               if (nmp->nm_sotype != SOCK_DGRAM)
+               if (nmp->nm_sotype != SOCK_DGRAM) {
+                       if (++rep->r_rexmit > NFS_MAXREXMIT)
+                               rep->r_rexmit = NFS_MAXREXMIT;
+                       continue;
+               }
+               if ((so = nmp->nm_so) == NULL)
                        continue;
 
                /*
                 * If there is enough space and the window allows..
                 *      Resend it
                        continue;
 
                /*
                 * If there is enough space and the window allows..
                 *      Resend it
+                * Set r_rtt to -1 in case we fail to send it now.
                 */
                 */
+               rep->r_rtt = -1;
                if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len &&
                if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len &&
-                      nmp->nm_sent < nmp->nm_window &&
-                      (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){
-                       nfsstats.rpcretries++;
+                  ((nmp->nm_flag & NFSMNT_DUMBTIMR) ||
+                   (rep->r_flags & R_SENT) ||
+                   nmp->nm_sent < nmp->nm_cwnd) &&
+                  (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){
                        if ((nmp->nm_flag & NFSMNT_NOCONN) == 0)
                            error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
                        if ((nmp->nm_flag & NFSMNT_NOCONN) == 0)
                            error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
-                           (caddr_t)0, (struct mbuf *)0, (struct mbuf *)0);
+                           (struct mbuf *)0, (struct mbuf *)0);
                        else
                            error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
                        else
                            error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
-                           nmp->nm_nam, (struct mbuf *)0, (struct mbuf *)0);
+                           nmp->nm_nam, (struct mbuf *)0);
                        if (error) {
                                if (NFSIGNORE_SOERROR(nmp->nm_soflags, error))
                                        so->so_error = 0;
                        } else {
                                /*
                        if (error) {
                                if (NFSIGNORE_SOERROR(nmp->nm_soflags, error))
                                        so->so_error = 0;
                        } else {
                                /*
-                                * We need to time the request even though we
-                                * are retransmitting.
+                                * Iff first send, start timing
+                                * else turn timing off, backoff timer
+                                * and divide congestion window by 2.
                                 */
                                 */
-                               nmp->nm_rtt = 0;
-                               nmp->nm_sent++;
-                               rep->r_flags |= (R_SENT|R_TIMING);
-                               rep->r_timer = rep->r_timerinit;
+                               if (rep->r_flags & R_SENT) {
+                                       rep->r_flags &= ~R_TIMING;
+                                       if (++rep->r_rexmit > NFS_MAXREXMIT)
+                                               rep->r_rexmit = NFS_MAXREXMIT;
+                                       nmp->nm_cwnd >>= 1;
+                                       if (nmp->nm_cwnd < NFS_CWNDSCALE)
+                                               nmp->nm_cwnd = NFS_CWNDSCALE;
+                                       nfsstats.rpcretries++;
+                               } else {
+                                       rep->r_flags |= R_SENT;
+                                       nmp->nm_sent += NFS_CWNDSCALE;
+                               }
+                               rep->r_rtt = 0;
                        }
                }
        }
                        }
                }
        }
+
+       /*
+        * Call the nqnfs server timer once a second to handle leases.
+        */
+       if (lasttime != time.tv_sec) {
+               lasttime = time.tv_sec;
+               nqnfs_serverd();
+       }
        splx(s);
        timeout(nfs_timer, (caddr_t)0, hz/NFS_HZ);
 }
 
 /*
        splx(s);
        timeout(nfs_timer, (caddr_t)0, hz/NFS_HZ);
 }
 
 /*
- * NFS timer update and backoff. The "Jacobson/Karels/Karn" scheme is
- * used here. The timer state is held in the nfsmount structure and
- * a single request is used to clock the response. When successful
- * the rtt smoothing in nfs_updatetimer is used, when failed the backoff
- * is done by nfs_backofftimer. We also log failure messages in these
- * routines.
- *
- * Congestion variables are held in the nfshost structure which
- * is referenced by nfsmounts and shared per-server. This separation
- * makes it possible to do per-mount timing which allows varying disk
- * access times to be dealt with, while preserving a network oriented
- * congestion control scheme.
- *
- * The windowing implements the Jacobson/Karels slowstart algorithm
- * with adjusted scaling factors. We start with one request, then send
- * 4 more after each success until the ssthresh limit is reached, then
- * we increment at a rate proportional to the window. On failure, we
- * remember 3/4 the current window and clamp the send limit to 1. Note
- * ICMP source quench is not reflected in so->so_error so we ignore that
- * for now.
- *
- * NFS behaves much more like a transport protocol with these changes,
- * shedding the teenage pedal-to-the-metal tendencies of "other"
- * implementations.
- *
- * Timers and congestion avoidance by Tom Talpey, Open Software Foundation.
+ * Test for a termination condition pending on the process.
+ * This is used for NFSMNT_INT mounts.
  */
  */
+nfs_sigintr(nmp, rep, p)
+       struct nfsmount *nmp;
+       struct nfsreq *rep;
+       register struct proc *p;
+{
+
+       if (rep && (rep->r_flags & R_SOFTTERM))
+               return (EINTR);
+       if (!(nmp->nm_flag & NFSMNT_INT))
+               return (0);
+       if (p && p->p_sig && (((p->p_sig &~ p->p_sigmask) &~ p->p_sigignore) &
+           NFSINT_SIGMASK))
+               return (EINTR);
+       return (0);
+}
 
 /*
 
 /*
- * The TCP algorithm was not forgiving enough. Because the NFS server
- * responds only after performing lookups/diskio/etc, we have to be
- * more prepared to accept a spiky variance. The TCP algorithm is:
- * TCP_RTO(nmp) ((((nmp)->nm_srtt >> 2) + (nmp)->nm_rttvar) >> 1)
+ * Lock a socket against others.
+ * Necessary for STREAM sockets to ensure you get an entire rpc request/reply
+ * and also to avoid race conditions between the processes with nfs requests
+ * in progress when a reconnect is necessary.
  */
  */
-#define NFS_RTO(nmp)   (((nmp)->nm_srtt >> 3) + (nmp)->nm_rttvar)
+nfs_sndlock(flagp, rep)
+       register int *flagp;
+       struct nfsreq *rep;
+{
+       struct proc *p;
 
 
-nfs_updatetimer(nmp)
-       register struct nfsmount *nmp;
+       if (rep)
+               p = rep->r_procp;
+       else
+               p = (struct proc *)0;
+       while (*flagp & NFSMNT_SNDLOCK) {
+               if (nfs_sigintr(rep->r_nmp, rep, p))
+                       return (EINTR);
+               *flagp |= NFSMNT_WANTSND;
+               (void) tsleep((caddr_t)flagp, PZERO-1, "nfsndlck", 0);
+       }
+       *flagp |= NFSMNT_SNDLOCK;
+       return (0);
+}
+
+/*
+ * Unlock the stream socket for others.
+ */
+void
+nfs_sndunlock(flagp)
+       register int *flagp;
 {
 
 {
 
-       /* If retransmitted, clear and return */
-       if (nmp->nm_rexmit || nmp->nm_currexmit) {
-               nmp->nm_rexmit = nmp->nm_currexmit = 0;
-               return;
+       if ((*flagp & NFSMNT_SNDLOCK) == 0)
+               panic("nfs sndunlock");
+       *flagp &= ~NFSMNT_SNDLOCK;
+       if (*flagp & NFSMNT_WANTSND) {
+               *flagp &= ~NFSMNT_WANTSND;
+               wakeup((caddr_t)flagp);
        }
        }
-       /* If have a measurement, do smoothing */
-       if (nmp->nm_srtt) {
-               register short delta;
-               delta = nmp->nm_rtt - (nmp->nm_srtt >> 3);
-               if ((nmp->nm_srtt += delta) <= 0)
-                       nmp->nm_srtt = 1;
-               if (delta < 0)
-                       delta = -delta;
-               delta -= (nmp->nm_rttvar >> 2);
-               if ((nmp->nm_rttvar += delta) <= 0)
-                       nmp->nm_rttvar = 1;
-       /* Else initialize */
-       } else {
-               nmp->nm_rttvar = nmp->nm_rtt << 1;
-               if (nmp->nm_rttvar == 0) nmp->nm_rttvar = 2;
-               nmp->nm_srtt = nmp->nm_rttvar << 2;
+}
+
+nfs_rcvlock(rep)
+       register struct nfsreq *rep;
+{
+       register int *flagp = &rep->r_nmp->nm_flag;
+
+       while (*flagp & NFSMNT_RCVLOCK) {
+               if (nfs_sigintr(rep->r_nmp, rep, rep->r_procp))
+                       return (EINTR);
+               *flagp |= NFSMNT_WANTRCV;
+               (void) tsleep((caddr_t)flagp, PZERO-1, "nfsrcvlck", 0);
+       }
+       *flagp |= NFSMNT_RCVLOCK;
+       return (0);
+}
+
+/*
+ * Unlock the stream socket for others.
+ */
+void
+nfs_rcvunlock(flagp)
+       register int *flagp;
+{
+
+       if ((*flagp & NFSMNT_RCVLOCK) == 0)
+               panic("nfs rcvunlock");
+       *flagp &= ~NFSMNT_RCVLOCK;
+       if (*flagp & NFSMNT_WANTRCV) {
+               *flagp &= ~NFSMNT_WANTRCV;
+               wakeup((caddr_t)flagp);
        }
        }
-       /* Compute new Retransmission TimeOut and clip */
-       nmp->nm_rto = NFS_RTO(nmp);
-       if (nmp->nm_rto < NFS_MINTIMEO)
-               nmp->nm_rto = NFS_MINTIMEO;
-       else if (nmp->nm_rto > NFS_MAXTIMEO)
-               nmp->nm_rto = NFS_MAXTIMEO;
-
-       /* Update window estimate */
-       if (nmp->nm_window < nmp->nm_ssthresh)  /* quickly */
-               nmp->nm_window += 4;
-       else {                                          /* slowly */
-               register long incr = ++nmp->nm_winext;
-               incr = (incr * incr) / nmp->nm_window;
-               if (incr > 0) {
-                       nmp->nm_winext = 0;
-                       ++nmp->nm_window;
+}
+
+/*
+ * This function compares two net addresses by family and returns TRUE
+ * if they are the same host.
+ * If there is any doubt, return FALSE.
+ * The AF_INET family is handled as a special case so that address mbufs
+ * don't need to be saved to store "struct in_addr", which is only 4 bytes.
+ */
+nfs_netaddr_match(family, haddr, hmask, nam)
+       int family;
+       union nethostaddr *haddr;
+       union nethostaddr *hmask;
+       struct mbuf *nam;
+{
+       register struct sockaddr_in *inetaddr;
+#ifdef ISO
+       register struct sockaddr_iso *isoaddr1, *isoaddr2;
+#endif
+
+
+       switch (family) {
+       case AF_INET:
+               inetaddr = mtod(nam, struct sockaddr_in *);
+               if (inetaddr->sin_family != AF_INET)
+                       return (0);
+               if (hmask) {
+                       if ((inetaddr->sin_addr.s_addr & hmask->had_inetaddr) ==
+                           (haddr->had_inetaddr & hmask->had_inetaddr))
+                               return (1);
+               } else if (inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
+                       return (1);
+               break;
+#ifdef ISO
+       case AF_ISO:
+               isoaddr1 = mtod(nam, struct sockaddr_iso *);
+               if (isoaddr1->siso_family != AF_ISO)
+                       return (0);
+               isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
+               if (isoaddr1->siso_nlen > 0 &&
+                   isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
+                   SAME_ISOADDR(isoaddr1, isoaddr2))
+                       return (1);
+               break;
+#endif /* ISO */
+       default:
+               break;
+       };
+       return (0);
+}
+
+/*
+ * Build hash lists of net addresses and hang them off the mount point.
+ * Called by ufs_mount() to set up the lists of export addresses.
+ */
+hang_addrlist(mp, argp)
+       struct mount *mp;
+       struct ufs_args *argp;
+{
+       register struct netaddrhash *np, **hnp;
+       register int i;
+       struct ufsmount *ump;
+       struct sockaddr *saddr;
+       struct mbuf *nam, *msk = (struct mbuf *)0;
+       union nethostaddr netmsk;
+       int error;
+
+       if (error = sockargs(&nam, (caddr_t)argp->saddr, argp->slen,
+           MT_SONAME))
+           return (error);
+       saddr = mtod(nam, struct sockaddr *);
+       ump = VFSTOUFS(mp);
+       if (saddr->sa_family == AF_INET &&
+           ((struct sockaddr_in *)saddr)->sin_addr.s_addr == INADDR_ANY) {
+           m_freem(nam);
+           if (mp->mnt_flag & MNT_DEFEXPORTED)
+               return (EPERM);
+           np = &ump->um_defexported;
+           np->neth_exflags = argp->exflags;
+           np->neth_anon = argp->anon;
+           np->neth_anon.cr_ref = 1;
+           mp->mnt_flag |= MNT_DEFEXPORTED;
+           return (0);
+       }
+       if (argp->msklen > 0) {
+           if (error = sockargs(&msk, (caddr_t)argp->smask, argp->msklen,
+               MT_SONAME)) {
+               m_freem(nam);
+               return (error);
+           }
+
+           /*
+            * Scan all the hash lists to check against duplications.
+            * For the net list, try both masks to catch a subnet
+            * of another network.
+            */
+           hnp = &ump->um_netaddr[NETMASK_HASH];
+           np = *hnp;
+           if (saddr->sa_family == AF_INET)
+               netmsk.had_inetaddr =
+                   mtod(msk, struct sockaddr_in *)->sin_addr.s_addr;
+           else
+               netmsk.had_nam = msk;
+           while (np) {
+               if (nfs_netaddr_match(np->neth_family, &np->neth_haddr,
+                   &np->neth_hmask, nam) ||
+                   nfs_netaddr_match(np->neth_family, &np->neth_haddr,
+                   &netmsk, nam)) {
+                       m_freem(nam);
+                       m_freem(msk);
+                       return (EPERM);
+               }
+               np = np->neth_next;
+           }
+           for (i = 0; i < NETHASHSZ; i++) {
+               np = ump->um_netaddr[i];
+               while (np) {
+                   if (nfs_netaddr_match(np->neth_family, &np->neth_haddr,
+                       &netmsk, nam)) {
+                       m_freem(nam);
+                       m_freem(msk);
+                       return (EPERM);
+                   }
+                   np = np->neth_next;
+               }
+           }
+       } else {
+           hnp = &ump->um_netaddr[NETADDRHASH(saddr)];
+           np = ump->um_netaddr[NETMASK_HASH];
+           while (np) {
+               if (nfs_netaddr_match(np->neth_family, &np->neth_haddr,
+                   &np->neth_hmask, nam)) {
+                   m_freem(nam);
+                   return (EPERM);
                }
                }
+               np = np->neth_next;
+           }
+           np = *hnp;
+           while (np) {
+               if (nfs_netaddr_match(np->neth_family, &np->neth_haddr,
+                   (union nethostaddr *)0, nam)) {
+                   m_freem(nam);
+                   return (EPERM);
+               }
+               np = np->neth_next;
+           }
        }
        }
-       if (nmp->nm_window > NFS_MAXWINDOW)
-               nmp->nm_window = NFS_MAXWINDOW;
+       np = (struct netaddrhash *) malloc(sizeof(struct netaddrhash), M_NETADDR,
+           M_WAITOK);
+       np->neth_family = saddr->sa_family;
+       if (saddr->sa_family == AF_INET) {
+               np->neth_inetaddr = ((struct sockaddr_in *)saddr)->sin_addr.s_addr;
+               m_freem(nam);
+               if (msk) {
+                       np->neth_inetmask = netmsk.had_inetaddr;
+                       m_freem(msk);
+                       if (np->neth_inetaddr &~ np->neth_inetmask)
+                               return (EPERM);
+               } else
+                       np->neth_inetmask = 0xffffffff;
+       } else {
+               np->neth_nam = nam;
+               np->neth_msk = msk;
+       }
+       np->neth_exflags = argp->exflags;
+       np->neth_anon = argp->anon;
+       np->neth_anon.cr_ref = 1;
+       np->neth_next = *hnp;
+       *hnp = np;
+       return (0);
 }
 
 }
 
-nfs_backofftimer(nmp)
-       register struct nfsmount *nmp;
+/*
+ * Free the net address hash lists that are hanging off the mount points.
+ */
+free_addrlist(ump)
+       struct ufsmount *ump;
 {
 {
-       register unsigned long newrto;
-
-       /* Clip shift count */
-       if (++nmp->nm_rexmit > 8 * sizeof nmp->nm_rto)
-               nmp->nm_rexmit = 8 * sizeof nmp->nm_rto;
-       /* Back off RTO exponentially */
-       newrto = NFS_RTO(nmp);
-       newrto <<= (nmp->nm_rexmit - 1);
-       if (newrto == 0 || newrto > NFS_MAXTIMEO)
-               newrto = NFS_MAXTIMEO;
-       nmp->nm_rto = newrto;
-
-       /* If too many retries, message, assume a bogus RTT and re-measure */
-       if (nmp->nm_currexmit < nmp->nm_rexmit) {
-               nmp->nm_currexmit = nmp->nm_rexmit;
-               if (nmp->nm_currexmit >= nfsrexmtthresh) {
-                       if (nmp->nm_currexmit == nfsrexmtthresh) {
-                               nmp->nm_rttvar += (nmp->nm_srtt >> 2);
-                               nmp->nm_srtt = 0;
+       register struct netaddrhash *np, *onp;
+       register int i;
+
+       for (i = 0; i <= NETHASHSZ; i++) {
+               np = ump->um_netaddr[i];
+               ump->um_netaddr[i] = (struct netaddrhash *)0;
+               while (np) {
+                       onp = np;
+                       np = np->neth_next;
+                       if (onp->neth_family != AF_INET) {
+                               m_freem(onp->neth_nam);
+                               m_freem(onp->neth_msk);
                        }
                        }
+                       free((caddr_t)onp, M_NETADDR);
                }
        }
                }
        }
-       /* Close down window but remember this point (3/4 current) for later */
-       nmp->nm_ssthresh = ((nmp->nm_window << 1) + nmp->nm_window) >> 2;
-       nmp->nm_window = 1;
-       nmp->nm_winext = 0;
 }
 
 /*
 }
 
 /*
- * Test for a termination signal pending on procp.
- * This is used for NFSMNT_INT mounts.
+ * Generate a hash code for an iso host address. Used by NETADDRHASH() for
+ * iso addresses.
  */
  */
-nfs_sigintr(p)
-       register struct proc *p;
+iso_addrhash(saddr)
+       struct sockaddr *saddr;
 {
 {
-       if (p && p->p_sig && (((p->p_sig &~ p->p_sigmask) &~ p->p_sigignore) &
-           NFSINT_SIGMASK))
-               return (1);
-       else
-               return (0);
+#ifdef ISO
+       register struct sockaddr_iso *siso;
+       register int i, sum;
+
+       sum = 0;
+       for (i = 0; i < siso->siso_nlen; i++)
+               sum += siso->siso_data[i];
+       return (sum & (NETHASHSZ - 1));
+#else
+       return (0);
+#endif /* ISO */
 }
 
 }
 
-nfs_msg(p, server, msg)
-       struct proc *p;
-       char *server, *msg;
+/*
+ * Check for badly aligned mbuf data areas and
+ * realign data in an mbuf list by copying the data areas up, as required.
+ */
+void
+nfs_realign(m, hsiz)
+       register struct mbuf *m;
+       int hsiz;
 {
 {
-       tpr_t tpr;
+       register struct mbuf *m2;
+       register int siz, mlen, olen;
+       register caddr_t tcp, fcp;
+       struct mbuf *mnew;
 
 
-       if (p)
-               tpr = tprintf_open(p);
-       else
-               tpr = NULL;
-       tprintf(tpr, "nfs server %s: %s\n", server, msg);
-       tprintf_close(tpr);
+       while (m) {
+           /*
+            * This never happens for UDP, rarely happens for TCP
+            * but frequently happens for iso transport.
+            */
+           if ((m->m_len & 0x3) || (mtod(m, int) & 0x3)) {
+               olen = m->m_len;
+               fcp = mtod(m, caddr_t);
+               m->m_flags &= ~M_PKTHDR;
+               if (m->m_flags & M_EXT)
+                       m->m_data = m->m_ext.ext_buf;
+               else
+                       m->m_data = m->m_dat;
+               m->m_len = 0;
+               tcp = mtod(m, caddr_t);
+               mnew = m;
+               m2 = m->m_next;
+       
+               /*
+                * If possible, only put the first invariant part
+                * of the RPC header in the first mbuf.
+                */
+               if (olen <= hsiz)
+                       mlen = hsiz;
+               else
+                       mlen = M_TRAILINGSPACE(m);
+       
+               /*
+                * Loop through the mbuf list consolidating data.
+                */
+               while (m) {
+                       while (olen > 0) {
+                               if (mlen == 0) {
+                                       m2->m_flags &= ~M_PKTHDR;
+                                       if (m2->m_flags & M_EXT)
+                                               m2->m_data = m2->m_ext.ext_buf;
+                                       else
+                                               m2->m_data = m2->m_dat;
+                                       m2->m_len = 0;
+                                       mlen = M_TRAILINGSPACE(m2);
+                                       tcp = mtod(m2, caddr_t);
+                                       mnew = m2;
+                                       m2 = m2->m_next;
+                               }
+                               siz = MIN(mlen, olen);
+                               if (tcp != fcp)
+                                       bcopy(fcp, tcp, siz);
+                               mnew->m_len += siz;
+                               mlen -= siz;
+                               olen -= siz;
+                               tcp += siz;
+                               fcp += siz;
+                       }
+                       m = m->m_next;
+                       if (m) {
+                               olen = m->m_len;
+                               fcp = mtod(m, caddr_t);
+                       }
+               }
+       
+               /*
+                * Finally, set m_len == 0 for any trailing mbufs that have
+                * been copied out of.
+                */
+               while (m2) {
+                       m2->m_len = 0;
+                       m2 = m2->m_next;
+               }
+               return;
+           }
+           m = m->m_next;
+       }
 }
 
 /*
 }
 
 /*
- * Lock a socket against others.
- * Necessary for STREAM sockets to ensure you get an entire rpc request/reply
- * and also to avoid race conditions between the processes with nfs requests
- * in progress when a reconnect is necessary.
+ * Socket upcall routine for the nfsd sockets.
+ * The caddr_t arg is a pointer to the "struct nfssvc_sock".
+ * Essentially do as much as possible non-blocking, else punt and it will
+ * be called with M_WAIT from an nfsd.
  */
  */
-nfs_solock(flagp)
-       register int *flagp;
+void
+nfsrv_rcv(so, arg, waitflag)
+       struct socket *so;
+       caddr_t arg;
+       int waitflag;
 {
 {
+       register struct nfssvc_sock *slp = (struct nfssvc_sock *)arg;
+       register struct mbuf *m;
+       struct mbuf *mp, *nam;
+       struct uio auio;
+       int flags, error;
 
 
-       while (*flagp & NFSMNT_SCKLOCK) {
-               *flagp |= NFSMNT_WANTSCK;
-               (void) tsleep((caddr_t)flagp, PZERO-1, "nfsolck", 0);
+       if (so->so_type == SOCK_STREAM) {
+               /*
+                * If there are already records on the queue, defer soreceive()
+                * to an nfsd so that there is feedback to the TCP layer that
+                * the nfs servers are heavily loaded.
+                */
+               if (slp->ns_rec && waitflag == M_DONTWAIT) {
+                       slp->ns_flag |= SLP_NEEDQ;
+                       nfsrv_wakenfsd(slp);
+                       return;
+               }
+
+               /*
+                * Do soreceive().
+                */
+               auio.uio_resid = 1000000000;
+               flags = MSG_DONTWAIT;
+               error = soreceive(so, &nam, &auio, &mp, (struct mbuf **)0, &flags);
+               if (error || mp == (struct mbuf *)0) {
+                       if (error != EWOULDBLOCK) {
+                               slp->ns_flag |= SLP_DISCONN;
+                               if (waitflag == M_DONTWAIT)
+                                       nfsrv_wakenfsd(slp);
+                       }
+                       goto dorecs;
+               }
+               m = mp;
+               if (slp->ns_rawend) {
+                       slp->ns_rawend->m_next = m;
+                       slp->ns_cc += 1000000000 - auio.uio_resid;
+               } else {
+                       slp->ns_raw = m;
+                       slp->ns_cc = 1000000000 - auio.uio_resid;
+               }
+               while (m->m_next)
+                       m = m->m_next;
+               slp->ns_rawend = m;
+
+               /*
+                * Now try and parse record(s) out of the raw stream data.
+                */
+               if (error = nfsrv_getstream(slp, waitflag)) {
+                       if (error == EPERM)
+                               slp->ns_flag |= SLP_DISCONN;
+                       if (error == EWOULDBLOCK)
+                               slp->ns_flag |= SLP_NEEDQ;
+                       if (waitflag == M_DONTWAIT)
+                               nfsrv_wakenfsd(slp);
+               }
+       } else {
+               do {
+                       auio.uio_resid = 1000000000;
+                       flags = MSG_DONTWAIT;
+                       error = soreceive(so, &nam, &auio, &mp,
+                                               (struct mbuf **)0, &flags);
+                       if (mp) {
+                               nfs_realign(mp, 10 * NFSX_UNSIGNED);
+                               if (nam) {
+                                       m = nam;
+                                       m->m_next = mp;
+                               } else
+                                       m = mp;
+                               if (slp->ns_recend)
+                                       slp->ns_recend->m_nextpkt = m;
+                               else
+                                       slp->ns_rec = m;
+                               slp->ns_recend = m;
+                               m->m_nextpkt = (struct mbuf *)0;
+                       }
+                       if (error) {
+                               if ((so->so_proto->pr_flags & PR_CONNREQUIRED)
+                                       && error != EWOULDBLOCK) {
+                                       slp->ns_flag |= SLP_DISCONN;
+                                       if (waitflag == M_DONTWAIT)
+                                               nfsrv_wakenfsd(slp);
+                               }
+                       }
+               } while (mp);
        }
        }
-       *flagp |= NFSMNT_SCKLOCK;
+
+       /*
+        * Now try and process the request records, non-blocking.
+        */
+dorecs:
+       if (slp->ns_rec && waitflag == M_DONTWAIT)
+               nfsrv_wakenfsd(slp);
 }
 
 /*
 }
 
 /*
- * Unlock the stream socket for others.
+ * Try and extract an RPC request from the mbuf data list received on a
+ * stream socket. The "waitflag" argument indicates whether or not it
+ * can sleep.
  */
  */
-nfs_sounlock(flagp)
-       register int *flagp;
+nfsrv_getstream(slp, waitflag)
+       register struct nfssvc_sock *slp;
+       int waitflag;
 {
 {
+       register struct mbuf *m;
+       register char *cp1, *cp2;
+       register int len;
+       struct mbuf *om, *m2, *recm;
+       u_long recmark;
 
 
-       if ((*flagp & NFSMNT_SCKLOCK) == 0)
-               panic("nfs sounlock");
-       *flagp &= ~NFSMNT_SCKLOCK;
-       if (*flagp & NFSMNT_WANTSCK) {
-               *flagp &= ~NFSMNT_WANTSCK;
-               wakeup((caddr_t)flagp);
+       if (slp->ns_flag & SLP_GETSTREAM)
+               panic("nfs getstream");
+       slp->ns_flag |= SLP_GETSTREAM;
+       for (;;) {
+           if (slp->ns_reclen == 0) {
+               if (slp->ns_cc < NFSX_UNSIGNED) {
+                       slp->ns_flag &= ~SLP_GETSTREAM;
+                       return (0);
+               }
+               m = slp->ns_raw;
+               if (m->m_len >= NFSX_UNSIGNED) {
+                       bcopy(mtod(m, caddr_t), (caddr_t)&recmark, NFSX_UNSIGNED);
+                       m->m_data += NFSX_UNSIGNED;
+                       m->m_len -= NFSX_UNSIGNED;
+               } else {
+                       cp1 = (caddr_t)&recmark;
+                       cp2 = mtod(m, caddr_t);
+                       while (cp1 < ((caddr_t)&recmark) + NFSX_UNSIGNED) {
+                               while (m->m_len == 0) {
+                                       m = m->m_next;
+                                       cp2 = mtod(m, caddr_t);
+                               }
+                               *cp1++ = *cp2++;
+                               m->m_data++;
+                               m->m_len--;
+                       }
+               }
+               slp->ns_cc -= NFSX_UNSIGNED;
+               slp->ns_reclen = ntohl(recmark) & ~0x80000000;
+               if (slp->ns_reclen < NFS_MINPACKET || slp->ns_reclen > NFS_MAXPACKET) {
+                       slp->ns_flag &= ~SLP_GETSTREAM;
+                       return (EPERM);
+               }
+           }
+
+           /*
+            * Now get the record part.
+            */
+           if (slp->ns_cc == slp->ns_reclen) {
+               recm = slp->ns_raw;
+               slp->ns_raw = slp->ns_rawend = (struct mbuf *)0;
+               slp->ns_cc = slp->ns_reclen = 0;
+           } else if (slp->ns_cc > slp->ns_reclen) {
+               len = 0;
+               m = slp->ns_raw;
+               om = (struct mbuf *)0;
+               while (len < slp->ns_reclen) {
+                       if ((len + m->m_len) > slp->ns_reclen) {
+                               m2 = m_copym(m, 0, slp->ns_reclen - len,
+                                       waitflag);
+                               if (m2) {
+                                       if (om) {
+                                               om->m_next = m2;
+                                               recm = slp->ns_raw;
+                                       } else
+                                               recm = m2;
+                                       m->m_data += slp->ns_reclen - len;
+                                       m->m_len -= slp->ns_reclen - len;
+                                       len = slp->ns_reclen;
+                               } else {
+                                       slp->ns_flag &= ~SLP_GETSTREAM;
+                                       return (EWOULDBLOCK);
+                               }
+                       } else if ((len + m->m_len) == slp->ns_reclen) {
+                               om = m;
+                               len += m->m_len;
+                               m = m->m_next;
+                               recm = slp->ns_raw;
+                               om->m_next = (struct mbuf *)0;
+                       } else {
+                               om = m;
+                               len += m->m_len;
+                               m = m->m_next;
+                       }
+               }
+               slp->ns_raw = m;
+               slp->ns_cc -= len;
+               slp->ns_reclen = 0;
+           } else {
+               slp->ns_flag &= ~SLP_GETSTREAM;
+               return (0);
+           }
+           nfs_realign(recm, 10 * NFSX_UNSIGNED);
+           if (slp->ns_recend)
+               slp->ns_recend->m_nextpkt = recm;
+           else
+               slp->ns_rec = recm;
+           slp->ns_recend = recm;
        }
 }
 
 /*
        }
 }
 
 /*
- * This function compares two net addresses by family and returns TRUE
- * if they are the same.
- * If there is any doubt, return FALSE.
+ * Parse an RPC header.
+ */
+nfsrv_dorec(slp, nd)
+       register struct nfssvc_sock *slp;
+       register struct nfsd *nd;
+{
+       register struct mbuf *m;
+       int error;
+
+       if (slp->ns_sref != nd->nd_sref ||
+           (m = slp->ns_rec) == (struct mbuf *)0)
+               return (ENOBUFS);
+       if (slp->ns_rec = m->m_nextpkt)
+               m->m_nextpkt = (struct mbuf *)0;
+       else
+               slp->ns_recend = (struct mbuf *)0;
+       if (m->m_type == MT_SONAME) {
+               nd->nd_nam = m;
+               nd->nd_md = nd->nd_mrep = m->m_next;
+               m->m_next = (struct mbuf *)0;
+       } else {
+               nd->nd_nam = (struct mbuf *)0;
+               nd->nd_md = nd->nd_mrep = m;
+       }
+       nd->nd_dpos = mtod(nd->nd_md, caddr_t);
+       if (error = nfs_getreq(nd, TRUE)) {
+               m_freem(nd->nd_nam);
+               return (error);
+       }
+       return (0);
+}
+
+/*
+ * Parse an RPC request
+ * - verify it
+ * - fill in the cred struct.
  */
  */
-nfs_netaddr_match(nam1, nam2)
-       struct mbuf *nam1, *nam2;
+nfs_getreq(nd, has_header)
+       register struct nfsd *nd;
+       int has_header;
 {
 {
-       register struct sockaddr *saddr1, *saddr2;
+       register int len, i;
+       register u_long *tl;
+       register long t1;
+       struct uio uio;
+       struct iovec iov;
+       caddr_t dpos, cp2;
+       u_long nfsvers, auth_type;
+       int error = 0, nqnfs = 0;
+       struct mbuf *mrep, *md;
 
 
-       saddr1 = mtod(nam1, struct sockaddr *);
-       saddr2 = mtod(nam2, struct sockaddr *);
-       if (saddr1->sa_family != saddr2->sa_family)
+       mrep = nd->nd_mrep;
+       md = nd->nd_md;
+       dpos = nd->nd_dpos;
+       if (has_header) {
+               nfsm_dissect(tl, u_long *, 10*NFSX_UNSIGNED);
+               nd->nd_retxid = *tl++;
+               if (*tl++ != rpc_call) {
+                       m_freem(mrep);
+                       return (EBADRPC);
+               }
+       } else {
+               nfsm_dissect(tl, u_long *, 8*NFSX_UNSIGNED);
+       }
+       nd->nd_repstat = 0;
+       if (*tl++ != rpc_vers) {
+               nd->nd_repstat = ERPCMISMATCH;
+               nd->nd_procnum = NFSPROC_NOOP;
                return (0);
                return (0);
+       }
+       nfsvers = nfs_vers;
+       if (*tl != nfs_prog) {
+               if (*tl == nqnfs_prog) {
+                       nqnfs++;
+                       nfsvers = nqnfs_vers;
+               } else {
+                       nd->nd_repstat = EPROGUNAVAIL;
+                       nd->nd_procnum = NFSPROC_NOOP;
+                       return (0);
+               }
+       }
+       tl++;
+       if (*tl++ != nfsvers) {
+               nd->nd_repstat = EPROGMISMATCH;
+               nd->nd_procnum = NFSPROC_NOOP;
+               return (0);
+       }
+       nd->nd_procnum = fxdr_unsigned(u_long, *tl++);
+       if (nd->nd_procnum == NFSPROC_NULL)
+               return (0);
+       if (nd->nd_procnum >= NFS_NPROCS ||
+               (!nqnfs && nd->nd_procnum > NFSPROC_STATFS) ||
+               (*tl != rpc_auth_unix && *tl != rpc_auth_kerb)) {
+               nd->nd_repstat = EPROCUNAVAIL;
+               nd->nd_procnum = NFSPROC_NOOP;
+               return (0);
+       }
+       auth_type = *tl++;
+       len = fxdr_unsigned(int, *tl++);
+       if (len < 0 || len > RPCAUTH_MAXSIZ) {
+               m_freem(mrep);
+               return (EBADRPC);
+       }
 
        /*
 
        /*
-        * Must do each address family separately since unused fields
-        * are undefined values and not always zeroed.
+        * Handle auth_unix or auth_kerb.
         */
         */
-       switch (saddr1->sa_family) {
-       case AF_INET:
-               if (((struct sockaddr_in *)saddr1)->sin_addr.s_addr ==
-                   ((struct sockaddr_in *)saddr2)->sin_addr.s_addr)
-                       return (1);
-               break;
-       default:
-               break;
-       };
+       if (auth_type == rpc_auth_unix) {
+               len = fxdr_unsigned(int, *++tl);
+               if (len < 0 || len > NFS_MAXNAMLEN) {
+                       m_freem(mrep);
+                       return (EBADRPC);
+               }
+               nfsm_adv(nfsm_rndup(len));
+               nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED);
+               nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++);
+               nd->nd_cr.cr_gid = fxdr_unsigned(gid_t, *tl++);
+               len = fxdr_unsigned(int, *tl);
+               if (len < 0 || len > RPCAUTH_UNIXGIDS) {
+                       m_freem(mrep);
+                       return (EBADRPC);
+               }
+               nfsm_dissect(tl, u_long *, (len + 2)*NFSX_UNSIGNED);
+               for (i = 1; i <= len; i++)
+                       if (i < NGROUPS)
+                               nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++);
+                       else
+                               tl++;
+               nd->nd_cr.cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1);
+       } else if (auth_type == rpc_auth_kerb) {
+               nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++);
+               nd->nd_authlen = fxdr_unsigned(int, *tl);
+               iov.iov_len = uio.uio_resid = nfsm_rndup(nd->nd_authlen);
+               if (uio.uio_resid > (len - 2*NFSX_UNSIGNED)) {
+                       m_freem(mrep);
+                       return (EBADRPC);
+               }
+               uio.uio_offset = 0;
+               uio.uio_iov = &iov;
+               uio.uio_iovcnt = 1;
+               uio.uio_segflg = UIO_SYSSPACE;
+               iov.iov_base = (caddr_t)nd->nd_authstr;
+               nfsm_mtouio(&uio, uio.uio_resid);
+               nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
+               nd->nd_flag |= NFSD_NEEDAUTH;
+       }
+
+       /*
+        * Do we have any use for the verifier.
+        * According to the "Remote Procedure Call Protocol Spec." it
+        * should be AUTH_NULL, but some clients make it AUTH_UNIX?
+        * For now, just skip over it
+        */
+       len = fxdr_unsigned(int, *++tl);
+       if (len < 0 || len > RPCAUTH_MAXSIZ) {
+               m_freem(mrep);
+               return (EBADRPC);
+       }
+       if (len > 0) {
+               nfsm_adv(nfsm_rndup(len));
+       }
+
+       /*
+        * For nqnfs, get piggybacked lease request.
+        */
+       if (nqnfs && nd->nd_procnum != NQNFSPROC_EVICTED) {
+               nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+               nd->nd_nqlflag = fxdr_unsigned(int, *tl);
+               if (nd->nd_nqlflag) {
+                       nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+                       nd->nd_duration = fxdr_unsigned(int, *tl);
+               } else
+                       nd->nd_duration = NQ_MINLEASE;
+       } else {
+               nd->nd_nqlflag = NQL_NOVAL;
+               nd->nd_duration = NQ_MINLEASE;
+       }
+       nd->nd_md = md;
+       nd->nd_dpos = dpos;
        return (0);
        return (0);
+nfsmout:
+       return (error);
 }
 
 /*
 }
 
 /*
- * Check the hostname fields for nfsd's mask and match fields.
- * By address family:
- * - Bitwise AND the mask with the host address field
- * - Compare for == with match
- * return TRUE if not equal
+ * Search for a sleeping nfsd and wake it up.
+ * SIDE EFFECT: If none found, set NFSD_CHECKSLP flag, so that one of the
+ * running nfsds will go look for the work in the nfssvc_sock list.
  */
  */
-nfs_badnam(nam, msk, mtch)
-       register struct mbuf *nam, *msk, *mtch;
+void
+nfsrv_wakenfsd(slp)
+       struct nfssvc_sock *slp;
 {
 {
-       switch (mtod(nam, struct sockaddr *)->sa_family) {
-       case AF_INET:
-               return ((mtod(nam, struct sockaddr_in *)->sin_addr.s_addr &
-                        mtod(msk, struct sockaddr_in *)->sin_addr.s_addr) !=
-                        mtod(mtch, struct sockaddr_in *)->sin_addr.s_addr);
-       default:
-               printf("nfs_badmatch, unknown sa_family\n");
-               return (0);
-       };
+       register struct nfsd *nd = nfsd_head.nd_next;
+
+       while (nd != (struct nfsd *)&nfsd_head) {
+               if (nd->nd_flag & NFSD_WAITING) {
+                       nd->nd_flag &= ~NFSD_WAITING;
+                       if (nd->nd_slp)
+                               panic("nfsd wakeup");
+                       nd->nd_slp = slp;
+                       nd->nd_sref = slp->ns_sref;
+                       wakeup((caddr_t)nd);
+                       return;
+               }
+               nd = nd->nd_next;
+       }
+       nfsd_head.nd_flag |= NFSD_CHECKSLP;
+}
+
+nfs_msg(p, server, msg)
+       struct proc *p;
+       char *server, *msg;
+{
+       tpr_t tpr;
+
+       if (p)
+               tpr = tprintf_open(p);
+       else
+               tpr = NULL;
+       tprintf(tpr, "nfs server %s: %s\n", server, msg);
+       tprintf_close(tpr);
 }
 }
index cc0edd9..fdc78b8 100644 (file)
@@ -7,17 +7,15 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_srvcache.c      7.11 (Berkeley) %G%
+ *     @(#)nfs_srvcache.c      7.12 (Berkeley) %G%
  */
 
 /*
  * Reference: Chet Juszczak, "Improving the Performance and Correctness
  */
 
 /*
  * Reference: Chet Juszczak, "Improving the Performance and Correctness
- *            of an NFS Server", in Proc. Winter 1989 USENIX Conference,
- *            pages 53-63. San Diego, February 1989.
+ *             of an NFS Server", in Proc. Winter 1989 USENIX Conference,
+ *             pages 53-63. San Diego, February 1989.
  */
  */
-
 #include "param.h"
 #include "param.h"
-#include "namei.h"
 #include "vnode.h"
 #include "mount.h"
 #include "kernel.h"
 #include "vnode.h"
 #include "mount.h"
 #include "kernel.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "socketvar.h"
-
-#include "../netinet/in.h"
-
+#include "netinet/in.h"
+#ifdef ISO
+#include "netiso/iso.h"
+#endif
 #include "nfsm_subs.h"
 #include "nfsm_subs.h"
+#include "rpcv2.h"
 #include "nfsv2.h"
 #include "nfsrvcache.h"
 #include "nfs.h"
 #include "nfsv2.h"
 #include "nfsrvcache.h"
 #include "nfs.h"
+#include "nqnfs.h"
 
 #if    ((NFSRCHSZ&(NFSRCHSZ-1)) == 0)
 #define        NFSRCHASH(xid)          (((xid)+((xid)>>16))&(NFSRCHSZ-1))
 
 #if    ((NFSRCHSZ&(NFSRCHSZ-1)) == 0)
 #define        NFSRCHASH(xid)          (((xid)+((xid)>>16))&(NFSRCHSZ-1))
@@ -50,6 +51,9 @@ static struct nfsrvcache nfsrvcache[NFSRVCACHESIZ];
 #define TRUE   1
 #define        FALSE   0
 
 #define TRUE   1
 #define        FALSE   0
 
+#define        NETFAMILY(rp) \
+               (((rp)->rc_flag & RC_INETADDR) ? AF_INET : AF_ISO)
+
 /*
  * Static array that defines which nfs rpc's are nonidempotent
  */
 /*
  * Static array that defines which nfs rpc's are nonidempotent
  */
@@ -72,6 +76,10 @@ int nonidempotent[NFS_NPROCS] = {
        TRUE,
        FALSE,
        FALSE,
        TRUE,
        FALSE,
        FALSE,
+       FALSE,
+       FALSE,
+       FALSE,
+       FALSE,
 };
 
 /* True iff the rpc reply is an nfs status ONLY! */
 };
 
 /* True iff the rpc reply is an nfs status ONLY! */
@@ -94,6 +102,10 @@ static int repliesstatus[NFS_NPROCS] = {
        TRUE,
        FALSE,
        FALSE,
        TRUE,
        FALSE,
        FALSE,
+       FALSE,
+       FALSE,
+       FALSE,
+       FALSE,
 };
 
 /*
 };
 
 /*
@@ -138,30 +150,39 @@ nfsrv_initcache()
  *   return DOIT
  * Update/add new request at end of lru list
  */
  *   return DOIT
  * Update/add new request at end of lru list
  */
-nfsrv_getcache(nam, xid, proc, repp)
+nfsrv_getcache(nam, nd, repp)
        struct mbuf *nam;
        struct mbuf *nam;
-       u_long xid;
-       int proc;
+       register struct nfsd *nd;
        struct mbuf **repp;
 {
        register struct nfsrvcache *rp;
        register union  rhead *rh;
        struct mbuf *mb;
        struct mbuf **repp;
 {
        register struct nfsrvcache *rp;
        register union  rhead *rh;
        struct mbuf *mb;
+       struct sockaddr_in *saddr;
        caddr_t bpos;
        int ret;
 
        caddr_t bpos;
        int ret;
 
-       rh = &rhead[NFSRCHASH(xid)];
+       if (nd->nd_nqlflag != NQL_NOVAL)
+               return (RC_DOIT);
+       rh = &rhead[NFSRCHASH(nd->nd_retxid)];
 loop:
        for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
 loop:
        for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
-               if (xid == rp->rc_xid && proc == rp->rc_proc &&
-                   nfs_netaddr_match(nam, &rp->rc_nam)) {
+           if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
+               nfs_netaddr_match(NETFAMILY(rp), &rp->rc_haddr, (union nethostaddr *)0, nam)) {
                        if ((rp->rc_flag & RC_LOCKED) != 0) {
                                rp->rc_flag |= RC_WANTED;
                                (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
                                goto loop;
                        }
                        rp->rc_flag |= RC_LOCKED;
                        if ((rp->rc_flag & RC_LOCKED) != 0) {
                                rp->rc_flag |= RC_WANTED;
                                (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
                                goto loop;
                        }
                        rp->rc_flag |= RC_LOCKED;
-                       put_at_head(rp);
+                       if (rp->rc_prev != &nfsrvcachehead) {
+                               rp->rc_next->rc_prev = rp->rc_prev;
+                               rp->rc_prev->rc_next = rp->rc_next;
+                               rp->rc_next = nfsrvcachehead.rc_next;
+                               nfsrvcachehead.rc_next = rp;
+                               rp->rc_prev = &nfsrvcachehead;
+                               rp->rc_next->rc_prev = rp;
+                       }
                        if (rp->rc_state == RC_UNUSED)
                                panic("nfsrv cache");
                        if (rp->rc_state == RC_INPROG ||
                        if (rp->rc_state == RC_UNUSED)
                                panic("nfsrv cache");
                        if (rp->rc_state == RC_INPROG ||
@@ -170,8 +191,8 @@ loop:
                                ret = RC_DROPIT;
                        } else if (rp->rc_flag & RC_REPSTATUS) {
                                nfsstats.srvcache_idemdonehits++;
                                ret = RC_DROPIT;
                        } else if (rp->rc_flag & RC_REPSTATUS) {
                                nfsstats.srvcache_idemdonehits++;
-                               nfs_rephead(0, xid, rp->rc_status, repp, &mb,
-                                       &bpos);
+                               nfs_rephead(0, nd, rp->rc_status,
+                                  0, (u_quad_t *)0, repp, &mb, &bpos);
                                rp->rc_timestamp = time.tv_sec;
                                ret = RC_REPLY;
                        } else if (rp->rc_flag & RC_REPMBUF) {
                                rp->rc_timestamp = time.tv_sec;
                                ret = RC_REPLY;
                        } else if (rp->rc_flag & RC_REPMBUF) {
@@ -198,43 +219,67 @@ loop:
        while ((rp->rc_flag & RC_LOCKED) != 0) {
                rp->rc_flag |= RC_WANTED;
                (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
        while ((rp->rc_flag & RC_LOCKED) != 0) {
                rp->rc_flag |= RC_WANTED;
                (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
+               rp = nfsrvcachehead.rc_prev;
        }
        }
+       rp->rc_flag |= RC_LOCKED;
        remque(rp);
        remque(rp);
-       put_at_head(rp);
+       if (rp->rc_prev != &nfsrvcachehead) {
+               rp->rc_next->rc_prev = rp->rc_prev;
+               rp->rc_prev->rc_next = rp->rc_next;
+               rp->rc_next = nfsrvcachehead.rc_next;
+               nfsrvcachehead.rc_next = rp;
+               rp->rc_prev = &nfsrvcachehead;
+               rp->rc_next->rc_prev = rp;
+       }
        if (rp->rc_flag & RC_REPMBUF)
        if (rp->rc_flag & RC_REPMBUF)
-               mb = rp->rc_reply;
-       else
-               mb = (struct mbuf *)0;
-       rp->rc_flag = 0;
+               m_freem(rp->rc_reply);
+       if (rp->rc_flag & RC_NAM)
+               MFREE(rp->rc_nam, mb);
+       rp->rc_flag &= (RC_LOCKED | RC_WANTED);
        rp->rc_state = RC_INPROG;
        rp->rc_state = RC_INPROG;
-       rp->rc_xid = xid;
-       bcopy((caddr_t)nam, (caddr_t)&rp->rc_nam, sizeof (struct mbuf));
-       rp->rc_proc = proc;
+       rp->rc_xid = nd->nd_retxid;
+       saddr = mtod(nam, struct sockaddr_in *);
+       switch (saddr->sin_family) {
+       case AF_INET:
+               rp->rc_flag |= RC_INETADDR;
+               rp->rc_inetaddr = saddr->sin_addr.s_addr;
+               break;
+       case AF_ISO:
+       default:
+               rp->rc_flag |= RC_NAM;
+               rp->rc_nam = m_copym(nam, 0, M_COPYALL, M_WAIT);
+               break;
+       };
+       rp->rc_proc = nd->nd_procnum;
        insque(rp, rh);
        insque(rp, rh);
-       if (mb)
-               m_freem(mb);
+       rp->rc_flag &= ~RC_LOCKED;
+       if (rp->rc_flag & RC_WANTED) {
+               rp->rc_flag &= ~RC_WANTED;
+               wakeup((caddr_t)rp);
+       }
        return (RC_DOIT);
 }
 
 /*
  * Update a request cache entry after the rpc has been done
  */
        return (RC_DOIT);
 }
 
 /*
  * Update a request cache entry after the rpc has been done
  */
-nfsrv_updatecache(nam, xid, proc, repvalid, repstat, repmbuf)
+void
+nfsrv_updatecache(nam, nd, repvalid, repmbuf)
        struct mbuf *nam;
        struct mbuf *nam;
-       u_long xid;
-       int proc;
+       register struct nfsd *nd;
        int repvalid;
        int repvalid;
-       int repstat;
        struct mbuf *repmbuf;
 {
        register struct nfsrvcache *rp;
        register union  rhead *rh;
 
        struct mbuf *repmbuf;
 {
        register struct nfsrvcache *rp;
        register union  rhead *rh;
 
-       rh = &rhead[NFSRCHASH(xid)];
+       if (nd->nd_nqlflag != NQL_NOVAL)
+               return;
+       rh = &rhead[NFSRCHASH(nd->nd_retxid)];
 loop:
        for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
 loop:
        for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
-               if (xid == rp->rc_xid && proc == rp->rc_proc &&
-                   nfs_netaddr_match(nam, &rp->rc_nam)) {
+           if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
+               nfs_netaddr_match(NETFAMILY(rp), &rp->rc_haddr, (union nethostaddr *)0, nam)) {
                        if ((rp->rc_flag & RC_LOCKED) != 0) {
                                rp->rc_flag |= RC_WANTED;
                                (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
                        if ((rp->rc_flag & RC_LOCKED) != 0) {
                                rp->rc_flag |= RC_WANTED;
                                (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
@@ -250,9 +295,9 @@ loop:
                         */
                        if (repvalid) {
                                rp->rc_timestamp = time.tv_sec;
                         */
                        if (repvalid) {
                                rp->rc_timestamp = time.tv_sec;
-                               if (nonidempotent[proc]) {
-                                       if (repliesstatus[proc]) {
-                                               rp->rc_status = repstat;
+                               if (nonidempotent[nd->nd_procnum]) {
+                                       if (repliesstatus[nd->nd_procnum]) {
+                                               rp->rc_status = nd->nd_repstat;
                                                rp->rc_flag |= RC_REPSTATUS;
                                        } else {
                                                rp->rc_reply = m_copym(repmbuf,
                                                rp->rc_flag |= RC_REPSTATUS;
                                        } else {
                                                rp->rc_reply = m_copym(repmbuf,
@@ -272,3 +317,36 @@ loop:
                }
        }
 }
                }
        }
 }
+
+/*
+ * Clean out the cache. Called when the last nfsd terminates.
+ */
+void
+nfsrv_cleancache()
+{
+       register int i;
+       register struct nfsrvcache *rp = nfsrvcache;
+       register struct nfsrvcache *hp = &nfsrvcachehead;
+       register union  rhead *rh = rhead;
+
+       for (i = NFSRCHSZ; --i >= 0; rh++) {
+               rh->rh_head[0] = rh;
+               rh->rh_head[1] = rh;
+       }
+       hp->rc_next = hp->rc_prev = hp;
+       for (i = NFSRVCACHESIZ; i-- > 0; ) {
+               if (rp->rc_flag & RC_REPMBUF)
+                       m_freem(rp->rc_reply);
+               if (rp->rc_flag & RC_NAM)
+                       m_freem(rp->rc_nam);
+               rp->rc_state = RC_UNUSED;
+               rp->rc_flag = 0;
+               rp->rc_forw = rp;
+               rp->rc_back = rp;
+               rp->rc_next = hp->rc_next;
+               hp->rc_next->rc_prev = rp;
+               rp->rc_prev = hp;
+               hp->rc_next = rp;
+               rp++;
+       }
+}
index ee73f89..b8322cf 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_subs.c  7.44 (Berkeley) %G%
+ *     @(#)nfs_subs.c  7.45 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
 #include "namei.h"
 #include "mbuf.h"
 #include "map.h"
 #include "namei.h"
 #include "mbuf.h"
 #include "map.h"
+#include "socket.h"
 
 #include "ufs/ufs/quota.h"
 #include "ufs/ufs/inode.h"
 
 #include "ufs/ufs/quota.h"
 #include "ufs/ufs/inode.h"
+#include "ufs/ufs/ufsmount.h"
 
 #include "rpcv2.h"
 #include "nfsv2.h"
 
 #include "rpcv2.h"
 #include "nfsv2.h"
-#include "nfs.h"
 #include "nfsnode.h"
 #include "nfsnode.h"
-#include "nfsiom.h"
+#include "nfs.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
-#include "nfscompress.h"
+#include "nfsmount.h"
+#include "nqnfs.h"
+#include "nfsrtt.h"
 
 #define TRUE   1
 #define        FALSE   0
 
 #define TRUE   1
 #define        FALSE   0
  */
 u_long nfs_procids[NFS_NPROCS];
 u_long nfs_xdrneg1;
  */
 u_long nfs_procids[NFS_NPROCS];
 u_long nfs_xdrneg1;
-u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied,
-       rpc_mismatch, rpc_auth_unix, rpc_msgaccepted;
+u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
+       rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred,
+       rpc_auth_kerb;
 u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
 u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
+
 /* And other global data */
 /* And other global data */
-static u_long *rpc_uidp = (u_long *)0;
-static u_long nfs_xid = 1;
-static char *rpc_unixauth;
-extern long hostid;
+static u_long nfs_xid = 0;
 enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
 enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
-extern struct map nfsmap[NFS_MSIZ];
 extern struct nfsreq nfsreqh;
 extern struct nfsreq nfsreqh;
-
-/* Function ret types */
-static char *nfs_unixauth();
-
-/*
- * Maximum number of groups passed through to NFS server.
- * According to RFC1057 it should be 16.
- * For release 3.X systems, the maximum value is 8.
- * For some other servers, the maximum value is 10.
- */
-int numgrps = 8;
+extern int nqnfs_piggy[NFS_NPROCS];
+extern struct nfsrtt nfsrtt;
+extern union nqsrvthead nqthead;
+extern union nqsrvthead nqfhead[NQLCHSZ];
+extern time_t nqnfsstarttime;
+extern u_long nqnfs_prog, nqnfs_vers;
+extern int nqsrv_clockskew;
+extern int nqsrv_writeslack;
+extern int nqsrv_maxlease;
 
 /*
  * Create the header for an rpc request packet
 
 /*
  * Create the header for an rpc request packet
- * The function nfs_unixauth() creates a unix style authorization string
- * and returns a ptr to it.
  * The hsiz is the size of the rest of the nfs request header.
  * (just used to decide if a cluster is a good idea)
  * The hsiz is the size of the rest of the nfs request header.
  * (just used to decide if a cluster is a good idea)
- * nb: Note that the prog, vers and procid args are already in xdr byte order
  */
  */
-struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid)
-       u_long prog;
-       u_long vers;
+struct mbuf *
+nfsm_reqh(vp, procid, hsiz, bposp)
+       struct vnode *vp;
        u_long procid;
        u_long procid;
-       struct ucred *cred;
        int hsiz;
        int hsiz;
-       caddr_t *bpos;
-       struct mbuf **mb;
-       u_long *retxid;
+       caddr_t *bposp;
 {
 {
-       register struct mbuf *mreq, *m;
+       register struct mbuf *mb;
        register u_long *tl;
        register u_long *tl;
-       struct mbuf *m1;
-       char *ap;
-       int asiz, siz;
-
-       NFSMGETHDR(mreq);
-       asiz = ((((cred->cr_ngroups - 1) > numgrps) ? numgrps :
-                 (cred->cr_ngroups - 1)) << 2);
-#ifdef FILLINHOST
-       asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED);
-#else
-       asiz += 9*NFSX_UNSIGNED;
-#endif
+       register caddr_t bpos;
+       struct mbuf *mb2;
+       struct nfsmount *nmp;
+       int nqflag;
 
 
-       /* If we need a lot, alloc a cluster ?? */
-       if ((asiz+hsiz+RPC_SIZ) > MHLEN)
-               MCLGET(mreq, M_WAIT);
-       mreq->m_len = NFSMSIZ(mreq);
-       siz = mreq->m_len;
-       m1 = mreq;
+       MGET(mb, M_WAIT, MT_DATA);
+       if (hsiz >= MINCLSIZE)
+               MCLGET(mb, M_WAIT);
+       mb->m_len = 0;
+       bpos = mtod(mb, caddr_t);
+       
        /*
        /*
-        * Alloc enough mbufs
-        * We do it now to avoid all sleeps after the call to nfs_unixauth()
+        * For NQNFS, add lease request.
         */
         */
-       while ((asiz+RPC_SIZ) > siz) {
-               MGET(m, M_WAIT, MT_DATA);
-               m1->m_next = m;
-               m->m_len = MLEN;
-               siz += MLEN;
-               m1 = m;
+       if (vp) {
+               nmp = VFSTONFS(vp->v_mount);
+               if (nmp->nm_flag & NFSMNT_NQNFS) {
+                       nqflag = NQNFS_NEEDLEASE(vp, procid);
+                       if (nqflag) {
+                               nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
+                               *tl++ = txdr_unsigned(nqflag);
+                               *tl = txdr_unsigned(nmp->nm_leaseterm);
+                       } else {
+                               nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+                               *tl = 0;
+                       }
+               }
+       }
+       /* Finally, return values */
+       *bposp = bpos;
+       return (mb);
+}
+
+/*
+ * Build the RPC header and fill in the authorization info.
+ * The authorization string argument is only used when the credentials
+ * come from outside of the kernel.
+ * Returns the head of the mbuf list.
+ */
+struct mbuf *
+nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
+       mrest_len, mbp, xidp)
+       register struct ucred *cr;
+       int nqnfs;
+       int procid;
+       int auth_type;
+       int auth_len;
+       char *auth_str;
+       struct mbuf *mrest;
+       int mrest_len;
+       struct mbuf **mbp;
+       u_long *xidp;
+{
+       register struct mbuf *mb;
+       register u_long *tl;
+       register caddr_t bpos;
+       register int i;
+       struct mbuf *mreq, *mb2;
+       int siz, grpsiz, authsiz;
+
+       authsiz = nfsm_rndup(auth_len);
+       if (auth_type == RPCAUTH_NQNFS)
+               authsiz += 2 * NFSX_UNSIGNED;
+       MGETHDR(mb, M_WAIT, MT_DATA);
+       if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) {
+               MCLGET(mb, M_WAIT);
+       } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) {
+               MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED);
+       } else {
+               MH_ALIGN(mb, 8*NFSX_UNSIGNED);
        }
        }
-       tl = mtod(mreq, u_long *);
-       *tl++ = *retxid = txdr_unsigned(++nfs_xid);
+       mb->m_len = 0;
+       mreq = mb;
+       bpos = mtod(mb, caddr_t);
+
+       /*
+        * First the RPC header.
+        */
+       nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED);
+       if (++nfs_xid == 0)
+               nfs_xid++;
+       *tl++ = *xidp = txdr_unsigned(nfs_xid);
        *tl++ = rpc_call;
        *tl++ = rpc_vers;
        *tl++ = rpc_call;
        *tl++ = rpc_vers;
-       *tl++ = prog;
-       *tl++ = vers;
-       *tl++ = procid;
-
-       /* Now we can call nfs_unixauth() and copy it in */
-       ap = nfs_unixauth(cred);
-       m = mreq;
-       siz = m->m_len-RPC_SIZ;
-       if (asiz <= siz) {
-               bcopy(ap, (caddr_t)tl, asiz);
-               m->m_len = asiz+RPC_SIZ;
+       if (nqnfs) {
+               *tl++ = txdr_unsigned(NQNFS_PROG);
+               *tl++ = txdr_unsigned(NQNFS_VER1);
        } else {
        } else {
-               bcopy(ap, (caddr_t)tl, siz);
-               ap += siz;
-               asiz -= siz;
-               while (asiz > 0) {
-                       siz = (asiz > MLEN) ? MLEN : asiz;
-                       m = m->m_next;
-                       bcopy(ap, mtod(m, caddr_t), siz);
-                       m->m_len = siz;
-                       asiz -= siz;
-                       ap += siz;
-               }
+               *tl++ = txdr_unsigned(NFS_PROG);
+               *tl++ = txdr_unsigned(NFS_VER2);
        }
        }
-       
-       /* Finally, return values */
-       *mb = m;
-       *bpos = mtod(m, caddr_t)+m->m_len;
+       *tl++ = txdr_unsigned(procid);
+
+       /*
+        * And then the authorization cred.
+        */
+       *tl++ = txdr_unsigned(auth_type);
+       *tl = txdr_unsigned(authsiz);
+       switch (auth_type) {
+       case RPCAUTH_UNIX:
+               nfsm_build(tl, u_long *, auth_len);
+               *tl++ = 0;              /* stamp ?? */
+               *tl++ = 0;              /* NULL hostname */
+               *tl++ = txdr_unsigned(cr->cr_uid);
+               *tl++ = txdr_unsigned(cr->cr_groups[0]);
+               grpsiz = (auth_len >> 2) - 5;
+               *tl++ = txdr_unsigned(grpsiz);
+               for (i = 1; i <= grpsiz; i++)
+                       *tl++ = txdr_unsigned(cr->cr_groups[i]);
+               break;
+       case RPCAUTH_NQNFS:
+               nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
+               *tl++ = txdr_unsigned(cr->cr_uid);
+               *tl = txdr_unsigned(auth_len);
+               siz = auth_len;
+               while (siz > 0) {
+                       if (M_TRAILINGSPACE(mb) == 0) {
+                               MGET(mb2, M_WAIT, MT_DATA);
+                               if (siz >= MINCLSIZE)
+                                       MCLGET(mb2, M_WAIT);
+                               mb->m_next = mb2;
+                               mb = mb2;
+                               mb->m_len = 0;
+                               bpos = mtod(mb, caddr_t);
+                       }
+                       i = MIN(siz, M_TRAILINGSPACE(mb));
+                       bcopy(auth_str, bpos, i);
+                       mb->m_len += i;
+                       auth_str += i;
+                       bpos += i;
+                       siz -= i;
+               }
+               if ((siz = nfsm_rndup(auth_len) - auth_len) > 0) {
+                       for (i = 0; i < siz; i++)
+                               *bpos++ = '\0';
+                       mb->m_len += siz;
+               }
+               break;
+       };
+       nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
+       *tl++ = txdr_unsigned(RPCAUTH_NULL);
+       *tl = 0;
+       mb->m_next = mrest;
+       mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len;
+       mreq->m_pkthdr.rcvif = (struct ifnet *)0;
+       *mbp = mb;
        return (mreq);
 }
 
        return (mreq);
 }
 
@@ -242,7 +319,7 @@ nfsm_uiotombuf(uiop, mq, siz, bpos)
 {
        register char *uiocp;
        register struct mbuf *mp, *mp2;
 {
        register char *uiocp;
        register struct mbuf *mp, *mp2;
-       register int xfer, left, len;
+       register int xfer, left, mlen;
        int uiosiz, clflg, rem;
        char *cp;
 
        int uiosiz, clflg, rem;
        char *cp;
 
@@ -251,7 +328,7 @@ nfsm_uiotombuf(uiop, mq, siz, bpos)
        else
                clflg = 0;
        rem = nfsm_rndup(siz)-siz;
        else
                clflg = 0;
        rem = nfsm_rndup(siz)-siz;
-       mp2 = *mq;
+       mp = mp2 = *mq;
        while (siz > 0) {
                if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
                        return (EINVAL);
        while (siz > 0) {
                if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
                        return (EINVAL);
@@ -261,26 +338,29 @@ nfsm_uiotombuf(uiop, mq, siz, bpos)
                        left = siz;
                uiosiz = left;
                while (left > 0) {
                        left = siz;
                uiosiz = left;
                while (left > 0) {
-                       MGET(mp, M_WAIT, MT_DATA);
-                       if (clflg)
-                               MCLGET(mp, M_WAIT);
-                       mp->m_len = NFSMSIZ(mp);
-                       mp2->m_next = mp;
-                       mp2 = mp;
-                       xfer = (left > mp->m_len) ? mp->m_len : left;
+                       mlen = M_TRAILINGSPACE(mp);
+                       if (mlen == 0) {
+                               MGET(mp, M_WAIT, MT_DATA);
+                               if (clflg)
+                                       MCLGET(mp, M_WAIT);
+                               mp->m_len = 0;
+                               mp2->m_next = mp;
+                               mp2 = mp;
+                               mlen = M_TRAILINGSPACE(mp);
+                       }
+                       xfer = (left > mlen) ? mlen : left;
 #ifdef notdef
                        /* Not Yet.. */
                        if (uiop->uio_iov->iov_op != NULL)
                                (*(uiop->uio_iov->iov_op))
 #ifdef notdef
                        /* Not Yet.. */
                        if (uiop->uio_iov->iov_op != NULL)
                                (*(uiop->uio_iov->iov_op))
-                               (uiocp, mtod(mp, caddr_t), xfer);
+                               (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
                        else
 #endif
                        if (uiop->uio_segflg == UIO_SYSSPACE)
                        else
 #endif
                        if (uiop->uio_segflg == UIO_SYSSPACE)
-                               bcopy(uiocp, mtod(mp, caddr_t), xfer);
+                               bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
                        else
                        else
-                               copyin(uiocp, mtod(mp, caddr_t), xfer);
-                       len = mp->m_len;
-                       mp->m_len = xfer;
+                               copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
+                       mp->m_len += xfer;
                        left -= xfer;
                        uiocp += xfer;
                        uiop->uio_offset += xfer;
                        left -= xfer;
                        uiocp += xfer;
                        uiop->uio_offset += xfer;
@@ -296,7 +376,7 @@ nfsm_uiotombuf(uiop, mq, siz, bpos)
                siz -= uiosiz;
        }
        if (rem > 0) {
                siz -= uiosiz;
        }
        if (rem > 0) {
-               if (rem > (len-mp->m_len)) {
+               if (rem > M_TRAILINGSPACE(mp)) {
                        MGET(mp, M_WAIT, MT_DATA);
                        mp->m_len = 0;
                        mp2->m_next = mp;
                        MGET(mp, M_WAIT, MT_DATA);
                        mp->m_len = 0;
                        mp2->m_next = mp;
@@ -316,7 +396,9 @@ nfsm_uiotombuf(uiop, mq, siz, bpos)
  * Help break down an mbuf chain by setting the first siz bytes contiguous
  * pointed to by returned val.
  * If Updateflg == True we can overwrite the first part of the mbuf data
  * Help break down an mbuf chain by setting the first siz bytes contiguous
  * pointed to by returned val.
  * If Updateflg == True we can overwrite the first part of the mbuf data
- * This is used by the macros nfsm_disect and nfsm_disecton for tough
+ * (in this case it can never sleep, so it can be called from interrupt level)
+ * it may however block when Updateflg == False
+ * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
  * cases. (The macros use the vars. dpos and dpos2)
  */
 nfsm_disct(mdp, dposp, siz, left, updateflg, cp2)
  * cases. (The macros use the vars. dpos and dpos2)
  */
 nfsm_disct(mdp, dposp, siz, left, updateflg, cp2)
@@ -329,7 +411,7 @@ nfsm_disct(mdp, dposp, siz, left, updateflg, cp2)
 {
        register struct mbuf *mp, *mp2;
        register int siz2, xfer;
 {
        register struct mbuf *mp, *mp2;
        register int siz2, xfer;
-       register caddr_t tl;
+       register caddr_t p;
 
        mp = *mdp;
        while (left == 0) {
 
        mp = *mdp;
        while (left == 0) {
@@ -357,10 +439,10 @@ nfsm_disct(mdp, dposp, siz, left, updateflg, cp2)
                        mp->m_len -= left;
                        mp = mp2;
                }
                        mp->m_len -= left;
                        mp = mp2;
                }
-               *cp2 = tl = mtod(mp, caddr_t);
-               bcopy(*dposp, tl, left);                /* Copy what was left */
+               *cp2 = p = mtod(mp, caddr_t);
+               bcopy(*dposp, p, left);         /* Copy what was left */
                siz2 = siz-left;
                siz2 = siz-left;
-               tl += left;
+               p += left;
                mp2 = mp->m_next;
                /* Loop around copying up the siz2 bytes */
                while (siz2 > 0) {
                mp2 = mp->m_next;
                /* Loop around copying up the siz2 bytes */
                while (siz2 > 0) {
@@ -368,10 +450,10 @@ nfsm_disct(mdp, dposp, siz, left, updateflg, cp2)
                                return (EBADRPC);
                        xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
                        if (xfer > 0) {
                                return (EBADRPC);
                        xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
                        if (xfer > 0) {
-                               bcopy(mtod(mp2, caddr_t), tl, xfer);
+                               bcopy(mtod(mp2, caddr_t), p, xfer);
                                NFSMADV(mp2, xfer);
                                mp2->m_len -= xfer;
                                NFSMADV(mp2, xfer);
                                mp2->m_len -= xfer;
-                               tl += xfer;
+                               p += xfer;
                                siz2 -= xfer;
                        }
                        if (siz2 > 0)
                                siz2 -= xfer;
                        }
                        if (siz2 > 0)
@@ -426,7 +508,7 @@ nfsm_strtmbuf(mb, bpos, cp, siz)
 
        putsize = 1;
        m2 = *mb;
 
        putsize = 1;
        m2 = *mb;
-       left = NFSMSIZ(m2)-m2->m_len;
+       left = M_TRAILINGSPACE(m2);
        if (left > 0) {
                tl = ((u_long *)(*bpos));
                *tl++ = txdr_unsigned(siz);
        if (left > 0) {
                tl = ((u_long *)(*bpos));
                *tl++ = txdr_unsigned(siz);
@@ -441,7 +523,7 @@ nfsm_strtmbuf(mb, bpos, cp, siz)
                        left = 0;
                }
        }
                        left = 0;
                }
        }
-       /* Loop arround adding mbufs */
+       /* Loop around adding mbufs */
        while (siz > 0) {
                MGET(m1, M_WAIT, MT_DATA);
                if (siz > MLEN)
        while (siz > 0) {
                MGET(m1, M_WAIT, MT_DATA);
                if (siz > MLEN)
@@ -481,14 +563,19 @@ nfsm_strtmbuf(mb, bpos, cp, siz)
 nfs_init()
 {
        register int i;
 nfs_init()
 {
        register int i;
+       union nqsrvthead *lhp;
 
 
+       nfsrtt.pos = 0;
        rpc_vers = txdr_unsigned(RPC_VER2);
        rpc_call = txdr_unsigned(RPC_CALL);
        rpc_reply = txdr_unsigned(RPC_REPLY);
        rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
        rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
        rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
        rpc_vers = txdr_unsigned(RPC_VER2);
        rpc_call = txdr_unsigned(RPC_CALL);
        rpc_reply = txdr_unsigned(RPC_REPLY);
        rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
        rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
        rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
+       rpc_autherr = txdr_unsigned(RPC_AUTHERR);
+       rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED);
        rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
        rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
+       rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS);
        nfs_vers = txdr_unsigned(NFS_VER2);
        nfs_prog = txdr_unsigned(NFS_PROG);
        nfs_true = txdr_unsigned(TRUE);
        nfs_vers = txdr_unsigned(NFS_VER2);
        nfs_prog = txdr_unsigned(NFS_PROG);
        nfs_true = txdr_unsigned(TRUE);
@@ -502,7 +589,24 @@ nfs_init()
        nfs_xdrneg1 = txdr_unsigned(-1);
        nfs_nhinit();                   /* Init the nfsnode table */
        nfsrv_initcache();              /* Init the server request cache */
        nfs_xdrneg1 = txdr_unsigned(-1);
        nfs_nhinit();                   /* Init the nfsnode table */
        nfsrv_initcache();              /* Init the server request cache */
-       rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ);
+
+       /*
+        * Initialize the nqnfs server stuff.
+        */
+       if (nqnfsstarttime == 0) {
+               nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
+                       + nqsrv_clockskew + nqsrv_writeslack;
+               NQLOADNOVRAM(nqnfsstarttime);
+               nqnfs_prog = txdr_unsigned(NQNFS_PROG);
+               nqnfs_vers = txdr_unsigned(NQNFS_VER1);
+               nqthead.th_head[0] = &nqthead;
+               nqthead.th_head[1] = &nqthead;
+               for (i = 0; i < NQLCHSZ; i++) {
+                       lhp = &nqfhead[i];
+                       lhp->th_head[0] = lhp;
+                       lhp->th_head[1] = lhp;
+               }
+       }
 
        /*
         * Initialize reply list and start timer
 
        /*
         * Initialize reply list and start timer
@@ -511,54 +615,6 @@ nfs_init()
        nfs_timer();
 }
 
        nfs_timer();
 }
 
-/*
- * Fill in the rest of the rpc_unixauth and return it
- */
-static char *nfs_unixauth(cr)
-       register struct ucred *cr;
-{
-       register u_long *tl;
-       register int i;
-       int ngr;
-
-       /* Maybe someday there should be a cache of AUTH_SHORT's */
-       if ((tl = rpc_uidp) == NULL) {
-#ifdef FILLINHOST
-               i = nfsm_rndup(hostnamelen)+(25*NFSX_UNSIGNED);
-#else
-               i = 25*NFSX_UNSIGNED;
-#endif
-               MALLOC(tl, u_long *, i, M_TEMP, M_WAITOK);
-               bzero((caddr_t)tl, i);
-               rpc_unixauth = (caddr_t)tl;
-               *tl++ = txdr_unsigned(RPCAUTH_UNIX);
-               tl++;   /* Fill in size later */
-               *tl++ = hostid;
-#ifdef FILLINHOST
-               *tl++ = txdr_unsigned(hostnamelen);
-               i = nfsm_rndup(hostnamelen);
-               bcopy(hostname, (caddr_t)tl, hostnamelen);
-               tl += (i>>2);
-#else
-               *tl++ = 0;
-#endif
-               rpc_uidp = tl;
-       }
-       *tl++ = txdr_unsigned(cr->cr_uid);
-       *tl++ = txdr_unsigned(cr->cr_groups[0]);
-       ngr = ((cr->cr_ngroups - 1) > numgrps) ? numgrps : (cr->cr_ngroups - 1);
-       *tl++ = txdr_unsigned(ngr);
-       for (i = 1; i <= ngr; i++)
-               *tl++ = txdr_unsigned(cr->cr_groups[i]);
-       /* And add the AUTH_NULL */
-       *tl++ = 0;
-       *tl = 0;
-       i = (((caddr_t)tl)-rpc_unixauth)-12;
-       tl = (u_long *)(rpc_unixauth+4);
-       *tl = txdr_unsigned(i);
-       return (rpc_unixauth);
-}
-
 /*
  * Attribute cache routines.
  * nfs_loadattrcache() - loads or updates the cache contents from attributes
 /*
  * Attribute cache routines.
  * nfs_loadattrcache() - loads or updates the cache contents from attributes
@@ -588,22 +644,22 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
        caddr_t dpos, cp2;
        int error = 0;
        struct mbuf *md;
        caddr_t dpos, cp2;
        int error = 0;
        struct mbuf *md;
-       enum vtype type;
-       u_short mode;
+       enum vtype vtyp;
+       u_short vmode;
        long rdev;
        struct timeval mtime;
        struct vnode *nvp;
 
        md = *mdp;
        dpos = *dposp;
        long rdev;
        struct timeval mtime;
        struct vnode *nvp;
 
        md = *mdp;
        dpos = *dposp;
-       t1 = (mtod(md, caddr_t)+md->m_len)-dpos;
+       t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
        if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2))
                return (error);
        fp = (struct nfsv2_fattr *)cp2;
        if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2))
                return (error);
        fp = (struct nfsv2_fattr *)cp2;
-       type = nfstov_type(fp->fa_type);
-       mode = fxdr_unsigned(u_short, fp->fa_mode);
-       if (type == VNON)
-               type = IFTOVT(mode);
+       vtyp = nfstov_type(fp->fa_type);
+       vmode = fxdr_unsigned(u_short, fp->fa_mode);
+       if (vtyp == VNON)
+               vtyp = IFTOVT(vmode);
        rdev = fxdr_unsigned(long, fp->fa_rdev);
        fxdr_time(&fp->fa_mtime, &mtime);
        /*
        rdev = fxdr_unsigned(long, fp->fa_rdev);
        fxdr_time(&fp->fa_mtime, &mtime);
        /*
@@ -615,10 +671,10 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
         */
        np = VTONFS(vp);
        if (vp->v_type == VNON) {
         */
        np = VTONFS(vp);
        if (vp->v_type == VNON) {
-               if (type == VCHR && rdev == 0xffffffff)
-                       vp->v_type = type = VFIFO;
+               if (vtyp == VCHR && rdev == 0xffffffff)
+                       vp->v_type = vtyp = VFIFO;
                else
                else
-                       vp->v_type = type;
+                       vp->v_type = vtyp;
                if (vp->v_type == VFIFO) {
 #ifdef FIFO
                        extern struct vnodeops fifo_nfsv2nodeops;
                if (vp->v_type == VFIFO) {
 #ifdef FIFO
                        extern struct vnodeops fifo_nfsv2nodeops;
@@ -634,7 +690,6 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
                                 * Discard unneeded vnode, but save its nfsnode.
                                 */
                                remque(np);
                                 * Discard unneeded vnode, but save its nfsnode.
                                 */
                                remque(np);
-                               nfs_unlock(vp);
                                nvp->v_data = vp->v_data;
                                vp->v_data = NULL;
                                vp->v_op = &spec_vnodeops;
                                nvp->v_data = vp->v_data;
                                vp->v_data = NULL;
                                vp->v_op = &spec_vnodeops;
@@ -645,15 +700,15 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
                                 */
                                np->n_vnode = nvp;
                                insque(np, nfs_hash(&np->n_fh));
                                 */
                                np->n_vnode = nvp;
                                insque(np, nfs_hash(&np->n_fh));
-                               nfs_lock(nvp);
                                *vpp = vp = nvp;
                        }
                }
                                *vpp = vp = nvp;
                        }
                }
-               np->n_mtime = mtime.tv_sec;
+               if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0)
+                       np->n_mtime = mtime.tv_sec;
        }
        vap = &np->n_vattr;
        }
        vap = &np->n_vattr;
-       vap->va_type = type;
-       vap->va_mode = (mode & 07777);
+       vap->va_type = vtyp;
+       vap->va_mode = (vmode & 07777);
        vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
        vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
        vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
        vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
        vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
        vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
@@ -701,28 +756,34 @@ nfs_getattrcache(vp, vap)
        register struct nfsnode *np;
 
        np = VTONFS(vp);
        register struct nfsnode *np;
 
        np = VTONFS(vp);
-       if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) {
-               nfsstats.attrcache_hits++;
-               bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr));
-               if ((np->n_flag & NMODIFIED) == 0) {
-                       np->n_size = vap->va_size;
-                       vnode_pager_setsize(vp, np->n_size);
-               } else if (np->n_size > vap->va_size)
-                       vap->va_size = np->n_size;
-               return (0);
-       } else {
+       if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
+               if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
+                       nfsstats.attrcache_misses++;
+                       return (ENOENT);
+               }
+       } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO) {
                nfsstats.attrcache_misses++;
                return (ENOENT);
        }
                nfsstats.attrcache_misses++;
                return (ENOENT);
        }
+       nfsstats.attrcache_hits++;
+       bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr));
+       if ((np->n_flag & NMODIFIED) == 0) {
+               np->n_size = vap->va_size;
+               vnode_pager_setsize(vp, np->n_size);
+       } else if (np->n_size > vap->va_size)
+               vap->va_size = np->n_size;
+       return (0);
 }
 
 /*
 }
 
 /*
- * Set up nameidata for a namei() call and do it
+ * Set up nameidata for a lookup() call and do it
  */
  */
-nfs_namei(ndp, fhp, len, mdp, dposp, p)
+nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
        register struct nameidata *ndp;
        fhandle_t *fhp;
        int len;
        register struct nameidata *ndp;
        fhandle_t *fhp;
        int len;
+       struct nfssvc_sock *slp;
+       struct mbuf *nam;
        struct mbuf **mdp;
        caddr_t *dposp;
        struct proc *p;
        struct mbuf **mdp;
        caddr_t *dposp;
        struct proc *p;
@@ -731,8 +792,7 @@ nfs_namei(ndp, fhp, len, mdp, dposp, p)
        register struct mbuf *md;
        register char *fromcp, *tocp;
        struct vnode *dp;
        register struct mbuf *md;
        register char *fromcp, *tocp;
        struct vnode *dp;
-       int flag;
-       int error;
+       int flag, error, rdonly;
 
        flag = ndp->ni_nameiop & OPMASK;
        MALLOC(ndp->ni_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
 
        flag = ndp->ni_nameiop & OPMASK;
        MALLOC(ndp->ni_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
@@ -783,7 +843,7 @@ nfs_namei(ndp, fhp, len, mdp, dposp, p)
        /*
         * Extract and set starting directory.
         */
        /*
         * Extract and set starting directory.
         */
-       if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred))
+       if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred, slp, nam, &rdonly))
                goto out;
        if (dp->v_type != VDIR) {
                vrele(dp);
                goto out;
        if (dp->v_type != VDIR) {
                vrele(dp);
@@ -791,7 +851,10 @@ nfs_namei(ndp, fhp, len, mdp, dposp, p)
                goto out;
        }
        ndp->ni_startdir = dp;
                goto out;
        }
        ndp->ni_startdir = dp;
-       ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE);
+       if (rdonly)
+               ndp->ni_nameiop |= (NOCROSSMOUNT | RDONLY);
+       else
+               ndp->ni_nameiop |= NOCROSSMOUNT;
        /*
         * And call lookup() to do the real work
         */
        /*
         * And call lookup() to do the real work
         */
@@ -826,6 +889,7 @@ out:
  * A fiddled version of m_adj() that ensures null fill to a long
  * boundary and only trims off the back end
  */
  * A fiddled version of m_adj() that ensures null fill to a long
  * boundary and only trims off the back end
  */
+void
 nfsm_adj(mp, len, nul)
        struct mbuf *mp;
        register int len;
 nfsm_adj(mp, len, nul)
        struct mbuf *mp;
        register int len;
@@ -889,230 +953,97 @@ nfsm_adj(mp, len, nul)
  *     - check that it is exported
  *     - get vp by calling VFS_FHTOVP() macro
  *     - if not lockflag unlock it with VOP_UNLOCK()
  *     - check that it is exported
  *     - get vp by calling VFS_FHTOVP() macro
  *     - if not lockflag unlock it with VOP_UNLOCK()
- *     - if cred->cr_uid == 0 set it to m_exroot
+ *     - if cred->cr_uid == 0 or MNT_EXPORTANON set it to neth_anon
  */
  */
-nfsrv_fhtovp(fhp, lockflag, vpp, cred)
+nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
        fhandle_t *fhp;
        int lockflag;
        struct vnode **vpp;
        struct ucred *cred;
        fhandle_t *fhp;
        int lockflag;
        struct vnode **vpp;
        struct ucred *cred;
+       struct nfssvc_sock *slp;
+       struct mbuf *nam;
+       int *rdonlyp;
 {
        register struct mount *mp;
 {
        register struct mount *mp;
+       register struct netaddrhash *np;
+       register struct ufsmount *ump;
+       register struct nfsuid *uidp;
+       struct sockaddr *saddr;
+       int error;
 
 
+       *vpp = (struct vnode *)0;
        if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
                return (ESTALE);
        if ((mp->mnt_flag & MNT_EXPORTED) == 0)
                return (EACCES);
        if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
                return (ESTALE);
        if ((mp->mnt_flag & MNT_EXPORTED) == 0)
                return (EACCES);
-       if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
-               return (ESTALE);
-       if (cred->cr_uid == 0)
-               cred->cr_uid = mp->mnt_exroot;
-       if (!lockflag)
-               VOP_UNLOCK(*vpp);
-       return (0);
-}
 
 
-/*
- * These two functions implement nfs rpc compression.
- * The algorithm is a trivial run length encoding of '\0' bytes. The high
- * order nibble of hex "e" is or'd with the number of zeroes - 2 in four
- * bits. (2 - 17 zeros) Any data byte with a high order nibble of hex "e"
- * is byte stuffed.
- * The compressed data is padded with 0x0 bytes to an even multiple of
- * 4 bytes in length to avoid any weird long pointer alignments.
- * If compression/uncompression is unsuccessful, the original mbuf list
- * is returned.
- * The first four bytes (the XID) are left uncompressed and the fifth
- * byte is set to 0x1 for request and 0x2 for reply.
- * An uncompressed RPC will always have the fifth byte == 0x0.
- */
-struct mbuf *
-nfs_compress(m0)
-       struct mbuf *m0;
-{
-       register u_char ch, nextch;
-       register int i, rlelast;
-       register u_char *ip, *op;
-       register int ileft, oleft, noteof;
-       register struct mbuf *m, *om;
-       struct mbuf **mp, *retm;
-       int olen, clget;
+       /*
+        * Get the export permission structure for this <mp, client> tuple.
+        */
+       ump = VFSTOUFS(mp);
+       if (nam) {
 
 
-       i = rlelast = 0;
-       noteof = 1;
-       m = m0;
-       if (m->m_len < 12)
-               return (m0);
-       if (m->m_pkthdr.len >= MINCLSIZE)
-               clget = 1;
-       else
-               clget = 0;
-       ileft = m->m_len - 9;
-       ip = mtod(m, u_char *);
-       MGETHDR(om, M_WAIT, MT_DATA);
-       if (clget)
-               MCLGET(om, M_WAIT);
-       retm = om;
-       mp = &om->m_next;
-       olen = om->m_len = 5;
-       oleft = M_TRAILINGSPACE(om);
-       op = mtod(om, u_char *);
-       *((u_long *)op) = *((u_long *)ip);
-       ip += 7;
-       op += 4;
-       *op++ = *ip++ + 1;
-       nextch = *ip++;
-       while (noteof) {
-               ch = nextch;
-               if (ileft == 0) {
-                       do {
-                               m = m->m_next;
-                       } while (m && m->m_len == 0);
-                       if (m) {
-                               ileft = m->m_len;
-                               ip = mtod(m, u_char *);
-                       } else {
-                               noteof = 0;
-                               nextch = 0x1;
-                               goto doit;
-                       }
-               }
-               nextch = *ip++;
-               ileft--;
-doit:
-               if (ch == '\0') {
-                       if (++i == NFSC_MAX || nextch != '\0') {
-                               if (i < 2) {
-                                       nfscput('\0');
-                               } else {
-                                       if (rlelast == i) {
-                                               nfscput('\0');
-                                               i--;
-                                       }
-                                       if (NFSCRLE(i) == (nextch & 0xff)) {
-                                               i--;
-                                               if (i < 2) {
-                                                       nfscput('\0');
-                                               } else {
-                                                       nfscput(NFSCRLE(i));
-                                               }
-                                               nfscput('\0');
-                                               rlelast = 0;
-                                       } else {
-                                               nfscput(NFSCRLE(i));
-                                               rlelast = i;
-                                       }
-                               }
-                               i = 0;
-                       }
-               } else {
-                       if ((ch & NFSCRL) == NFSCRL) {
-                               nfscput(ch);
-                       }
-                       nfscput(ch);
-                       i = rlelast = 0;
-               }
-       }
-       if (olen < m0->m_pkthdr.len) {
-               m_freem(m0);
-               if (i = (olen & 0x3)) {
-                       i = 4 - i;
-                       while (i-- > 0) {
-                               nfscput('\0');
-                       }
+               /*
+                * First search for a network match.
+                */
+               np = ump->um_netaddr[NETMASK_HASH];
+               while (np) {
+                   if (nfs_netaddr_match(np->neth_family, &np->neth_haddr,
+                       &np->neth_hmask, nam))
+                       break;
+                       np = np->neth_next;
                }
                }
-               retm->m_pkthdr.len = olen;
-               retm->m_pkthdr.rcvif = (struct ifnet *)0;
-               return (retm);
-       } else {
-               m_freem(retm);
-               return (m0);
-       }
-}
-
-struct mbuf *
-nfs_uncompress(m0)
-       struct mbuf *m0;
-{
-       register u_char cp, nextcp, *ip, *op;
-       register struct mbuf *m, *om;
-       struct mbuf *retm, **mp;
-       int i, j, noteof, clget, ileft, oleft, olen;
 
 
-       m = m0;
-       i = 0;
-       while (m && i < MINCLSIZE) {
-               i += m->m_len;
-               m = m->m_next;
-       }
-       if (i < 6)
-               return (m0);
-       if (i >= MINCLSIZE)
-               clget = 1;
-       else
-               clget = 0;
-       m = m0;
-       MGET(om, M_WAIT, MT_DATA);
-       if (clget)
-               MCLGET(om, M_WAIT);
-       olen = om->m_len = 8;
-       oleft = M_TRAILINGSPACE(om);
-       op = mtod(om, u_char *);
-       retm = om;
-       mp = &om->m_next;
-       if (m->m_len >= 6) {
-               ileft = m->m_len - 6;
-               ip = mtod(m, u_char *);
-               *((u_long *)op) = *((u_long *)ip);
-               bzero(op + 4, 3);
-               ip += 4;
-               op += 7;
-               if (*ip == '\0') {
-                       m_freem(om);
-                       return (m0);
+               /*
+                * If not found, try for an address match.
+                */
+               if (np == (struct netaddrhash *)0) {
+                   saddr = mtod(nam, struct sockaddr *);
+                   np = ump->um_netaddr[NETADDRHASH(saddr)];
+                   while (np) {
+                       if (nfs_netaddr_match(np->neth_family, &np->neth_haddr,
+                           (struct netaddrhash *)0, nam))
+                           break;
+                       np = np->neth_next;
+                   }
                }
                }
-               *op++ = *ip++ - 1;
-               cp = *ip++;
-       } else {
-               ileft = m->m_len;
-               ip = mtod(m, u_char *);
-               nfscget(*op++);
-               nfscget(*op++);
-               nfscget(*op++);
-               nfscget(*op++);
-               bzero(op, 3);
-               op += 3;
-               nfscget(*op);
-               if (*op == '\0') {
-                       m_freem(om);
-                       return (m0);
-               }
-               (*op)--;
-               op++;
-               nfscget(cp);
+       } else
+               np = (struct netaddrhash *)0;
+       if (np == (struct netaddrhash *)0) {
+
+               /*
+                * If no address match, use the default if it exists.
+                */
+               if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0)
+                       return (EACCES);
+               np = &ump->um_defexported;
        }
        }
-       noteof = 1;
-       while (noteof) {
-               if ((cp & NFSCRL) == NFSCRL) {
-                       nfscget(nextcp);
-                       if (cp == nextcp) {
-                               nfscput(cp);
-                               goto readit;
-                       } else {
-                               i = (cp & 0xf) + 2;
-                               for (j = 0; j < i; j++) {
-                                       nfscput('\0');
-                               }
-                               cp = nextcp;
-                       }
-               } else {
-                       nfscput(cp);
-readit:
-                       nfscget(cp);
+
+       /*
+        * Check/setup credentials.
+        */
+       if (np->neth_exflags & MNT_EXKERB) {
+               uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)];
+               while (uidp) {
+                       if (uidp->nu_uid == cred->cr_uid)
+                               break;
+                       uidp = uidp->nu_hnext;
                }
                }
-       }
-       m_freem(m0);
-       if (i = (olen & 0x3))
-               om->m_len -= i;
-       return (retm);
+               if (uidp) {
+                       if (cred->cr_ref != 1)
+                               panic("nsrv fhtovp");
+                       *cred = uidp->nu_cr;
+               } else
+                       return (NQNFS_AUTHERR);
+       } else if (cred->cr_uid == 0 || (np->neth_exflags & MNT_EXPORTANON))
+               *cred = np->neth_anon;
+       if (error = VFS_FHTOVP(mp, &fhp->fh_fid, 0, vpp))
+               return (ESTALE);
+       if (np->neth_exflags & MNT_EXRDONLY)
+               *rdonlyp = 1;
+       else
+               *rdonlyp = 0;
+       if (!lockflag)
+               VOP_UNLOCK(*vpp);
+       return (0);
 }
 }
index e199ee1..95e5f3e 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_syscalls.c      7.26.1.1 (Berkeley) %G%
+ *     @(#)nfs_syscalls.c      7.27 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
 #include "kernel.h"
 #include "file.h"
 #include "stat.h"
 #include "kernel.h"
 #include "file.h"
 #include "stat.h"
-#include "namei.h"
 #include "vnode.h"
 #include "mount.h"
 #include "proc.h"
 #include "vnode.h"
 #include "mount.h"
 #include "proc.h"
+#include "uio.h"
 #include "malloc.h"
 #include "buf.h"
 #include "mbuf.h"
 #include "malloc.h"
 #include "buf.h"
 #include "mbuf.h"
 #include "socketvar.h"
 #include "domain.h"
 #include "protosw.h"
 #include "socketvar.h"
 #include "domain.h"
 #include "protosw.h"
-
-#include "../netinet/in.h"
-#include "../netinet/tcp.h"
-
+#include "namei.h"
+#include "netinet/in.h"
+#include "netinet/tcp.h"
+#ifdef ISO
+#include "netiso/iso.h"
+#endif
+#include "machine/endian.h"
+#include "rpcv2.h"
 #include "nfsv2.h"
 #include "nfs.h"
 #include "nfsrvcache.h"
 #include "nfsv2.h"
 #include "nfs.h"
 #include "nfsrvcache.h"
+#include "nfsmount.h"
+#include "nqnfs.h"
 
 /* Global defs. */
 extern u_long nfs_prog, nfs_vers;
 extern int (*nfsrv_procs[NFS_NPROCS])();
 extern struct buf nfs_bqueue;
 
 /* Global defs. */
 extern u_long nfs_prog, nfs_vers;
 extern int (*nfsrv_procs[NFS_NPROCS])();
 extern struct buf nfs_bqueue;
-extern int nfs_numasync;
 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
-extern int nfs_tcpnodelay;
-struct mbuf *nfs_compress();
+extern int nfs_numasync;
+extern time_t nqnfsstarttime;
+extern struct nfsrv_req nsrvq_head;
+extern struct nfsd nfsd_head;
+extern int nqsrv_writeslack;
+struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
+int nuidhash_max = NFS_MAXUIDHASH;
+static int nfs_numnfsd = 0;
+int nfsd_waiting = 0;
+static int notstarted = 1;
+static int modify_flag = 0;
+void nfsrv_cleancache(), nfsrv_rcv(), nfsrv_wakenfsd(), nfs_sndunlock();
 
 #define        TRUE    1
 #define        FALSE   0
 
 static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
 
 #define        TRUE    1
 #define        FALSE   0
 
 static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
-static int compressreply[NFS_NPROCS] = {
-       FALSE,
-       TRUE,
-       TRUE,
-       FALSE,
-       TRUE,
-       TRUE,
-       FALSE,
-       FALSE,
-       TRUE,
-       TRUE,
-       TRUE,
-       TRUE,
-       TRUE,
-       TRUE,
-       TRUE,
-       TRUE,
-       TRUE,
-       TRUE,
-};
 /*
  * NFS server system calls
  * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
 /*
  * NFS server system calls
  * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
@@ -75,7 +70,6 @@ static int compressreply[NFS_NPROCS] = {
 /*
  * Get file handle system call
  */
 /*
  * Get file handle system call
  */
-/* ARGSUSED */
 getfh(p, uap, retval)
        struct proc *p;
        register struct args {
 getfh(p, uap, retval)
        struct proc *p;
        register struct args {
@@ -112,75 +106,203 @@ getfh(p, uap, retval)
        return (error);
 }
 
        return (error);
 }
 
+static struct nfssvc_sock nfssvc_sockhead;
+
 /*
  * Nfs server psuedo system call for the nfsd's
 /*
  * Nfs server psuedo system call for the nfsd's
- * Never returns unless it fails or gets killed
+ * Based on the flag value it either:
+ * - adds a socket to the selection list
+ * - remains in the kernel as an nfsd
+ * - remains in the kernel as an nfsiod
  */
  */
-/* ARGSUSED */
 nfssvc(p, uap, retval)
        struct proc *p;
        register struct args {
 nfssvc(p, uap, retval)
        struct proc *p;
        register struct args {
-               int s;
-               caddr_t mskval;
-               int msklen;
-               caddr_t mtchval;
-               int mtchlen;
+               int flag;
+               caddr_t argp;
        } *uap;
        int *retval;
 {
        } *uap;
        int *retval;
 {
-       register struct mbuf *m;
-       register int siz;
-       register struct ucred *cr;
+       struct nameidata nd;
        struct file *fp;
        struct file *fp;
-       struct mbuf *mreq, *mrep, *nam, *md;
-       struct mbuf msk, mtch;
-       struct socket *so;
-       caddr_t dpos;
-       int procid, repstat, error, cacherep, wascomp;
-       u_long retxid;
+       struct mbuf *nam;
+       struct nfsd_args nfsdarg;
+       struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs;
+       struct nfsd_cargs ncd;
+       struct nfsd *nfsd;
+       struct nfssvc_sock *slp;
+       struct nfsuid *nuidp, **nuh;
+       struct nfsmount *nmp;
+       int error;
 
        /*
         * Must be super user
         */
        if (error = suser(p->p_ucred, &p->p_acflag))
                return (error);
 
        /*
         * Must be super user
         */
        if (error = suser(p->p_ucred, &p->p_acflag))
                return (error);
-       if (error = getsock(p->p_fd, uap->s, &fp))
-               return (error);
+       if (nfssvc_sockhead.ns_next == NULL) {
+               nfs_udpsock = (struct nfssvc_sock *)
+                   malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
+               bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock));
+               nfs_cltpsock = (struct nfssvc_sock *)
+                   malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
+               bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock));
+               nfssvc_sockhead.ns_next = nfs_udpsock;
+               nfs_udpsock->ns_next = nfs_cltpsock;
+               nfs_cltpsock->ns_next = &nfssvc_sockhead;
+               nfssvc_sockhead.ns_prev = nfs_cltpsock;
+               nfs_cltpsock->ns_prev = nfs_udpsock;
+               nfs_udpsock->ns_prev = &nfssvc_sockhead;
+               nfs_udpsock->ns_lrunext = nfs_udpsock->ns_lruprev =
+                       (struct nfsuid *)nfs_udpsock;
+               nfs_cltpsock->ns_lrunext = nfs_cltpsock->ns_lruprev =
+                       (struct nfsuid *)nfs_cltpsock;
+               nfsd_head.nd_next = nfsd_head.nd_prev = &nfsd_head;
+               nfsd_head.nd_flag = 0;
+       }
+       if (uap->flag & NFSSVC_BIOD)
+               error = nfssvc_iod(p);
+       else if (uap->flag & NFSSVC_MNTD) {
+               if (error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)))
+                       return (error);
+               nd.ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+               nd.ni_segflg = UIO_USERSPACE;
+               nd.ni_dirp = ncd.ncd_dirp;
+               if (error = namei(&nd, p))
+                       return (error);
+               if ((nd.ni_vp->v_flag & VROOT) == 0)
+                       error = EINVAL;
+               nmp = VFSTONFS(nd.ni_vp->v_mount);
+               vput(nd.ni_vp);
+               if (error)
+                       return (error);
+               else if (nmp->nm_flag & NFSMNT_MNTD)
+                       return (0);
+               nmp->nm_flag |= NFSMNT_MNTD;
+               error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag, uap->argp, p);
+       } else if (uap->flag & NFSSVC_ADDSOCK) {
+               if (error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof (nfsdarg)))
+                       return (error);
+               if (error = getsock(p->p_fd, nfsdarg.sock, &fp))
+                       return (error);
+               /*
+                * Get the client address for connected sockets.
+                */
+               if (nfsdarg.name == NULL || nfsdarg.namelen == 0)
+                       nam = (struct mbuf *)0;
+               else if (error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen,
+                       MT_SONAME))
+                       return (error);
+               error = nfssvc_addsock(fp, nam);
+       } else {
+               if (error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)))
+                       return (error);
+               if ((uap->flag & NFSSVC_AUTHIN) && (nfsd = nsd->nsd_nfsd) &&
+                       nfsd->nd_sref == nfsd->nd_slp->ns_sref) {
+                       slp = nfsd->nd_slp;
+                       if (slp->ns_numuids < nuidhash_max) {
+                               slp->ns_numuids++;
+                               nuidp = (struct nfsuid *)
+                                  malloc(sizeof (struct nfsuid), M_NFSUID, M_WAITOK);
+                       } else
+                               nuidp = (struct nfsuid *)0;
+                       if (slp->ns_sref != nfsd->nd_sref) {
+                           if (nuidp)
+                               free((caddr_t)nuidp, M_NFSUID);
+                       } else {
+                           if (nuidp == (struct nfsuid *)0) {
+                               nuidp = slp->ns_lruprev;
+                               remque(nuidp);
+                               if (nuidp->nu_hprev)
+                                       nuidp->nu_hprev->nu_hnext = nuidp->nu_hnext;
+                               if (nuidp->nu_hnext)
+                                       nuidp->nu_hnext->nu_hprev = nuidp->nu_hprev;
+                           }
+                           nuidp->nu_cr = nsd->nsd_cr;
+                           nuidp->nu_cr.cr_ref = 1;
+                           nuidp->nu_uid = nsd->nsd_uid;
+                           insque(nuidp, (struct nfsuid *)slp);
+                           nuh = &slp->ns_uidh[NUIDHASH(nsd->nsd_uid)];
+                           if (nuidp->nu_hnext = *nuh)
+                               nuidp->nu_hnext->nu_hprev = nuidp;
+                           nuidp->nu_hprev = (struct nfsuid *)0;
+                           *nuh = nuidp;
+                       }
+               }
+               if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd))
+                       nfsd->nd_flag |= NFSD_AUTHFAIL;
+               error = nfssvc_nfsd(nsd, uap->argp, p);
+       }
+       if (error == EINTR || error == ERESTART)
+               error = 0;
+       return (error);
+}
+
+/*
+ * Adds a socket to the list for servicing by nfsds.
+ */
+nfssvc_addsock(fp, mynam)
+       struct file *fp;
+       struct mbuf *mynam;
+{
+       register struct mbuf *m;
+       register int siz;
+       register struct nfssvc_sock *slp;
+       register struct socket *so;
+       struct nfssvc_sock *tslp;
+       int error, s;
+
        so = (struct socket *)fp->f_data;
        so = (struct socket *)fp->f_data;
-       if (sosendallatonce(so))
-               siz = NFS_MAXPACKET;
+       tslp = (struct nfssvc_sock *)0;
+       /*
+        * Add it to the list, as required.
+        */
+       if (so->so_proto->pr_protocol == IPPROTO_UDP) {
+               tslp = nfs_udpsock;
+               if (tslp->ns_flag & SLP_VALID) {
+                       m_freem(mynam);
+                       return (EPERM);
+               }
+#ifdef ISO
+       } else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) {
+               tslp = nfs_cltpsock;
+               if (tslp->ns_flag & SLP_VALID) {
+                       m_freem(mynam);
+                       return (EPERM);
+               }
+#endif /* ISO */
+       } else {
+               slp = nfs_cltpsock->ns_next;
+               while (slp != &nfssvc_sockhead) {
+                       if ((slp->ns_flag & SLP_VALID) == 0) {
+                               tslp = slp;
+                               break;
+                       }
+                       slp = slp->ns_next;
+               }
+       }
+       if (so->so_type == SOCK_STREAM)
+               siz = NFS_MAXPACKET + sizeof (u_long);
        else
        else
-               siz = NFS_MAXPACKET + sizeof(u_long);
-       if (error = soreserve(so, siz, siz))
-               goto bad;
-       if (error = sockargs(&nam, uap->mskval, uap->msklen, MT_SONAME))
-               goto bad;
-       bcopy((caddr_t)nam, (caddr_t)&msk, sizeof (struct mbuf));
-       msk.m_data = msk.m_dat;
-       m_freem(nam);
-       if (error = sockargs(&nam, uap->mtchval, uap->mtchlen, MT_SONAME))
-               goto bad;
-       bcopy((caddr_t)nam, (caddr_t)&mtch, sizeof (struct mbuf));
-       mtch.m_data = mtch.m_dat;
-       m_freem(nam);
-
-       /* Copy the cred so others don't see changes */
-       cr = p->p_ucred = crcopy(p->p_ucred);
+               siz = NFS_MAXPACKET;
+       if (error = soreserve(so, siz, siz)) {
+               m_freem(mynam);
+               return (error);
+       }
 
        /*
         * Set protocol specific options { for now TCP only } and
         * reserve some space. For datagram sockets, this can get called
         * repeatedly for the same socket, but that isn't harmful.
         */
 
        /*
         * Set protocol specific options { for now TCP only } and
         * reserve some space. For datagram sockets, this can get called
         * repeatedly for the same socket, but that isn't harmful.
         */
-       if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
+       if (so->so_type == SOCK_STREAM) {
                MGET(m, M_WAIT, MT_SOOPTS);
                *mtod(m, int *) = 1;
                m->m_len = sizeof(int);
                sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
        }
        if (so->so_proto->pr_domain->dom_family == AF_INET &&
                MGET(m, M_WAIT, MT_SOOPTS);
                *mtod(m, int *) = 1;
                m->m_len = sizeof(int);
                sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
        }
        if (so->so_proto->pr_domain->dom_family == AF_INET &&
-           so->so_proto->pr_protocol == IPPROTO_TCP &&
-           nfs_tcpnodelay) {
+           so->so_proto->pr_protocol == IPPROTO_TCP) {
                MGET(m, M_WAIT, MT_SOOPTS);
                *mtod(m, int *) = 1;
                m->m_len = sizeof(int);
                MGET(m, M_WAIT, MT_SOOPTS);
                *mtod(m, int *) = 1;
                m->m_len = sizeof(int);
@@ -190,46 +312,213 @@ nfssvc(p, uap, retval)
        so->so_rcv.sb_timeo = 0;
        so->so_snd.sb_flags &= ~SB_NOINTR;
        so->so_snd.sb_timeo = 0;
        so->so_rcv.sb_timeo = 0;
        so->so_snd.sb_flags &= ~SB_NOINTR;
        so->so_snd.sb_timeo = 0;
+       if (tslp)
+               slp = tslp;
+       else {
+               slp = (struct nfssvc_sock *)
+                       malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
+               bzero((caddr_t)slp, sizeof (struct nfssvc_sock));
+               slp->ns_prev = nfssvc_sockhead.ns_prev;
+               slp->ns_prev->ns_next = slp;
+               slp->ns_next = &nfssvc_sockhead;
+               nfssvc_sockhead.ns_prev = slp;
+               slp->ns_lrunext = slp->ns_lruprev = (struct nfsuid *)slp;
+       }
+       slp->ns_so = so;
+       slp->ns_nam = mynam;
+       fp->f_count++;
+       slp->ns_fp = fp;
+       s = splnet();
+       so->so_upcallarg = (caddr_t)slp;
+       so->so_upcall = nfsrv_rcv;
+       slp->ns_flag = (SLP_VALID | SLP_NEEDQ);
+       nfsd_head.nd_flag |= NFSD_CHECKSLP;
+       nfsrv_wakenfsd(slp);
+       splx(s);
+       return (0);
+}
 
 
+/*
+ * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
+ * until it is killed by a signal.
+ */
+nfssvc_nfsd(nsd, argp, p)
+       struct nfsd_srvargs *nsd;
+       caddr_t argp;
+       struct proc *p;
+{
+       register struct mbuf *m, *nam2;
+       register int siz;
+       register struct nfssvc_sock *slp;
+       register struct socket *so;
+       register int *solockp;
+       struct nfsd *nd = nsd->nsd_nfsd;
+       struct mbuf *mreq, *nam;
+       int error, cacherep, s;
+       int sotype;
+
+       if (nd == (struct nfsd *)0) {
+               nsd->nsd_nfsd = nd = (struct nfsd *)
+                       malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK);
+               bzero((caddr_t)nd, sizeof (struct nfsd));
+               nd->nd_cr.cr_ref = 1;
+               nd->nd_procp = p;
+               s = splnet();
+               insque(nd, &nfsd_head);
+               splx(s);
+               nfs_numnfsd++;
+       }
        /*
        /*
-        * Just loop around doin our stuff until SIGKILL
+        * Loop getting rpc requests until SIGKILL.
         */
        for (;;) {
         */
        for (;;) {
-               if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1,
-                  &nam, &mrep, &md, &dpos, &retxid, &procid, cr,
-                  &msk, &mtch, &wascomp)) {
-                       if (nam)
-                               m_freem(nam);
-                       if (error == EPIPE || error == EINTR ||
-                           error == ERESTART) {
-                               error = 0;
-                               goto bad;
+               if ((nd->nd_flag & NFSD_REQINPROG) == 0) {
+                       s = splnet();
+                       while (nd->nd_slp == (struct nfssvc_sock *)0 &&
+                                (nfsd_head.nd_flag & NFSD_CHECKSLP) == 0) {
+                               nd->nd_flag |= NFSD_WAITING;
+                               nfsd_waiting++;
+                               if (tsleep((caddr_t)nd, PSOCK | PCATCH, "nfsd", 0)) {
+                                       nfsd_waiting--;
+                                       splx(s);
+                                       goto done;
+                               }
+                               nfsd_waiting--;
                        }
                        }
-                       so->so_error = 0;
-                       continue;
-               }
+                       if (nd->nd_slp == (struct nfssvc_sock *)0 &&
+                               (nfsd_head.nd_flag & NFSD_CHECKSLP)) {
+                               slp = nfssvc_sockhead.ns_next;
+                               while (slp != &nfssvc_sockhead) {
+                                   if ((slp->ns_flag & SLP_VALID) &&
+                                       (slp->ns_flag & (SLP_NEEDQ | SLP_DISCONN))) {
+                                           nd->nd_slp = slp;
+                                           nd->nd_sref = slp->ns_sref;
+                                           break;
+                                   }
+                                   slp = slp->ns_next;
+                               }
+                               if (slp == &nfssvc_sockhead)
+                                       nfsd_head.nd_flag &= ~NFSD_CHECKSLP;
+                       }
+                       if ((slp = nd->nd_slp) == (struct nfssvc_sock *)0) {
+                               splx(s);
+                               continue;
+                       }
+                       if (slp->ns_flag & SLP_DISCONN) {
+                               slp->ns_flag &= ~SLP_DISCONN;
+                               (void) nfs_sndlock(&slp->ns_solock,
+                                       (struct nfsreq *)0);
+                               if (nd->nd_sref == slp->ns_sref)
+                                       nfsrv_zapsock(slp, p);
+                               nfs_sndunlock(&slp->ns_solock);
+                               nd->nd_slp = (struct nfssvc_sock *)0;
+                               splx(s);
+                               continue;
+                       }
+                       if (slp->ns_flag & SLP_NEEDQ) {
+                               slp->ns_flag &= ~SLP_NEEDQ;
+                               (void) nfs_sndlock(&slp->ns_solock,
+                                       (struct nfsreq *)0);
+                               if (nd->nd_sref == slp->ns_sref) {
+                                   if (slp->ns_so->so_rcv.sb_cc > 0)
+                                       nfsrv_rcv(slp->ns_so, (caddr_t)slp,
+                                               M_WAIT);
+                                   else if (slp->ns_so->so_type == SOCK_STREAM)
+                                       (void) nfsrv_getstream(slp, M_WAIT);
+                               }
+                               nfs_sndunlock(&slp->ns_solock);
+                       }
+                       error = nfsrv_dorec(slp, nd);
+                       splx(s);
+                       if (error) {
+                               nd->nd_slp = (struct nfssvc_sock *)0;
+                               continue;
+                       }
+                       nd->nd_flag |= NFSD_REQINPROG;
+               } else
+                       slp = nd->nd_slp;
+               so = slp->ns_so;
+               sotype = so->so_type;
 
 
-               if (nam)
-                       cacherep = nfsrv_getcache(nam, retxid, procid, &mreq);
+               /*
+                * Check to see if authorization is needed.
+                */
+               if (nd->nd_flag & NFSD_NEEDAUTH) {
+                       nd->nd_flag &= ~NFSD_NEEDAUTH;
+                       nsd->nsd_uid = nd->nd_cr.cr_uid;
+                       nsd->nsd_haddr =
+                           mtod(slp->ns_nam, struct sockaddr_in *)->sin_addr.s_addr;
+                       nsd->nsd_authlen = nd->nd_authlen;
+                       (void) copyout(nd->nd_authstr, nsd->nsd_authstr,
+                                nd->nd_authlen);
+                       (void) copyout((caddr_t)nsd, argp, sizeof (*nsd));
+                       return (ENEEDAUTH);
+               }
+               if (so->so_proto->pr_flags & PR_CONNREQUIRED)
+                       solockp = &slp->ns_solock;
                else
                else
+                       solockp = (int *)0;
+               nd->nd_repstat = 0;
+               /*
+                * nam == nam2 for connectionless protocols such as UDP
+                * nam2 == NULL for connection based protocols to disable
+                *    recent request caching.
+                */
+               nam2 = nd->nd_nam;
+
+               if (nam2) {
+                       nam = nam2;
+                       cacherep = nfsrv_getcache(nam2, nd, &mreq);
+               } else {
+                       nam = slp->ns_nam;
+                       cacherep = RC_DOIT;
+               }
+
+               /*
+                * Check for just starting up for NQNFS and send
+                * fake "try again later" replies to the NQNFS clients.
+                */
+               if (notstarted && nqnfsstarttime <= time.tv_sec) {
+                       if (modify_flag) {
+                               nqnfsstarttime = time.tv_sec + nqsrv_writeslack;
+                               modify_flag = 0;
+                       } else
+                               notstarted = 0;
+               }
+               if (notstarted) {
+                       if (nd->nd_nqlflag == NQL_NOVAL)
+                               cacherep = RC_DROPIT;
+                       else if (nd->nd_procnum != NFSPROC_WRITE) {
+                               nd->nd_procnum = NFSPROC_NOOP;
+                               nd->nd_repstat = NQNFS_TRYLATER;
+                               cacherep = RC_DOIT;
+                       } else
+                               modify_flag = 1;
+               } else if (nd->nd_flag & NFSD_AUTHFAIL) {
+                       nd->nd_flag &= ~NFSD_AUTHFAIL;
+                       nd->nd_procnum = NFSPROC_NOOP;
+                       nd->nd_repstat = NQNFS_AUTHERR;
                        cacherep = RC_DOIT;
                        cacherep = RC_DOIT;
+               }
+
                switch (cacherep) {
                case RC_DOIT:
                switch (cacherep) {
                case RC_DOIT:
-                       if (error = (*(nfsrv_procs[procid]))(mrep, md, dpos,
-                               cr, retxid, &mreq, &repstat, p)) {
-                               nfsstats.srv_errs++;
-                               if (nam) {
-                                       nfsrv_updatecache(nam, retxid, procid,
-                                               FALSE, repstat, mreq);
-                                       m_freem(nam);
+                       error = (*(nfsrv_procs[nd->nd_procnum]))(nd,
+                               nd->nd_mrep, nd->nd_md, nd->nd_dpos, &nd->nd_cr,
+                               nam, &mreq);
+                       if (error) {
+                               if (nd->nd_procnum != NQNFSPROC_VACATED)
+                                       nfsstats.srv_errs++;
+                               if (nam2) {
+                                       nfsrv_updatecache(nam2, nd, FALSE, mreq);
+                                       m_freem(nam2);
                                }
                                break;
                        }
                                }
                                break;
                        }
-                       nfsstats.srvrpccnt[procid]++;
-                       if (nam)
-                               nfsrv_updatecache(nam, retxid, procid, TRUE,
-                                       repstat, mreq);
-                       mrep = (struct mbuf *)0;
+                       nfsstats.srvrpccnt[nd->nd_procnum]++;
+                       if (nam2)
+                               nfsrv_updatecache(nam2, nd, TRUE, mreq);
+                       nd->nd_mrep = (struct mbuf *)0;
                case RC_REPLY:
                        m = mreq;
                        siz = 0;
                case RC_REPLY:
                        m = mreq;
                        siz = 0;
@@ -241,37 +530,43 @@ nfssvc(p, uap, retval)
                                printf("mbuf siz=%d\n",siz);
                                panic("Bad nfs svc reply");
                        }
                                printf("mbuf siz=%d\n",siz);
                                panic("Bad nfs svc reply");
                        }
-                       mreq->m_pkthdr.len = siz;
-                       mreq->m_pkthdr.rcvif = (struct ifnet *)0;
-                       if (wascomp && compressreply[procid]) {
-                               mreq = nfs_compress(mreq);
-                               siz = mreq->m_pkthdr.len;
-                       }
+                       m = mreq;
+                       m->m_pkthdr.len = siz;
+                       m->m_pkthdr.rcvif = (struct ifnet *)0;
                        /*
                        /*
-                        * For non-atomic protocols, prepend a Sun RPC
+                        * For stream protocols, prepend a Sun RPC
                         * Record Mark.
                         */
                         * Record Mark.
                         */
-                       if (!sosendallatonce(so)) {
-                               M_PREPEND(mreq, sizeof(u_long), M_WAIT);
-                               *mtod(mreq, u_long *) = htonl(0x80000000 | siz);
+                       if (sotype == SOCK_STREAM) {
+                               M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
+                               *mtod(m, u_long *) = htonl(0x80000000 | siz);
                        }
                        }
-                       error = nfs_send(so, nam, mreq, (struct nfsreq *)0);
-                       if (nam)
-                               m_freem(nam);
-                       if (mrep)
-                               m_freem(mrep);
-                       if (error) {
-                               if (error == EPIPE || error == EINTR ||
-                                   error == ERESTART)
-                                       goto bad;
-                               so->so_error = 0;
+                       if (solockp)
+                               (void) nfs_sndlock(solockp, (struct nfsreq *)0);
+                       if (nd->nd_sref == slp->ns_sref)
+                           error = nfs_send(so, nam2, m, (struct nfsreq *)0);
+                       else {
+                           error = EPIPE;
+                           m_freem(m);
                        }
                        }
+                       if (nam2)
+                               MFREE(nam2, m);
+                       if (nd->nd_mrep)
+                               m_freem(nd->nd_mrep);
+                       if (error == EPIPE)
+                               nfsrv_zapsock(slp, p);
+                       if (solockp)
+                               nfs_sndunlock(solockp);
+                       if (error == EINTR || error == ERESTART)
+                               goto done;
                        break;
                case RC_DROPIT:
                        break;
                case RC_DROPIT:
-                       m_freem(mrep);
-                       m_freem(nam);
+                       m_freem(nd->nd_mrep);
+                       m_freem(nam2);
                        break;
                };
                        break;
                };
+               nd->nd_flag &= ~NFSD_REQINPROG;
+               nd->nd_slp = (struct nfssvc_sock *)0;
 #ifdef DIAGNOSTIC
                if (p->p_spare[0])
                        panic("nfssvc: M_NAMEI");
 #ifdef DIAGNOSTIC
                if (p->p_spare[0])
                        panic("nfssvc: M_NAMEI");
@@ -279,31 +574,37 @@ nfssvc(p, uap, retval)
                        panic("nfssvc: STARTSAVE");
 #endif
        }
                        panic("nfssvc: STARTSAVE");
 #endif
        }
-bad:
+done:
+       s = splnet();
+       remque(nd);
+       splx(s);
+       free((caddr_t)nd, M_NFSD);
+       nsd->nsd_nfsd = (struct nfsd *)0;
+       if (--nfs_numnfsd == 0) {
+               slp = nfssvc_sockhead.ns_next;
+               while (slp != &nfssvc_sockhead) {
+                       if (slp->ns_flag & SLP_VALID)
+                               nfsrv_zapsock(slp, p);
+                       slp = slp->ns_next;
+               }
+               nfsrv_cleancache();     /* And clear out server cache */
+       }
        return (error);
 }
 
 /*
        return (error);
 }
 
 /*
- * Nfs pseudo system call for asynchronous i/o daemons.
- * These babies just pretend to be disk interrupt service routines
- * for client nfs. They are mainly here for read ahead/write behind.
- * Never returns unless it fails or gets killed
+ * Asynchronous I/O daemons for client nfs.
+ * These babies just pretend to be disk interrupt service routines.
+ * They are mainly here for read ahead/write behind.
+ * Never returns unless it fails or gets killed.
  */
  */
-/* ARGSUSED */
-async_daemon(p, uap, retval)
+nfssvc_iod(p)
        struct proc *p;
        struct proc *p;
-       struct args *uap;
-       int *retval;
 {
        register struct buf *bp, *dp;
        register int i, myiod;
 {
        register struct buf *bp, *dp;
        register int i, myiod;
-       int error;
+       int error = 0;
 
 
-       /*
-        * Must be super user
-        */
-       if (error = suser(p->p_ucred, &p->p_acflag))
-               return (error);
        /*
         * Assign my position or return error if too many already running
         */
        /*
         * Assign my position or return error if too many already running
         */
@@ -337,7 +638,7 @@ async_daemon(p, uap, retval)
                                dp->b_actl = bp->b_actl;
                                bp->b_actl->b_actf = dp;
                        }
                                dp->b_actl = bp->b_actl;
                                bp->b_actl->b_actf = dp;
                        }
-                       (void) nfs_doio(bp);
+                       (void) nfs_doio(bp, (struct proc *)0);
                }
                if (error) {
                        nfs_asyncdaemon[myiod] = 0;
                }
                if (error) {
                        nfs_asyncdaemon[myiod] = 0;
@@ -346,3 +647,98 @@ async_daemon(p, uap, retval)
                }
        }
 }
                }
        }
 }
+
+/*
+ * Shut down a socket associated with an nfssvc_sock structure.
+ * Should be called with the send lock set, if required.
+ * The trick here is to increment the sref at the start, so that the nfsds
+ * will stop using it and clear ns_flag at the end so that it will not be
+ * reassigned during cleanup.
+ */
+nfsrv_zapsock(slp, p)
+       register struct nfssvc_sock *slp;
+       struct proc *p;
+{
+       register struct nfsuid *nuidp, *onuidp;
+       register int i;
+       struct socket *so;
+       struct file *fp;
+       struct mbuf *m;
+
+       if (fp = slp->ns_fp) {
+               slp->ns_fp = (struct file *)0;
+               slp->ns_sref++;
+               so = slp->ns_so;
+               soshutdown(so, 2);
+               closef(fp, p);
+               if (slp->ns_nam)
+                       MFREE(slp->ns_nam, m);
+               m_freem(slp->ns_raw);
+               m_freem(slp->ns_rec);
+               nuidp = slp->ns_lrunext;
+               while (nuidp != (struct nfsuid *)slp) {
+                       onuidp = nuidp;
+                       nuidp = nuidp->nu_lrunext;
+                       free((caddr_t)onuidp, M_NFSUID);
+               }
+               slp->ns_lrunext = slp->ns_lruprev = (struct nfsuid *)slp;
+               for (i = 0; i < NUIDHASHSIZ; i++)
+                       slp->ns_uidh[i] = (struct nfsuid *)0;
+               slp->ns_flag = 0;
+       }
+}
+
+/*
+ * Get an authorization string for the uid by having the mount_nfs sitting
+ * on this mount point porpous out of the kernel and do it.
+ */
+nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len)
+       register struct nfsmount *nmp;
+       struct nfsreq *rep;
+       struct ucred *cred;
+       int *auth_type;
+       char **auth_str;
+       int *auth_len;
+{
+       int error = 0;
+
+       while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) {
+               nmp->nm_flag |= NFSMNT_WANTAUTH;
+               (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK,
+                       "nfsauth1", 2 * hz);
+               if (error = nfs_sigintr(nmp, rep, rep->r_procp)) {
+                       nmp->nm_flag &= ~NFSMNT_WANTAUTH;
+                       return (error);
+               }
+       }
+       nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH);
+       nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
+       nmp->nm_authuid = cred->cr_uid;
+       wakeup((caddr_t)&nmp->nm_authstr);
+
+       /*
+        * And wait for mount_nfs to do its stuff.
+        */
+       while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) {
+               (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK,
+                       "nfsauth2", 2 * hz);
+               error = nfs_sigintr(nmp, rep, rep->r_procp);
+       }
+       if (nmp->nm_flag & NFSMNT_AUTHERR) {
+               nmp->nm_flag &= ~NFSMNT_AUTHERR;
+               error = EAUTH;
+       }
+       if (error)
+               free((caddr_t)*auth_str, M_TEMP);
+       else {
+               *auth_type = nmp->nm_authtype;
+               *auth_len = nmp->nm_authlen;
+       }
+       nmp->nm_flag &= ~NFSMNT_HASAUTH;
+       nmp->nm_flag |= NFSMNT_WAITAUTH;
+       if (nmp->nm_flag & NFSMNT_WANTAUTH) {
+               nmp->nm_flag &= ~NFSMNT_WANTAUTH;
+               wakeup((caddr_t)&nmp->nm_authtype);
+       }
+       return (error);
+}
index 908527b..1328eef 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_vfsops.c        7.35 (Berkeley) %G%
+ *     @(#)nfs_vfsops.c        7.36 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
 #include "proc.h"
 #include "namei.h"
 #include "vnode.h"
 #include "proc.h"
 #include "namei.h"
 #include "vnode.h"
+#include "kernel.h"
 #include "mount.h"
 #include "buf.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "systm.h"
 
 #include "mount.h"
 #include "buf.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "systm.h"
 
-#include "../net/if.h"
-#include "../net/route.h"
-#include "../netinet/in.h"
+#include "net/if.h"
+#include "net/route.h"
+#include "netinet/in.h"
 
 
+#include "rpcv2.h"
 #include "nfsv2.h"
 #include "nfsv2.h"
+#include "nfsnode.h"
 #include "nfsmount.h"
 #include "nfs.h"
 #include "nfsmount.h"
 #include "nfs.h"
-#include "nfsnode.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 #include "nfsdiskless.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 #include "nfsdiskless.h"
+#include "nqnfs.h"
 
 /*
  * nfs vfs operations.
 
 /*
  * nfs vfs operations.
@@ -51,11 +54,17 @@ struct vfsops nfs_vfsops = {
        nfs_init,
 };
 
        nfs_init,
 };
 
+/*
+ * This structure must be filled in by a primary bootstrap or bootstrap
+ * server for a diskless/dataless machine. It is initialized below just
+ * to ensure that it is allocated to initialized data (.data not .bss).
+ */
+struct nfs_diskless nfs_diskless = { 0 };
+
 static u_char nfs_mntid;
 extern u_long nfs_procids[NFS_NPROCS];
 extern u_long nfs_prog, nfs_vers;
 static u_char nfs_mntid;
 extern u_long nfs_procids[NFS_NPROCS];
 extern u_long nfs_prog, nfs_vers;
-struct nfs_diskless nfs_diskless;
-void nfs_disconnect();
+void nfs_disconnect(), nfsargs_ntoh();
 
 #define TRUE   1
 #define        FALSE   0
 
 #define TRUE   1
 #define        FALSE   0
@@ -87,13 +96,13 @@ nfs_statfs(mp, sbp, p)
        nfsstats.rpccnt[NFSPROC_STATFS]++;
        cred = crget();
        cred->cr_ngroups = 1;
        nfsstats.rpccnt[NFSPROC_STATFS]++;
        cred = crget();
        cred->cr_ngroups = 1;
-       nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH);
+       nfsm_reqhead(vp, NFSPROC_STATFS, NFSX_FH);
        nfsm_fhtom(vp);
        nfsm_fhtom(vp);
-       nfsm_request(vp, NFSPROC_STATFS, p, 0);
-       nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
+       nfsm_request(vp, NFSPROC_STATFS, p, cred);
+       nfsm_dissect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
        sbp->f_type = MOUNT_NFS;
        sbp->f_flags = nmp->nm_flag;
        sbp->f_type = MOUNT_NFS;
        sbp->f_flags = nmp->nm_flag;
-       sbp->f_iosize = fxdr_unsigned(long, sfp->sf_tsize);
+       sbp->f_iosize = NFS_MAXDGRAMDATA;
        sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
        sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
        sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
        sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
        sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
        sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
@@ -105,7 +114,7 @@ nfs_statfs(mp, sbp, p)
                bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
        }
        nfsm_reqdone;
                bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
        }
        nfsm_reqdone;
-       nfs_nput(vp);
+       vrele(vp);
        crfree(cred);
        return (error);
 }
        crfree(cred);
        return (error);
 }
@@ -119,8 +128,8 @@ nfs_statfs(mp, sbp, p)
  *   can talk to the server
  * - If nfs_diskless.mygateway is filled in, use that address as
  *   a default gateway.
  *   can talk to the server
  * - If nfs_diskless.mygateway is filled in, use that address as
  *   a default gateway.
- *   (This is done the 4.3 way with rtioctl() and should be changed)
  * - hand craft the swap nfs vnode hanging off a fake mount point
  * - hand craft the swap nfs vnode hanging off a fake mount point
+ *     if swdevt[0].sw_dev == NODEV
  * - build the rootfs mount point and call mountnfs() to do the rest.
  */
 nfs_mountroot()
  * - build the rootfs mount point and call mountnfs() to do the rest.
  */
 nfs_mountroot()
@@ -132,7 +141,7 @@ nfs_mountroot()
        int error;
 
        /*
        int error;
 
        /*
-        * Do enough of ifconfig(8) so that critical net interface can
+        * Do enough of ifconfig(8) so that the critical net interface can
         * talk to the server.
         */
        if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
         * talk to the server.
         */
        if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
@@ -144,22 +153,20 @@ nfs_mountroot()
        /*
         * If the gateway field is filled in, set it as the default route.
         */
        /*
         * If the gateway field is filled in, set it as the default route.
         */
-#ifdef COMPAT_43
-       if (nfs_diskless.mygateway.sa_family == AF_INET) {
-               struct ortentry rt;
-               struct sockaddr_in *sin;
-
-               sin = (struct sockaddr_in *) &rt.rt_dst;
-               sin->sin_len = sizeof (struct sockaddr_in);
-               sin->sin_family = AF_INET;
-               sin->sin_addr.s_addr = 0;       /* default */
-               bcopy((caddr_t)&nfs_diskless.mygateway, (caddr_t)&rt.rt_gateway,
-                       sizeof (struct sockaddr_in));
-               rt.rt_flags = (RTF_UP | RTF_GATEWAY);
-               if (rtioctl(SIOCADDRT, (caddr_t)&rt))
+       if (nfs_diskless.mygateway.sin_len != 0) {
+               struct sockaddr_in sin;
+               extern struct sockaddr_in icmpmask;
+
+               sin.sin_len = sizeof (struct sockaddr_in);
+               sin.sin_family = AF_INET;
+               sin.sin_addr.s_addr = 0;        /* default */
+               in_sockmaskof(sin.sin_addr, &icmpmask);
+               if (rtrequest(RTM_ADD, (struct sockaddr *)&sin,
+                       (struct sockaddr *)&nfs_diskless.mygateway,
+                       (struct sockaddr *)&icmpmask,
+                       RTF_UP | RTF_GATEWAY, (struct rtentry **)0))
                        panic("nfs root route");
        }
                        panic("nfs root route");
        }
-#endif /* COMPAT_43 */
 
        /*
         * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
 
        /*
         * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
@@ -173,7 +180,6 @@ nfs_mountroot()
                        panic("nfs root mount");
                mp->mnt_op = &nfs_vfsops;
                mp->mnt_flag = 0;
                        panic("nfs root mount");
                mp->mnt_op = &nfs_vfsops;
                mp->mnt_flag = 0;
-               mp->mnt_exroot = 0;
                mp->mnt_mounth = NULLVP;
        
                /*
                mp->mnt_mounth = NULLVP;
        
                /*
@@ -187,8 +193,9 @@ nfs_mountroot()
                if (m == NULL)
                        panic("nfs root mbuf");
                bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t),
                if (m == NULL)
                        panic("nfs root mbuf");
                bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t),
-                       nfs_diskless.swap_saddr.sa_len);
-               m->m_len = nfs_diskless.swap_saddr.sa_len;
+                       nfs_diskless.swap_saddr.sin_len);
+               m->m_len = (int)nfs_diskless.swap_saddr.sin_len;
+               nfsargs_ntoh(&nfs_diskless.swap_args);
                if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap",
                        nfs_diskless.swap_hostnam, &vp))
                        panic("nfs swap");
                if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap",
                        nfs_diskless.swap_hostnam, &vp))
                        panic("nfs swap");
@@ -197,6 +204,7 @@ nfs_mountroot()
                swapdev_vp = vp;
                VREF(vp);
                swdevt[0].sw_vp = vp;
                swapdev_vp = vp;
                VREF(vp);
                swdevt[0].sw_vp = vp;
+               swdevt[0].sw_nblks = ntohl(nfs_diskless.swap_nblks);
        }
 
        /*
        }
 
        /*
@@ -208,7 +216,6 @@ nfs_mountroot()
                panic("nfs root mount2");
        mp->mnt_op = &nfs_vfsops;
        mp->mnt_flag = MNT_RDONLY;
                panic("nfs root mount2");
        mp->mnt_op = &nfs_vfsops;
        mp->mnt_flag = MNT_RDONLY;
-       mp->mnt_exroot = 0;
        mp->mnt_mounth = NULLVP;
 
        /*
        mp->mnt_mounth = NULLVP;
 
        /*
@@ -219,8 +226,9 @@ nfs_mountroot()
        if (m == NULL)
                panic("nfs root mbuf2");
        bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t),
        if (m == NULL)
                panic("nfs root mbuf2");
        bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t),
-               nfs_diskless.root_saddr.sa_len);
-       m->m_len = nfs_diskless.root_saddr.sa_len;
+               nfs_diskless.root_saddr.sin_len);
+       m->m_len = (int)nfs_diskless.root_saddr.sin_len;
+       nfsargs_ntoh(&nfs_diskless.root_args);
        if (mountnfs(&nfs_diskless.root_args, mp, m, "/",
                nfs_diskless.root_hostnam, &vp))
                panic("nfs root");
        if (mountnfs(&nfs_diskless.root_args, mp, m, "/",
                nfs_diskless.root_hostnam, &vp))
                panic("nfs root");
@@ -236,6 +244,28 @@ nfs_mountroot()
        return (0);
 }
 
        return (0);
 }
 
+/*
+ * Convert the integer fields of the nfs_args structure from net byte order
+ * to host byte order. Called by nfs_mountroot() above.
+ */
+void
+nfsargs_ntoh(nfsp)
+       register struct nfs_args *nfsp;
+{
+
+       NTOHL(nfsp->sotype);
+       NTOHL(nfsp->proto);
+       NTOHL(nfsp->flags);
+       NTOHL(nfsp->wsize);
+       NTOHL(nfsp->rsize);
+       NTOHL(nfsp->timeo);
+       NTOHL(nfsp->retrans);
+       NTOHL(nfsp->maxgrouplist);
+       NTOHL(nfsp->readahead);
+       NTOHL(nfsp->leaseterm);
+       NTOHL(nfsp->deadthresh);
+}
+
 /*
  * VFS Operations.
  *
 /*
  * VFS Operations.
  *
@@ -275,7 +305,7 @@ nfs_mount(mp, path, data, ndp, p)
        bzero(&hst[len], MNAMELEN - len);
        /* sockargs() call must be after above copyin() calls */
        if (error = sockargs(&nam, (caddr_t)args.addr,
        bzero(&hst[len], MNAMELEN - len);
        /* sockargs() call must be after above copyin() calls */
        if (error = sockargs(&nam, (caddr_t)args.addr,
-               sizeof (struct sockaddr), MT_SONAME))
+               args.addrlen, MT_SONAME))
                return (error);
        args.fh = &nfh;
        error = mountnfs(&args, mp, nam, pth, hst, &vp);
                return (error);
        args.fh = &nfh;
        error = mountnfs(&args, mp, nam, pth, hst, &vp);
@@ -293,13 +323,13 @@ mountnfs(argp, mp, nam, pth, hst, vpp)
        struct vnode **vpp;
 {
        register struct nfsmount *nmp;
        struct vnode **vpp;
 {
        register struct nfsmount *nmp;
-       struct proc *p = curproc;               /* XXX */
        struct nfsnode *np;
        int error;
        fsid_t tfsid;
 
        struct nfsnode *np;
        int error;
        fsid_t tfsid;
 
-       MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK);
-       bzero((caddr_t)nmp, sizeof *nmp);
+       MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount), M_NFSMNT,
+               M_WAITOK);
+       bzero((caddr_t)nmp, sizeof (struct nfsmount));
        mp->mnt_data = (qaddr_t)nmp;
        /*
         * Generate a unique nfs mount id. The problem is that a dev number
        mp->mnt_data = (qaddr_t)nmp;
        /*
         * Generate a unique nfs mount id. The problem is that a dev number
@@ -332,12 +362,27 @@ mountnfs(argp, mp, nam, pth, hst, vpp)
        mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
        nmp->nm_mountp = mp;
        nmp->nm_flag = argp->flags;
        mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
        nmp->nm_mountp = mp;
        nmp->nm_flag = argp->flags;
-       nmp->nm_rto = NFS_TIMEO;
-       nmp->nm_rtt = -1;
-       nmp->nm_rttvar = nmp->nm_rto << 1;
+       if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) ==
+               (NFSMNT_NQNFS | NFSMNT_MYWRITE)) {
+               error = EPERM;
+               goto bad;
+       }
+       if ((nmp->nm_flag & (NFSMNT_RDIRALOOK | NFSMNT_LEASETERM)) &&
+           (nmp->nm_flag & NFSMNT_NQNFS) == 0) {
+               error = EPERM;
+               goto bad;
+       }
+       nmp->nm_timeo = NFS_TIMEO;
        nmp->nm_retry = NFS_RETRANS;
        nmp->nm_wsize = NFS_WSIZE;
        nmp->nm_rsize = NFS_RSIZE;
        nmp->nm_retry = NFS_RETRANS;
        nmp->nm_wsize = NFS_WSIZE;
        nmp->nm_rsize = NFS_RSIZE;
+       nmp->nm_numgrps = NFS_MAXGRPS;
+       nmp->nm_readahead = NFS_DEFRAHEAD;
+       nmp->nm_leaseterm = NQ_DEFLEASE;
+       nmp->nm_deadthresh = NQ_DEADTHRESH;
+       nmp->nm_tnext = (struct nfsnode *)nmp;
+       nmp->nm_tprev = (struct nfsnode *)nmp;
+       nmp->nm_inprog = NULLVP;
        bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
        mp->mnt_stat.f_type = MOUNT_NFS;
        bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
        bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
        mp->mnt_stat.f_type = MOUNT_NFS;
        bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
@@ -345,14 +390,11 @@ mountnfs(argp, mp, nam, pth, hst, vpp)
        nmp->nm_nam = nam;
 
        if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
        nmp->nm_nam = nam;
 
        if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
-               nmp->nm_rto = argp->timeo;
-               /* NFS timeouts are specified in 1/10 sec. */
-               nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ;
-               if (nmp->nm_rto < NFS_MINTIMEO)
-                       nmp->nm_rto = NFS_MINTIMEO;
-               else if (nmp->nm_rto > NFS_MAXTIMEO)
-                       nmp->nm_rto = NFS_MAXTIMEO;
-               nmp->nm_rttvar = nmp->nm_rto << 1;
+               nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
+               if (nmp->nm_timeo < NFS_MINTIMEO)
+                       nmp->nm_timeo = NFS_MINTIMEO;
+               else if (nmp->nm_timeo > NFS_MAXTIMEO)
+                       nmp->nm_timeo = NFS_MAXTIMEO;
        }
 
        if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
        }
 
        if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
@@ -384,14 +426,37 @@ mountnfs(argp, mp, nam, pth, hst, vpp)
        }
        if (nmp->nm_rsize > MAXBSIZE)
                nmp->nm_rsize = MAXBSIZE;
        }
        if (nmp->nm_rsize > MAXBSIZE)
                nmp->nm_rsize = MAXBSIZE;
+       if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
+               argp->maxgrouplist <= NFS_MAXGRPS)
+               nmp->nm_numgrps = argp->maxgrouplist;
+       if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
+               argp->readahead <= NFS_MAXRAHEAD)
+               nmp->nm_readahead = argp->readahead;
+       if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
+               argp->leaseterm <= NQ_MAXLEASE)
+               nmp->nm_leaseterm = argp->leaseterm;
+       if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
+               argp->deadthresh <= NQ_NEVERDEAD)
+               nmp->nm_deadthresh = argp->deadthresh;
        /* Set up the sockets and per-host congestion */
        nmp->nm_sotype = argp->sotype;
        nmp->nm_soproto = argp->proto;
        /* Set up the sockets and per-host congestion */
        nmp->nm_sotype = argp->sotype;
        nmp->nm_soproto = argp->proto;
-       if (error = nfs_connect(nmp))
-               goto bad;
 
 
-       if (error = nfs_statfs(mp, &mp->mnt_stat, p))
+       /*
+        * For Connection based sockets (TCP,...) defer the connect until
+        * the first request, in case the server is not responding.
+        */
+       if (nmp->nm_sotype == SOCK_DGRAM &&
+               (error = nfs_connect(nmp, (struct nfsreq *)0)))
                goto bad;
                goto bad;
+
+       /*
+        * This is silly, but it has to be set so that vinifod() works.
+        * We do not want to do an nfs_statfs() here since we can get
+        * stuck on a dead server and we are holding a lock on the mount
+        * point.
+        */
+       mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
        /*
         * A reference count is needed on the nfsnode representing the
         * remote root.  If this object is not persistent, then backward
        /*
         * A reference count is needed on the nfsnode representing the
         * remote root.  If this object is not persistent, then backward
@@ -402,16 +467,12 @@ mountnfs(argp, mp, nam, pth, hst, vpp)
         */
        if (error = nfs_nget(mp, &nmp->nm_fh, &np))
                goto bad;
         */
        if (error = nfs_nget(mp, &nmp->nm_fh, &np))
                goto bad;
-       /*
-        * Unlock it, but keep the reference count.
-        */
-       nfs_unlock(NFSTOV(np));
        *vpp = NFSTOV(np);
 
        return (0);
 bad:
        nfs_disconnect(nmp);
        *vpp = NFSTOV(np);
 
        return (0);
 bad:
        nfs_disconnect(nmp);
-       FREE(nmp, M_NFSMNT);
+       free((caddr_t)nmp, M_NFSMNT);
        m_freem(nam);
        return (error);
 }
        m_freem(nam);
        return (error);
 }
@@ -463,18 +524,36 @@ nfs_unmount(mp, mntflags, p)
                vput(vp);
                return (EBUSY);
        }
                vput(vp);
                return (EBUSY);
        }
+
+       /*
+        * Must handshake with nqnfs_clientd() if it is active.
+        */
+       nmp->nm_flag |= NFSMNT_DISMINPROG;
+       while (nmp->nm_inprog != NULLVP)
+               (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
        if (error = vflush(mp, vp, flags)) {
                vput(vp);
        if (error = vflush(mp, vp, flags)) {
                vput(vp);
+               nmp->nm_flag &= ~NFSMNT_DISMINPROG;
                return (error);
        }
                return (error);
        }
+
+       /*
+        * We are now committed to the unmount.
+        * For NQNFS, let the server daemon free the nfsmount structure.
+        */
+       if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
+               nmp->nm_flag |= NFSMNT_DISMNT;
+
        /*
        /*
-        * Get rid of two reference counts, and unlock it on the second.
+        * There are two reference counts to get rid of here.
         */
        vrele(vp);
         */
        vrele(vp);
-       vput(vp);
+       vrele(vp);
        nfs_disconnect(nmp);
        m_freem(nmp->nm_nam);
        nfs_disconnect(nmp);
        m_freem(nmp->nm_nam);
-       free((caddr_t)nmp, M_NFSMNT);
+
+       if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
+               free((caddr_t)nmp, M_NFSMNT);
        return (0);
 }
 
        return (0);
 }
 
@@ -523,9 +602,10 @@ nfs_sync(mp, waitfor)
  * At this point, this should never happen
  */
 /* ARGSUSED */
  * At this point, this should never happen
  */
 /* ARGSUSED */
-nfs_fhtovp(mp, fhp, vpp)
+nfs_fhtovp(mp, fhp, setgen, vpp)
        struct mount *mp;
        struct fid *fhp;
        struct mount *mp;
        struct fid *fhp;
+       int setgen;
        struct vnode **vpp;
 {
 
        struct vnode **vpp;
 {
 
index 5d421a0..42c29db 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_vnops.c 7.64 (Berkeley) %G%
+ *     @(#)nfs_vnops.c 7.65 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
 #include "ufs/ufs/inode.h"
 #include "ufs/ufs/dir.h"
 
 #include "ufs/ufs/inode.h"
 #include "ufs/ufs/dir.h"
 
+#include "rpcv2.h"
 #include "nfsv2.h"
 #include "nfs.h"
 #include "nfsnode.h"
 #include "nfsmount.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 #include "nfsv2.h"
 #include "nfs.h"
 #include "nfsnode.h"
 #include "nfsmount.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
-#include "nfsiom.h"
+#include "nqnfs.h"
 
 /* Defs */
 #define        TRUE    1
 
 /* Defs */
 #define        TRUE    1
@@ -183,32 +184,30 @@ struct vnodeops fifo_nfsv2nodeops = {
 #endif /* FIFO */
 
 /*
 #endif /* FIFO */
 
 /*
- * Global vars
+ * Global variables
  */
 extern u_long nfs_procids[NFS_NPROCS];
 extern u_long nfs_prog, nfs_vers;
 extern char nfsiobuf[MAXPHYS+NBPG];
  */
 extern u_long nfs_procids[NFS_NPROCS];
 extern u_long nfs_prog, nfs_vers;
 extern char nfsiobuf[MAXPHYS+NBPG];
-struct map nfsmap[NFS_MSIZ];
 struct buf nfs_bqueue;         /* Queue head for nfsiod's */
 struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
 int nfs_numasync = 0;
 struct buf nfs_bqueue;         /* Queue head for nfsiod's */
 struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
 int nfs_numasync = 0;
-static int nfsmap_want = 0;
+#define        DIRHDSIZ        (sizeof (struct direct) - (MAXNAMLEN + 1))
 
 /*
  * nfs null call from vfs.
  */
 
 /*
  * nfs null call from vfs.
  */
-nfs_null(vp, cred, p)
+nfs_null(vp, cred, procp)
        struct vnode *vp;
        struct ucred *cred;
        struct vnode *vp;
        struct ucred *cred;
-       struct proc *p;
+       struct proc *procp;
 {
        caddr_t bpos, dpos;
 {
        caddr_t bpos, dpos;
-       u_long xid;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb;
        
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb;
        
-       nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0);
-       nfsm_request(vp, NFSPROC_NULL, p, 0);
+       nfsm_reqhead(vp, NFSPROC_NULL, 0);
+       nfsm_request(vp, NFSPROC_NULL, procp, cred);
        nfsm_reqdone;
        return (error);
 }
        nfsm_reqdone;
        return (error);
 }
@@ -217,11 +216,11 @@ nfs_null(vp, cred, p)
  * nfs access vnode op.
  * Essentially just get vattr and then imitate iaccess()
  */
  * nfs access vnode op.
  * Essentially just get vattr and then imitate iaccess()
  */
-nfs_access(vp, mode, cred, p)
+nfs_access(vp, mode, cred, procp)
        struct vnode *vp;
        int mode;
        register struct ucred *cred;
        struct vnode *vp;
        int mode;
        register struct ucred *cred;
-       struct proc *p;
+       struct proc *procp;
 {
        register struct vattr *vap;
        register gid_t *gp;
 {
        register struct vattr *vap;
        register gid_t *gp;
@@ -236,7 +235,7 @@ nfs_access(vp, mode, cred, p)
        if (cred->cr_uid == 0)
                return (0);
        vap = &vattr;
        if (cred->cr_uid == 0)
                return (0);
        vap = &vattr;
-       if (error = nfs_dogetattr(vp, vap, cred, 0, p))
+       if (error = nfs_getattr(vp, vap, cred, procp))
                return (error);
        /*
         * Access check is based on only one of owner, group, public.
                return (error);
        /*
         * Access check is based on only one of owner, group, public.
@@ -261,21 +260,21 @@ found:
 /*
  * nfs open vnode op
  * Just check to see if the type is ok
 /*
  * nfs open vnode op
  * Just check to see if the type is ok
+ * and that deletion is not in progress.
  */
 /* ARGSUSED */
  */
 /* ARGSUSED */
-nfs_open(vp, mode, cred, p)
-       struct vnode *vp;
+nfs_open(vp, mode, cred, procp)
+       register struct vnode *vp;
        int mode;
        struct ucred *cred;
        int mode;
        struct ucred *cred;
-       struct proc *p;
+       struct proc *procp;
 {
 {
-       register enum vtype vtyp;
 
 
-       vtyp = vp->v_type;
-       if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK)
-               return (0);
-       else
+       if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
                return (EACCES);
                return (EACCES);
+       if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0)
+               VTONFS(vp)->n_attrstamp = 0; /* For Open/Close consistency */
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -283,17 +282,18 @@ nfs_open(vp, mode, cred, p)
  * For reg files, invalidate any buffer cache entries.
  */
 /* ARGSUSED */
  * For reg files, invalidate any buffer cache entries.
  */
 /* ARGSUSED */
-nfs_close(vp, fflags, cred, p)
+nfs_close(vp, fflags, cred, procp)
        register struct vnode *vp;
        int fflags;
        struct ucred *cred;
        register struct vnode *vp;
        int fflags;
        struct ucred *cred;
-       struct proc *p;
+       struct proc *procp;
 {
        register struct nfsnode *np = VTONFS(vp);
        int error = 0;
 
 {
        register struct nfsnode *np = VTONFS(vp);
        int error = 0;
 
-       if (vp->v_type == VREG && (np->n_flag & NMODIFIED)) {
-               nfs_lock(vp);
+       if ((np->n_flag & NMODIFIED) &&
+           (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
+           vp->v_type == VREG) {
                np->n_flag &= ~NMODIFIED;
                vinvalbuf(vp, TRUE);
                np->n_attrstamp = 0;
                np->n_flag &= ~NMODIFIED;
                vinvalbuf(vp, TRUE);
                np->n_attrstamp = 0;
@@ -301,7 +301,6 @@ nfs_close(vp, fflags, cred, p)
                        np->n_flag &= ~NWRITEERR;
                        error = np->n_error;
                }
                        np->n_flag &= ~NWRITEERR;
                        error = np->n_error;
                }
-               nfs_unlock(vp);
        }
        return (error);
 }
        }
        return (error);
 }
@@ -309,26 +308,14 @@ nfs_close(vp, fflags, cred, p)
 /*
  * nfs getattr call from vfs.
  */
 /*
  * nfs getattr call from vfs.
  */
-nfs_getattr(vp, vap, cred, p)
+nfs_getattr(vp, vap, cred, procp)
        register struct vnode *vp;
        struct vattr *vap;
        struct ucred *cred;
        register struct vnode *vp;
        struct vattr *vap;
        struct ucred *cred;
-       struct proc *p;
-{
-       return (nfs_dogetattr(vp, vap, cred, 0, p));
-}
-
-nfs_dogetattr(vp, vap, cred, tryhard, p)
-       register struct vnode *vp;
-       struct vattr *vap;
-       struct ucred *cred;
-       int tryhard;
-       struct proc *p;
+       struct proc *procp;
 {
        register caddr_t cp;
 {
        register caddr_t cp;
-       register long t1;
        caddr_t bpos, dpos;
        caddr_t bpos, dpos;
-       u_long xid;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        
@@ -336,9 +323,9 @@ nfs_dogetattr(vp, vap, cred, tryhard, p)
        if (nfs_getattrcache(vp, vap) == 0)
                return (0);
        nfsstats.rpccnt[NFSPROC_GETATTR]++;
        if (nfs_getattrcache(vp, vap) == 0)
                return (0);
        nfsstats.rpccnt[NFSPROC_GETATTR]++;
-       nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH);
+       nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
        nfsm_fhtom(vp);
        nfsm_fhtom(vp);
-       nfsm_request(vp, NFSPROC_GETATTR, p, tryhard);
+       nfsm_request(vp, NFSPROC_GETATTR, procp, cred);
        nfsm_loadattr(vp, vap);
        nfsm_reqdone;
        return (error);
        nfsm_loadattr(vp, vap);
        nfsm_reqdone;
        return (error);
@@ -347,23 +334,24 @@ nfs_dogetattr(vp, vap, cred, tryhard, p)
 /*
  * nfs setattr call.
  */
 /*
  * nfs setattr call.
  */
-nfs_setattr(vp, vap, cred, p)
+nfs_setattr(vp, vap, cred, procp)
        register struct vnode *vp;
        register struct vattr *vap;
        struct ucred *cred;
        register struct vnode *vp;
        register struct vattr *vap;
        struct ucred *cred;
-       struct proc *p;
+       struct proc *procp;
 {
        register struct nfsv2_sattr *sp;
        register caddr_t cp;
        register long t1;
 {
        register struct nfsv2_sattr *sp;
        register caddr_t cp;
        register long t1;
-       caddr_t bpos, dpos;
-       u_long xid;
+       caddr_t bpos, dpos, cp2;
+       u_long *tl;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
-       struct nfsnode *np;
+       struct nfsnode *np = VTONFS(vp);
+       u_quad_t frev;
 
        nfsstats.rpccnt[NFSPROC_SETATTR]++;
 
        nfsstats.rpccnt[NFSPROC_SETATTR]++;
-       nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR);
+       nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR);
        nfsm_fhtom(vp);
        nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
        if (vap->va_mode == 0xffff)
        nfsm_fhtom(vp);
        nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
        if (vap->va_mode == 0xffff)
@@ -384,19 +372,23 @@ nfs_setattr(vp, vap, cred, p)
        txdr_time(&vap->va_mtime, &sp->sa_mtime);
        if (vap->va_size != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
            vap->va_atime.tv_sec != VNOVAL) {
        txdr_time(&vap->va_mtime, &sp->sa_mtime);
        if (vap->va_size != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
            vap->va_atime.tv_sec != VNOVAL) {
-               np = VTONFS(vp);
                if (np->n_flag & NMODIFIED) {
                        np->n_flag &= ~NMODIFIED;
                        if (vap->va_size == 0)
                                vinvalbuf(vp, FALSE);
                        else
                                vinvalbuf(vp, TRUE);
                if (np->n_flag & NMODIFIED) {
                        np->n_flag &= ~NMODIFIED;
                        if (vap->va_size == 0)
                                vinvalbuf(vp, FALSE);
                        else
                                vinvalbuf(vp, TRUE);
-                       np->n_attrstamp = 0;
                }
        }
                }
        }
-       nfsm_request(vp, NFSPROC_SETATTR, p, 1);
+       nfsm_request(vp, NFSPROC_SETATTR, procp, cred);
        nfsm_loadattr(vp, (struct vattr *)0);
        nfsm_loadattr(vp, (struct vattr *)0);
-       /* should we fill in any vap fields ?? */
+       if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
+           NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
+               nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
+               fxdr_hyper(tl, &frev);
+               if (QUADGT(frev, np->n_brev))
+                       np->n_brev = frev;
+       }
        nfsm_reqdone;
        return (error);
 }
        nfsm_reqdone;
        return (error);
 }
@@ -406,23 +398,27 @@ nfs_setattr(vp, vap, cred, p)
  * First look in cache
  * If not found, unlock the directory nfsnode and do the rpc
  */
  * First look in cache
  * If not found, unlock the directory nfsnode and do the rpc
  */
-nfs_lookup(vp, ndp, p)
+nfs_lookup(vp, ndp, procp)
        register struct vnode *vp;
        register struct nameidata *ndp;
        register struct vnode *vp;
        register struct nameidata *ndp;
-       struct proc *p;
+       struct proc *procp;
 {
        register struct vnode *vdp;
        register u_long *tl;
        register caddr_t cp;
        register long t1, t2;
 {
        register struct vnode *vdp;
        register u_long *tl;
        register caddr_t cp;
        register long t1, t2;
+       struct nfsmount *nmp;
+       struct nfsnode *tp;
        caddr_t bpos, dpos, cp2;
        caddr_t bpos, dpos, cp2;
-       u_long xid;
+       time_t reqtime;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct vnode *newvp;
        long len;
        nfsv2fh_t *fhp;
        struct nfsnode *np;
        int lockparent, wantparent, flag, error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct vnode *newvp;
        long len;
        nfsv2fh_t *fhp;
        struct nfsnode *np;
        int lockparent, wantparent, flag, error = 0;
+       int nqlflag, cachable;
+       u_quad_t frev;
 
        ndp->ni_dvp = vp;
        ndp->ni_vp = NULL;
 
        ndp->ni_dvp = vp;
        ndp->ni_vp = NULL;
@@ -431,6 +427,8 @@ nfs_lookup(vp, ndp, p)
        lockparent = ndp->ni_nameiop & LOCKPARENT;
        flag = ndp->ni_nameiop & OPMASK;
        wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
        lockparent = ndp->ni_nameiop & LOCKPARENT;
        flag = ndp->ni_nameiop & OPMASK;
        wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
+       nmp = VFSTONFS(vp->v_mount);
+       np = VTONFS(vp);
        if ((error = cache_lookup(ndp)) && error != ENOENT) {
                struct vattr vattr;
                int vpid;
        if ((error = cache_lookup(ndp)) && error != ENOENT) {
                struct vattr vattr;
                int vpid;
@@ -444,154 +442,172 @@ nfs_lookup(vp, ndp, p)
                if (vp == vdp) {
                        VREF(vdp);
                        error = 0;
                if (vp == vdp) {
                        VREF(vdp);
                        error = 0;
-               } else if (ndp->ni_isdotdot) {
-                       nfs_unlock(vp);
-                       error = vget(vdp);
-                       if (!error && lockparent && *ndp->ni_next == '\0')
-                               nfs_lock(vp);
-               } else {
+               } else
                        error = vget(vdp);
                        error = vget(vdp);
-                       if (!lockparent || error || *ndp->ni_next != '\0')
-                               nfs_unlock(vp);
-               }
                if (!error) {
                        if (vpid == vdp->v_id) {
                if (!error) {
                        if (vpid == vdp->v_id) {
-                          if (!nfs_dogetattr(vdp, &vattr, ndp->ni_cred, 0, p)&&
+                          if (nmp->nm_flag & NFSMNT_NQNFS) {
+                               if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
+                                       if (QUADNE(np->n_lrev, np->n_brev) ||
+                                           (np->n_flag & NMODIFIED)) {
+                                               np->n_direofoffset = 0;
+                                               cache_purge(vp);
+                                               np->n_flag &= ~NMODIFIED;
+                                               vinvalbuf(vp, FALSE);
+                                               np->n_brev = np->n_lrev;
+                                       } else {
+                                               nfsstats.lookupcache_hits++;
+                                               if (flag != LOOKUP &&
+                                                   *ndp->ni_next == '\0')
+                                                   ndp->ni_nameiop |= SAVENAME;
+                                               return (0);
+                                       }
+                               }
+                          } else if (!nfs_getattr(vdp, &vattr, ndp->ni_cred, procp) &&
                               vattr.va_ctime.tv_sec == VTONFS(vdp)->n_ctime) {
                                nfsstats.lookupcache_hits++;
                               vattr.va_ctime.tv_sec == VTONFS(vdp)->n_ctime) {
                                nfsstats.lookupcache_hits++;
-                               if (flag != LOOKUP && *ndp->ni_next == 0)
+                               if (flag != LOOKUP && *ndp->ni_next == '\0')
                                        ndp->ni_nameiop |= SAVENAME;
                                return (0);
                           }
                           cache_purge(vdp);
                        }
                                        ndp->ni_nameiop |= SAVENAME;
                                return (0);
                           }
                           cache_purge(vdp);
                        }
-                       nfs_nput(vdp);
-                       if (lockparent && vdp != vp && *ndp->ni_next == '\0')
-                               nfs_unlock(vp);
+                       vrele(vdp);
                }
                ndp->ni_vp = NULLVP;
                }
                ndp->ni_vp = NULLVP;
-       } else
-               nfs_unlock(vp);
+       }
        error = 0;
        nfsstats.lookupcache_misses++;
        nfsstats.rpccnt[NFSPROC_LOOKUP]++;
        len = ndp->ni_namelen;
        error = 0;
        nfsstats.lookupcache_misses++;
        nfsstats.rpccnt[NFSPROC_LOOKUP]++;
        len = ndp->ni_namelen;
-       nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
+       nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
+
+       /*
+        * For nqnfs optionally piggyback a getlease request for the name
+        * being looked up.
+        */
+       if (nmp->nm_flag & NFSMNT_NQNFS) {
+               if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
+                   (ndp->ni_makeentry && (flag != DELETE || *ndp->ni_next))) {
+                       nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
+                       *tl++ = txdr_unsigned(NQL_READ);
+                       *tl = txdr_unsigned(nmp->nm_leaseterm);
+               } else {
+                       nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+                       *tl = 0;
+               }
+       }
        nfsm_fhtom(vp);
        nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
        nfsm_fhtom(vp);
        nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
-       nfsm_request(vp, NFSPROC_LOOKUP, p, 0);
+       reqtime = time.tv_sec;
+       nfsm_request(vp, NFSPROC_LOOKUP, procp, ndp->ni_cred);
 nfsmout:
        if (error) {
 nfsmout:
        if (error) {
-               if (lockparent || (flag != CREATE && flag != RENAME) ||
-                   *ndp->ni_next != 0)
-                       nfs_lock(vp);
-               if (flag != LOOKUP && *ndp->ni_next == 0)
+               if (flag != LOOKUP && *ndp->ni_next == '\0')
                        ndp->ni_nameiop |= SAVENAME;
                return (error);
        }
                        ndp->ni_nameiop |= SAVENAME;
                return (error);
        }
-       nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH);
+       if (nmp->nm_flag & NFSMNT_NQNFS) {
+               nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+               if (*tl) {
+                       nqlflag = fxdr_unsigned(int, *tl);
+                       nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
+                       cachable = fxdr_unsigned(int, *tl++);
+                       reqtime += fxdr_unsigned(int, *tl++);
+                       fxdr_hyper(tl, &frev);
+               } else
+                       nqlflag = 0;
+       }
+       nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
 
        /*
 
        /*
-        * Handle DELETE and RENAME cases...
+        * Handle RENAME case...
         */
         */
-       if (flag == DELETE && *ndp->ni_next == 0) {
-               if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
-                       VREF(vp);
-                       newvp = vp;
-                       np = VTONFS(vp);
-               } else {
-                       if (error = nfs_nget(vp->v_mount, fhp, &np)) {
-                               nfs_lock(vp);
-                               m_freem(mrep);
-                               return (error);
-                       }
-                       newvp = NFSTOV(np);
-               }
-               if (error =
-                   nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
-                       nfs_lock(vp);
-                       if (newvp != vp)
-                               nfs_nput(newvp);
-                       else
-                               vrele(vp);
-                       m_freem(mrep);
-                       return (error);
-               }
-               ndp->ni_vp = newvp;
-               if (lockparent || vp == newvp)
-                       nfs_lock(vp);
-               m_freem(mrep);
-               ndp->ni_nameiop |= SAVENAME;
-               return (0);
-       }
-
        if (flag == RENAME && wantparent && *ndp->ni_next == 0) {
        if (flag == RENAME && wantparent && *ndp->ni_next == 0) {
-               if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
-                       nfs_lock(vp);
+               if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
                        m_freem(mrep);
                        return (EISDIR);
                }
                if (error = nfs_nget(vp->v_mount, fhp, &np)) {
                        m_freem(mrep);
                        return (EISDIR);
                }
                if (error = nfs_nget(vp->v_mount, fhp, &np)) {
-                       nfs_lock(vp);
                        m_freem(mrep);
                        return (error);
                }
                newvp = NFSTOV(np);
                if (error =
                    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
                        m_freem(mrep);
                        return (error);
                }
                newvp = NFSTOV(np);
                if (error =
                    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
-                       nfs_lock(vp);
-                       nfs_nput(newvp);
+                       vrele(newvp);
                        m_freem(mrep);
                        return (error);
                }
                ndp->ni_vp = newvp;
                        m_freem(mrep);
                        return (error);
                }
                ndp->ni_vp = newvp;
-               if (lockparent)
-                       nfs_lock(vp);
                m_freem(mrep);
                ndp->ni_nameiop |= SAVENAME;
                return (0);
        }
 
                m_freem(mrep);
                ndp->ni_nameiop |= SAVENAME;
                return (0);
        }
 
-       if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
+       if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
                VREF(vp);
                newvp = vp;
                VREF(vp);
                newvp = vp;
-               np = VTONFS(vp);
-       } else if (ndp->ni_isdotdot) {
-               if (error = nfs_nget(vp->v_mount, fhp, &np)) {
-                       nfs_lock(vp);
-                       m_freem(mrep);
-                       return (error);
-               }
-               newvp = NFSTOV(np);
        } else {
                if (error = nfs_nget(vp->v_mount, fhp, &np)) {
        } else {
                if (error = nfs_nget(vp->v_mount, fhp, &np)) {
-                       nfs_lock(vp);
                        m_freem(mrep);
                        return (error);
                }
                newvp = NFSTOV(np);
        }
        if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
                        m_freem(mrep);
                        return (error);
                }
                newvp = NFSTOV(np);
        }
        if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
-               nfs_lock(vp);
-               if (newvp != vp)
-                       nfs_nput(newvp);
-               else
-                       vrele(vp);
+               vrele(newvp);
                m_freem(mrep);
                return (error);
        }
        m_freem(mrep);
                m_freem(mrep);
                return (error);
        }
        m_freem(mrep);
-
-       if (vp == newvp || (lockparent && *ndp->ni_next == '\0'))
-               nfs_lock(vp);
        ndp->ni_vp = newvp;
        ndp->ni_vp = newvp;
-       if (flag != LOOKUP && *ndp->ni_next == 0)
+       if (flag != LOOKUP && *ndp->ni_next == '\0')
                ndp->ni_nameiop |= SAVENAME;
                ndp->ni_nameiop |= SAVENAME;
-       if (error == 0 && ndp->ni_makeentry) {
-               np->n_ctime = np->n_vattr.va_ctime.tv_sec;
+       if (ndp->ni_makeentry && (flag != DELETE || *ndp->ni_next)) {
+               if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
+                       np->n_ctime = np->n_vattr.va_ctime.tv_sec;
+               else if (nqlflag && reqtime > time.tv_sec) {
+                       if (np->n_tnext) {
+                               if (np->n_tnext == (struct nfsnode *)nmp)
+                                       nmp->nm_tprev = np->n_tprev;
+                               else
+                                       np->n_tnext->n_tprev = np->n_tprev;
+                               if (np->n_tprev == (struct nfsnode *)nmp)
+                                       nmp->nm_tnext = np->n_tnext;
+                               else
+                                       np->n_tprev->n_tnext = np->n_tnext;
+                               if (nqlflag == NQL_WRITE)
+                                       np->n_flag |= NQNFSWRITE;
+                       } else if (nqlflag == NQL_READ)
+                               np->n_flag &= ~NQNFSWRITE;
+                       else
+                               np->n_flag |= NQNFSWRITE;
+                       if (cachable)
+                               np->n_flag &= ~NQNFSNONCACHE;
+                       else
+                               np->n_flag |= NQNFSNONCACHE;
+                       np->n_expiry = reqtime;
+                       np->n_lrev = frev;
+                       tp = nmp->nm_tprev;
+                       while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry)
+                               tp = tp->n_tprev;
+                       if (tp == (struct nfsnode *)nmp) {
+                               np->n_tnext = nmp->nm_tnext;
+                               nmp->nm_tnext = np;
+                       } else {
+                               np->n_tnext = tp->n_tnext;
+                               tp->n_tnext = np;
+                       }
+                       np->n_tprev = tp;
+                       if (np->n_tnext == (struct nfsnode *)nmp)
+                               nmp->nm_tprev = np;
+                       else
+                               np->n_tnext->n_tprev = np;
+               }
                cache_enter(ndp);
        }
                cache_enter(ndp);
        }
-       return (error);
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -635,15 +651,14 @@ nfs_readlinkrpc(vp, uiop, cred)
        register caddr_t cp;
        register long t1;
        caddr_t bpos, dpos, cp2;
        register caddr_t cp;
        register long t1;
        caddr_t bpos, dpos, cp2;
-       u_long xid;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        long len;
 
        nfsstats.rpccnt[NFSPROC_READLINK]++;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        long len;
 
        nfsstats.rpccnt[NFSPROC_READLINK]++;
-       nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH);
+       nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
        nfsm_fhtom(vp);
        nfsm_fhtom(vp);
-       nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, 0);
+       nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
        nfsm_strsiz(len, NFS_MAXPATHLEN);
        nfsm_mtouio(uiop, len);
        nfsm_reqdone;
        nfsm_strsiz(len, NFS_MAXPATHLEN);
        nfsm_mtouio(uiop, len);
        nfsm_reqdone;
@@ -663,7 +678,6 @@ nfs_readrpc(vp, uiop, cred)
        register caddr_t cp;
        register long t1;
        caddr_t bpos, dpos, cp2;
        register caddr_t cp;
        register long t1;
        caddr_t bpos, dpos, cp2;
-       u_long xid;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct nfsmount *nmp;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct nfsmount *nmp;
@@ -674,13 +688,13 @@ nfs_readrpc(vp, uiop, cred)
        while (tsiz > 0) {
                nfsstats.rpccnt[NFSPROC_READ]++;
                len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
        while (tsiz > 0) {
                nfsstats.rpccnt[NFSPROC_READ]++;
                len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
-               nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3);
+               nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
                nfsm_fhtom(vp);
                nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
                *tl++ = txdr_unsigned(uiop->uio_offset);
                *tl++ = txdr_unsigned(len);
                *tl = 0;
                nfsm_fhtom(vp);
                nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
                *tl++ = txdr_unsigned(uiop->uio_offset);
                *tl++ = txdr_unsigned(len);
                *tl = 0;
-               nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, 1);
+               nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
                nfsm_loadattr(vp, (struct vattr *)0);
                nfsm_strsiz(retlen, nmp->nm_rsize);
                nfsm_mtouio(uiop, retlen);
                nfsm_loadattr(vp, (struct vattr *)0);
                nfsm_strsiz(retlen, nmp->nm_rsize);
                nfsm_mtouio(uiop, retlen);
@@ -705,11 +719,12 @@ nfs_writerpc(vp, uiop, cred)
        register u_long *tl;
        register caddr_t cp;
        register long t1;
        register u_long *tl;
        register caddr_t cp;
        register long t1;
-       caddr_t bpos, dpos;
-       u_long xid;
+       caddr_t bpos, dpos, cp2;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct nfsmount *nmp;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct nfsmount *nmp;
+       struct nfsnode *np = VTONFS(vp);
+       u_quad_t frev;
        long len, tsiz;
 
        nmp = VFSTONFS(vp->v_mount);
        long len, tsiz;
 
        nmp = VFSTONFS(vp->v_mount);
@@ -717,19 +732,30 @@ nfs_writerpc(vp, uiop, cred)
        while (tsiz > 0) {
                nfsstats.rpccnt[NFSPROC_WRITE]++;
                len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
        while (tsiz > 0) {
                nfsstats.rpccnt[NFSPROC_WRITE]++;
                len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
-               nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred,
-                       NFSX_FH+NFSX_UNSIGNED*4);
+               nfsm_reqhead(vp, NFSPROC_WRITE,
+                       NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
                nfsm_fhtom(vp);
                nfsm_build(tl, u_long *, NFSX_UNSIGNED*4);
                *(tl+1) = txdr_unsigned(uiop->uio_offset);
                *(tl+3) = txdr_unsigned(len);
                nfsm_uiotom(uiop, len);
                nfsm_fhtom(vp);
                nfsm_build(tl, u_long *, NFSX_UNSIGNED*4);
                *(tl+1) = txdr_unsigned(uiop->uio_offset);
                *(tl+3) = txdr_unsigned(len);
                nfsm_uiotom(uiop, len);
-               nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, 1);
+               nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
                nfsm_loadattr(vp, (struct vattr *)0);
                nfsm_loadattr(vp, (struct vattr *)0);
+               if (nmp->nm_flag & NFSMNT_MYWRITE)
+                       VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec;
+               else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
+                        NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
+                       nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
+                       fxdr_hyper(tl, &frev);
+                       if (QUADGT(frev, np->n_brev))
+                               np->n_brev = frev;
+               }
                m_freem(mrep);
                tsiz -= len;
        }
 nfsmout:
                m_freem(mrep);
                tsiz -= len;
        }
 nfsmout:
+       if (error)
+               uiop->uio_resid = tsiz;
        return (error);
 }
 
        return (error);
 }
 
@@ -739,18 +765,17 @@ nfsmout:
  * set to specify the file type and the size field for rdev.
  */
 /* ARGSUSED */
  * set to specify the file type and the size field for rdev.
  */
 /* ARGSUSED */
-nfs_mknod(ndp, vap, cred, p)
+nfs_mknod(ndp, vap, cred, procp)
        struct nameidata *ndp;
        struct ucred *cred;
        register struct vattr *vap;
        struct nameidata *ndp;
        struct ucred *cred;
        register struct vattr *vap;
-       struct proc *p;
+       struct proc *procp;
 {
        register struct nfsv2_sattr *sp;
        register u_long *tl;
        register caddr_t cp;
 {
        register struct nfsv2_sattr *sp;
        register u_long *tl;
        register caddr_t cp;
-       register long t1, t2;
+       register long t2;
        caddr_t bpos, dpos;
        caddr_t bpos, dpos;
-       u_long xid;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        u_long rdev;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        u_long rdev;
@@ -767,7 +792,7 @@ nfs_mknod(ndp, vap, cred, p)
                return (EOPNOTSUPP);
        }
        nfsstats.rpccnt[NFSPROC_CREATE]++;
                return (EOPNOTSUPP);
        }
        nfsstats.rpccnt[NFSPROC_CREATE]++;
-       nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred,
+       nfsm_reqhead(ndp->ni_dvp, NFSPROC_CREATE,
          NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_SATTR);
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
          NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_SATTR);
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
@@ -779,33 +804,32 @@ nfs_mknod(ndp, vap, cred, p)
        /* or should these be VNOVAL ?? */
        txdr_time(&vap->va_atime, &sp->sa_atime);
        txdr_time(&vap->va_mtime, &sp->sa_mtime);
        /* or should these be VNOVAL ?? */
        txdr_time(&vap->va_atime, &sp->sa_atime);
        txdr_time(&vap->va_mtime, &sp->sa_mtime);
-       nfsm_request(ndp->ni_dvp, NFSPROC_CREATE, p, 1);
+       nfsm_request(ndp->ni_dvp, NFSPROC_CREATE, procp, cred);
        nfsm_reqdone;
        FREE(ndp->ni_pnbuf, M_NAMEI);
        VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
        nfsm_reqdone;
        FREE(ndp->ni_pnbuf, M_NAMEI);
        VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
-       nfs_nput(ndp->ni_dvp);
+       vrele(ndp->ni_dvp);
        return (error);
 }
 
 /*
  * nfs file create call
  */
        return (error);
 }
 
 /*
  * nfs file create call
  */
-nfs_create(ndp, vap, p)
+nfs_create(ndp, vap, procp)
        register struct nameidata *ndp;
        register struct vattr *vap;
        register struct nameidata *ndp;
        register struct vattr *vap;
-       struct proc *p;
+       struct proc *procp;
 {
        register struct nfsv2_sattr *sp;
        register u_long *tl;
        register caddr_t cp;
        register long t1, t2;
        caddr_t bpos, dpos, cp2;
 {
        register struct nfsv2_sattr *sp;
        register u_long *tl;
        register caddr_t cp;
        register long t1, t2;
        caddr_t bpos, dpos, cp2;
-       u_long xid;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_CREATE]++;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_CREATE]++;
-       nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred,
+       nfsm_reqhead(ndp->ni_dvp, NFSPROC_CREATE,
          NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_SATTR);
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
          NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_SATTR);
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
@@ -817,12 +841,12 @@ nfs_create(ndp, vap, p)
        /* or should these be VNOVAL ?? */
        txdr_time(&vap->va_atime, &sp->sa_atime);
        txdr_time(&vap->va_mtime, &sp->sa_mtime);
        /* or should these be VNOVAL ?? */
        txdr_time(&vap->va_atime, &sp->sa_atime);
        txdr_time(&vap->va_mtime, &sp->sa_mtime);
-       nfsm_request(ndp->ni_dvp, NFSPROC_CREATE, p, 1);
+       nfsm_request(ndp->ni_dvp, NFSPROC_CREATE, procp, ndp->ni_cred);
        nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
        nfsm_reqdone;
        FREE(ndp->ni_pnbuf, M_NAMEI);
        VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
        nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
        nfsm_reqdone;
        FREE(ndp->ni_pnbuf, M_NAMEI);
        VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
-       nfs_nput(ndp->ni_dvp);
+       vrele(ndp->ni_dvp);
        return (error);
 }
 
        return (error);
 }
 
@@ -837,30 +861,43 @@ nfs_create(ndp, vap, p)
  *     else
  *       do the remove rpc
  */
  *     else
  *       do the remove rpc
  */
-nfs_remove(ndp, p)
+nfs_remove(ndp, procp)
        register struct nameidata *ndp;
        register struct nameidata *ndp;
-       struct proc *p;
+       struct proc *procp;
 {
        register struct vnode *vp = ndp->ni_vp;
        register struct nfsnode *np = VTONFS(ndp->ni_vp);
        register u_long *tl;
        register caddr_t cp;
 {
        register struct vnode *vp = ndp->ni_vp;
        register struct nfsnode *np = VTONFS(ndp->ni_vp);
        register u_long *tl;
        register caddr_t cp;
-       register long t1, t2;
+       register long t2;
        caddr_t bpos, dpos;
        caddr_t bpos, dpos;
-       u_long xid;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        if (vp->v_usecount > 1) {
                if (!np->n_sillyrename)
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        if (vp->v_usecount > 1) {
                if (!np->n_sillyrename)
-                       error = nfs_sillyrename(ndp, p);
+                       error = nfs_sillyrename(ndp, procp);
        } else {
        } else {
+               /*
+                * Purge the name cache so that the chance of a lookup for
+                * the name succeeding while the remove is in progress is
+                * minimized. Without node locking it can still happen, such
+                * that an I/O op returns ESTALE, but since you get this if
+                * another host removes the file..
+                */
+               cache_purge(vp);
+               /*
+                * Throw away biocache buffers. Mainly to avoid
+                * unnecessary delayed writes.
+                */
+               vinvalbuf(vp, FALSE);
+               /* Do the rpc */
                nfsstats.rpccnt[NFSPROC_REMOVE]++;
                nfsstats.rpccnt[NFSPROC_REMOVE]++;
-               nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
+               nfsm_reqhead(ndp->ni_dvp, NFSPROC_REMOVE,
                        NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen));
                nfsm_fhtom(ndp->ni_dvp);
                nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
                        NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen));
                nfsm_fhtom(ndp->ni_dvp);
                nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
-               nfsm_request(ndp->ni_dvp, NFSPROC_REMOVE, p, 1);
+               nfsm_request(ndp->ni_dvp, NFSPROC_REMOVE, procp, ndp->ni_cred);
                nfsm_reqdone;
                FREE(ndp->ni_pnbuf, M_NAMEI);
                VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
                nfsm_reqdone;
                FREE(ndp->ni_pnbuf, M_NAMEI);
                VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
@@ -874,35 +911,31 @@ nfs_remove(ndp, p)
                        error = 0;
        }
        np->n_attrstamp = 0;
                        error = 0;
        }
        np->n_attrstamp = 0;
-       if (ndp->ni_dvp == vp)
-               vrele(vp);
-       else
-               nfs_nput(ndp->ni_dvp);
-       nfs_nput(vp);
+       vrele(ndp->ni_dvp);
+       vrele(vp);
        return (error);
 }
 
 /*
  * nfs file remove rpc called from nfs_inactive
  */
        return (error);
 }
 
 /*
  * nfs file remove rpc called from nfs_inactive
  */
-nfs_removeit(sp, p)
+nfs_removeit(sp, procp)
        register struct sillyrename *sp;
        register struct sillyrename *sp;
-       struct proc *p;
+       struct proc *procp;
 {
        register u_long *tl;
        register caddr_t cp;
 {
        register u_long *tl;
        register caddr_t cp;
-       register long t1, t2;
+       register long t2;
        caddr_t bpos, dpos;
        caddr_t bpos, dpos;
-       u_long xid;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_REMOVE]++;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_REMOVE]++;
-       nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], sp->s_cred,
+       nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
                NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
        nfsm_fhtom(sp->s_dvp);
        nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
                NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
        nfsm_fhtom(sp->s_dvp);
        nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
-       nfsm_request(sp->s_dvp, NFSPROC_REMOVE, p, 1);
+       nfsm_request(sp->s_dvp, NFSPROC_REMOVE, procp, sp->s_cred);
        nfsm_reqdone;
        VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
        return (error);
        nfsm_reqdone;
        VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
        return (error);
@@ -911,27 +944,26 @@ nfs_removeit(sp, p)
 /*
  * nfs file rename call
  */
 /*
  * nfs file rename call
  */
-nfs_rename(sndp, tndp, p)
+nfs_rename(sndp, tndp, procp)
        register struct nameidata *sndp, *tndp;
        register struct nameidata *sndp, *tndp;
-       struct proc *p;
+       struct proc *procp;
 {
        register u_long *tl;
        register caddr_t cp;
 {
        register u_long *tl;
        register caddr_t cp;
-       register long t1, t2;
+       register long t2;
        caddr_t bpos, dpos;
        caddr_t bpos, dpos;
-       u_long xid;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_RENAME]++;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_RENAME]++;
-       nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
-               (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_namelen) +
+       nfsm_reqhead(sndp->ni_dvp, NFSPROC_RENAME,
+               (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_namelen)+
                nfsm_rndup(tndp->ni_namelen)); /* or sndp->ni_cred?*/
        nfsm_fhtom(sndp->ni_dvp);
        nfsm_strtom(sndp->ni_ptr, sndp->ni_namelen, NFS_MAXNAMLEN);
        nfsm_fhtom(tndp->ni_dvp);
        nfsm_strtom(tndp->ni_ptr, tndp->ni_namelen, NFS_MAXNAMLEN);
                nfsm_rndup(tndp->ni_namelen)); /* or sndp->ni_cred?*/
        nfsm_fhtom(sndp->ni_dvp);
        nfsm_strtom(sndp->ni_ptr, sndp->ni_namelen, NFS_MAXNAMLEN);
        nfsm_fhtom(tndp->ni_dvp);
        nfsm_strtom(tndp->ni_ptr, tndp->ni_namelen, NFS_MAXNAMLEN);
-       nfsm_request(sndp->ni_dvp, NFSPROC_RENAME, p, 1);
+       nfsm_request(sndp->ni_dvp, NFSPROC_RENAME, procp, tndp->ni_cred);
        nfsm_reqdone;
        VTONFS(sndp->ni_dvp)->n_flag |= NMODIFIED;
        VTONFS(tndp->ni_dvp)->n_flag |= NMODIFIED;
        nfsm_reqdone;
        VTONFS(sndp->ni_dvp)->n_flag |= NMODIFIED;
        VTONFS(tndp->ni_dvp)->n_flag |= NMODIFIED;
@@ -959,67 +991,60 @@ nfs_rename(sndp, tndp, p)
 /*
  * nfs file rename rpc called from nfs_remove() above
  */
 /*
  * nfs file rename rpc called from nfs_remove() above
  */
-nfs_renameit(sndp, sp, p)
+nfs_renameit(sndp, sp, procp)
        register struct nameidata *sndp;
        register struct sillyrename *sp;
        register struct nameidata *sndp;
        register struct sillyrename *sp;
-       struct proc *p;
+       struct proc *procp;
 {
        register u_long *tl;
        register caddr_t cp;
 {
        register u_long *tl;
        register caddr_t cp;
-       register long t1, t2;
+       register long t2;
        caddr_t bpos, dpos;
        caddr_t bpos, dpos;
-       u_long xid;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_RENAME]++;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_RENAME]++;
-       nfsm_reqhead(nfs_procids[NFSPROC_RENAME], sp->s_cred,
-               (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_namelen) +
-               nfsm_rndup(sp->s_namlen)); /* or sndp->ni_cred?*/
+       nfsm_reqhead(sndp->ni_dvp, NFSPROC_RENAME,
+               (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_namelen)+
+               nfsm_rndup(sp->s_namlen));
        nfsm_fhtom(sndp->ni_dvp);
        nfsm_strtom(sndp->ni_ptr, sndp->ni_namelen, NFS_MAXNAMLEN);
        nfsm_fhtom(sp->s_dvp);
        nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
        nfsm_fhtom(sndp->ni_dvp);
        nfsm_strtom(sndp->ni_ptr, sndp->ni_namelen, NFS_MAXNAMLEN);
        nfsm_fhtom(sp->s_dvp);
        nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
-       nfsm_request(sndp->ni_dvp, NFSPROC_RENAME, p, 1);
+       nfsm_request(sndp->ni_dvp, NFSPROC_RENAME, procp, sndp->ni_cred);
        nfsm_reqdone;
        FREE(sndp->ni_pnbuf, M_NAMEI);
        VTONFS(sndp->ni_dvp)->n_flag |= NMODIFIED;
        nfsm_reqdone;
        FREE(sndp->ni_pnbuf, M_NAMEI);
        VTONFS(sndp->ni_dvp)->n_flag |= NMODIFIED;
-       VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
        return (error);
 }
 
 /*
  * nfs hard link create call
  */
        return (error);
 }
 
 /*
  * nfs hard link create call
  */
-nfs_link(vp, ndp, p)
+nfs_link(vp, ndp, procp)
        register struct vnode *vp;
        register struct nameidata *ndp;
        register struct vnode *vp;
        register struct nameidata *ndp;
-       struct proc *p;
+       struct proc *procp;
 {
        register u_long *tl;
        register caddr_t cp;
 {
        register u_long *tl;
        register caddr_t cp;
-       register long t1, t2;
+       register long t2;
        caddr_t bpos, dpos;
        caddr_t bpos, dpos;
-       u_long xid;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
-       if (ndp->ni_dvp != vp)
-               nfs_lock(vp);
        nfsstats.rpccnt[NFSPROC_LINK]++;
        nfsstats.rpccnt[NFSPROC_LINK]++;
-       nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred,
+       nfsm_reqhead(vp, NFSPROC_LINK,
                NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen));
        nfsm_fhtom(vp);
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
                NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen));
        nfsm_fhtom(vp);
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
-       nfsm_request(vp, NFSPROC_LINK, p, 1);
+       nfsm_request(vp, NFSPROC_LINK, procp, ndp->ni_cred);
        nfsm_reqdone;
        FREE(ndp->ni_pnbuf, M_NAMEI);
        VTONFS(vp)->n_attrstamp = 0;
        VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
        nfsm_reqdone;
        FREE(ndp->ni_pnbuf, M_NAMEI);
        VTONFS(vp)->n_attrstamp = 0;
        VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
-       if (ndp->ni_dvp != vp)
-               nfs_unlock(vp);
-       nfs_nput(ndp->ni_dvp);
+       vrele(ndp->ni_dvp);
        /*
         * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
         */
        /*
         * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
         */
@@ -1031,27 +1056,27 @@ nfs_link(vp, ndp, p)
 /*
  * nfs symbolic link create call
  */
 /*
  * nfs symbolic link create call
  */
-nfs_symlink(ndp, vap, nm, p)
+nfs_symlink(ndp, vap, nm, procp)
        struct nameidata *ndp;
        struct vattr *vap;
        struct nameidata *ndp;
        struct vattr *vap;
-       char *nm;               /* is this the path ?? */
-       struct proc *p;
+       char *nm;
+       struct proc *procp;
 {
        register struct nfsv2_sattr *sp;
        register u_long *tl;
        register caddr_t cp;
 {
        register struct nfsv2_sattr *sp;
        register u_long *tl;
        register caddr_t cp;
-       register long t1, t2;
+       register long t2;
        caddr_t bpos, dpos;
        caddr_t bpos, dpos;
-       u_long xid;
-       int error = 0;
+       int slen, error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_SYMLINK]++;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_SYMLINK]++;
-       nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred,
-       NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_UNSIGNED);
+       slen = strlen(nm);
+       nfsm_reqhead(ndp->ni_dvp, NFSPROC_SYMLINK,
+        NFSX_FH+2*NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+nfsm_rndup(slen)+NFSX_SATTR);
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
-       nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN);
+       nfsm_strtom(nm, slen, NFS_MAXPATHLEN);
        nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
        sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
        sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
        nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
        sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
        sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
@@ -1059,11 +1084,11 @@ nfs_symlink(ndp, vap, nm, p)
        sp->sa_size = txdr_unsigned(VNOVAL);
        txdr_time(&vap->va_atime, &sp->sa_atime);       /* or VNOVAL ?? */
        txdr_time(&vap->va_mtime, &sp->sa_mtime);       /* or VNOVAL ?? */
        sp->sa_size = txdr_unsigned(VNOVAL);
        txdr_time(&vap->va_atime, &sp->sa_atime);       /* or VNOVAL ?? */
        txdr_time(&vap->va_mtime, &sp->sa_mtime);       /* or VNOVAL ?? */
-       nfsm_request(ndp->ni_dvp, NFSPROC_SYMLINK, p, 1);
+       nfsm_request(ndp->ni_dvp, NFSPROC_SYMLINK, procp, ndp->ni_cred);
        nfsm_reqdone;
        FREE(ndp->ni_pnbuf, M_NAMEI);
        VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
        nfsm_reqdone;
        FREE(ndp->ni_pnbuf, M_NAMEI);
        VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
-       nfs_nput(ndp->ni_dvp);
+       vrele(ndp->ni_dvp);
        /*
         * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
         */
        /*
         * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
         */
@@ -1075,10 +1100,10 @@ nfs_symlink(ndp, vap, nm, p)
 /*
  * nfs make dir call
  */
 /*
  * nfs make dir call
  */
-nfs_mkdir(ndp, vap, p)
+nfs_mkdir(ndp, vap, procp)
        register struct nameidata *ndp;
        struct vattr *vap;
        register struct nameidata *ndp;
        struct vattr *vap;
-       struct proc *p;
+       struct proc *procp;
 {
        register struct nfsv2_sattr *sp;
        register u_long *tl;
 {
        register struct nfsv2_sattr *sp;
        register u_long *tl;
@@ -1086,13 +1111,12 @@ nfs_mkdir(ndp, vap, p)
        register long t1, t2;
        register int len;
        caddr_t bpos, dpos, cp2;
        register long t1, t2;
        register int len;
        caddr_t bpos, dpos, cp2;
-       u_long xid;
        int error = 0, firsttry = 1;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        len = ndp->ni_namelen;
        nfsstats.rpccnt[NFSPROC_MKDIR]++;
        int error = 0, firsttry = 1;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        len = ndp->ni_namelen;
        nfsstats.rpccnt[NFSPROC_MKDIR]++;
-       nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred,
+       nfsm_reqhead(ndp->ni_dvp, NFSPROC_MKDIR,
          NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR);
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
          NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR);
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
@@ -1103,7 +1127,7 @@ nfs_mkdir(ndp, vap, p)
        sp->sa_size = txdr_unsigned(VNOVAL);
        txdr_time(&vap->va_atime, &sp->sa_atime);       /* or VNOVAL ?? */
        txdr_time(&vap->va_mtime, &sp->sa_mtime);       /* or VNOVAL ?? */
        sp->sa_size = txdr_unsigned(VNOVAL);
        txdr_time(&vap->va_atime, &sp->sa_atime);       /* or VNOVAL ?? */
        txdr_time(&vap->va_mtime, &sp->sa_mtime);       /* or VNOVAL ?? */
-       nfsm_request(ndp->ni_dvp, NFSPROC_MKDIR, p, 1);
+       nfsm_request(ndp->ni_dvp, NFSPROC_MKDIR, procp, ndp->ni_cred);
        nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
        nfsm_reqdone;
        VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
        nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
        nfsm_reqdone;
        VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
@@ -1118,11 +1142,11 @@ nfs_mkdir(ndp, vap, p)
                error = 0;
                nfsstats.rpccnt[NFSPROC_LOOKUP]++;
                ndp->ni_vp = NULL;
                error = 0;
                nfsstats.rpccnt[NFSPROC_LOOKUP]++;
                ndp->ni_vp = NULL;
-               nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred,
+               nfsm_reqhead(ndp->ni_dvp, NFSPROC_LOOKUP,
                    NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
                nfsm_fhtom(ndp->ni_dvp);
                nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
                    NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
                nfsm_fhtom(ndp->ni_dvp);
                nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
-               nfsm_request(ndp->ni_dvp, NFSPROC_LOOKUP, p, 1);
+               nfsm_request(ndp->ni_dvp, NFSPROC_LOOKUP, procp, ndp->ni_cred);
                nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
                if (ndp->ni_vp->v_type != VDIR) {
                        vput(ndp->ni_vp);
                nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
                if (ndp->ni_vp->v_type != VDIR) {
                        vput(ndp->ni_vp);
@@ -1131,43 +1155,43 @@ nfs_mkdir(ndp, vap, p)
                m_freem(mrep);
        }
        FREE(ndp->ni_pnbuf, M_NAMEI);
                m_freem(mrep);
        }
        FREE(ndp->ni_pnbuf, M_NAMEI);
-       nfs_nput(ndp->ni_dvp);
+       vrele(ndp->ni_dvp);
        return (error);
 }
 
 /*
  * nfs remove directory call
  */
        return (error);
 }
 
 /*
  * nfs remove directory call
  */
-nfs_rmdir(ndp, p)
+nfs_rmdir(ndp, procp)
        register struct nameidata *ndp;
        register struct nameidata *ndp;
-       struct proc *p;
+       struct proc *procp;
 {
        register u_long *tl;
        register caddr_t cp;
 {
        register u_long *tl;
        register caddr_t cp;
-       register long t1, t2;
+       register long t2;
        caddr_t bpos, dpos;
        caddr_t bpos, dpos;
-       u_long xid;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        if (ndp->ni_dvp == ndp->ni_vp) {
                vrele(ndp->ni_dvp);
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        if (ndp->ni_dvp == ndp->ni_vp) {
                vrele(ndp->ni_dvp);
-               nfs_nput(ndp->ni_dvp);
+               vrele(ndp->ni_dvp);
+               FREE(ndp->ni_pnbuf, M_NAMEI);
                return (EINVAL);
        }
        nfsstats.rpccnt[NFSPROC_RMDIR]++;
                return (EINVAL);
        }
        nfsstats.rpccnt[NFSPROC_RMDIR]++;
-       nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred,
+       nfsm_reqhead(ndp->ni_dvp, NFSPROC_RMDIR,
                NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen));
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
                NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen));
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
-       nfsm_request(ndp->ni_dvp, NFSPROC_RMDIR, p, 1);
+       nfsm_request(ndp->ni_dvp, NFSPROC_RMDIR, procp, ndp->ni_cred);
        nfsm_reqdone;
        FREE(ndp->ni_pnbuf, M_NAMEI);
        VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
        cache_purge(ndp->ni_dvp);
        cache_purge(ndp->ni_vp);
        nfsm_reqdone;
        FREE(ndp->ni_pnbuf, M_NAMEI);
        VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
        cache_purge(ndp->ni_dvp);
        cache_purge(ndp->ni_vp);
-       nfs_nput(ndp->ni_vp);
-       nfs_nput(ndp->ni_dvp);
+       vrele(ndp->ni_vp);
+       vrele(ndp->ni_dvp);
        /*
         * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
         */
        /*
         * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
         */
@@ -1198,12 +1222,19 @@ nfs_readdir(vp, uiop, cred, eofflagp)
         * First, check for hit on the EOF offset cache
         */
        if (uiop->uio_offset != 0 && uiop->uio_offset == np->n_direofoffset &&
         * First, check for hit on the EOF offset cache
         */
        if (uiop->uio_offset != 0 && uiop->uio_offset == np->n_direofoffset &&
-           (np->n_flag & NMODIFIED) == 0 &&
-           nfs_dogetattr(vp, &vattr, cred, 0, uiop->uio_procp) == 0 &&
-           np->n_mtime == vattr.va_mtime.tv_sec) {
-               *eofflagp = 1;
-               nfsstats.direofcache_hits++;
-               return (0);
+           (np->n_flag & NMODIFIED) == 0) {
+               if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
+                       if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
+                               *eofflagp = 1;
+                               nfsstats.direofcache_hits++;
+                               return (0);
+                       }
+               } else if (nfs_getattr(vp, &vattr, cred, uiop->uio_procp) == 0 &&
+                       np->n_mtime == vattr.va_mtime.tv_sec) {
+                       *eofflagp = 1;
+                       nfsstats.direofcache_hits++;
+                       return (0);
+               }
        }
 
        /*
        }
 
        /*
@@ -1236,7 +1267,6 @@ nfs_readdirrpc(vp, uiop, cred)
        register long t1;
        long tlen, lastlen;
        caddr_t bpos, dpos, cp2;
        register long t1;
        long tlen, lastlen;
        caddr_t bpos, dpos, cp2;
-       u_long xid;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct mbuf *md2;
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct mbuf *md2;
@@ -1258,15 +1288,16 @@ nfs_readdirrpc(vp, uiop, cred)
         */
        while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
                nfsstats.rpccnt[NFSPROC_READDIR]++;
         */
        while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
                nfsstats.rpccnt[NFSPROC_READDIR]++;
-               nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid);
+               nfsm_reqhead(vp, NFSPROC_READDIR,
+                       NFSX_FH+2*NFSX_UNSIGNED);
                nfsm_fhtom(vp);
                nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
                *tl++ = txdr_unsigned(uiop->uio_offset);
                *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
                        nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
                nfsm_fhtom(vp);
                nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
                *tl++ = txdr_unsigned(uiop->uio_offset);
                *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
                        nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
-               nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, 0);
+               nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
                siz = 0;
                siz = 0;
-               nfsm_disect(tl, u_long *, NFSX_UNSIGNED);
+               nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
                more_dirs = fxdr_unsigned(int, *tl);
        
                /* Save the position so that we can do nfsm_mtouio() later */
                more_dirs = fxdr_unsigned(int, *tl);
        
                /* Save the position so that we can do nfsm_mtouio() later */
@@ -1281,7 +1312,7 @@ nfs_readdirrpc(vp, uiop, cred)
                while (more_dirs && siz < uiop->uio_resid) {
                        savoff = off;           /* Hold onto offset and dp */
                        savdp = dp;
                while (more_dirs && siz < uiop->uio_resid) {
                        savoff = off;           /* Hold onto offset and dp */
                        savdp = dp;
-                       nfsm_disecton(tl, u_long *, 2*NFSX_UNSIGNED);
+                       nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED);
                        dp = (struct direct *)tl;
                        dp->d_ino = fxdr_unsigned(u_long, *tl++);
                        len = fxdr_unsigned(int, *tl);
                        dp = (struct direct *)tl;
                        dp->d_ino = fxdr_unsigned(u_long, *tl++);
                        len = fxdr_unsigned(int, *tl);
@@ -1302,7 +1333,7 @@ nfs_readdirrpc(vp, uiop, cred)
                                nfsm_adv(tlen - len);
                                len = tlen;
                        }
                                nfsm_adv(tlen - len);
                                len = tlen;
                        }
-                       nfsm_disecton(tl, u_long *, 2*NFSX_UNSIGNED);
+                       nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED);
                        off = fxdr_unsigned(off_t, *tl);
                        *tl++ = 0;      /* Ensures null termination of name */
                        more_dirs = fxdr_unsigned(int, *tl);
                        off = fxdr_unsigned(off_t, *tl);
                        *tl++ = 0;      /* Ensures null termination of name */
                        more_dirs = fxdr_unsigned(int, *tl);
@@ -1313,7 +1344,7 @@ nfs_readdirrpc(vp, uiop, cred)
                 * If at end of rpc data, get the eof boolean
                 */
                if (!more_dirs) {
                 * If at end of rpc data, get the eof boolean
                 */
                if (!more_dirs) {
-                       nfsm_disecton(tl, u_long *, NFSX_UNSIGNED);
+                       nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED);
                        more_dirs = (fxdr_unsigned(int, *tl) == 0);
 
                        /*
                        more_dirs = (fxdr_unsigned(int, *tl) == 0);
 
                        /*
@@ -1362,6 +1393,201 @@ nfsmout:
        return (error);
 }
 
        return (error);
 }
 
+/*
+ * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc() when
+ * the "rdirlook" mount option is specified.
+ */
+nfs_readdirlookrpc(vp, uiop, cred)
+       struct vnode *vp;
+       register struct uio *uiop;
+       struct ucred *cred;
+{
+       register int len;
+       register struct direct *dp;
+       register u_long *tl;
+       register caddr_t cp;
+       register long t1;
+       caddr_t bpos, dpos, cp2;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       struct nameidata nami, *ndp = &nami;
+       off_t off, endoff;
+       time_t reqtime, ltime;
+       struct nfsmount *nmp;
+       struct nfsnode *np, *tp;
+       struct vnode *newvp;
+       nfsv2fh_t *fhp;
+       u_long fileno;
+       u_quad_t frev;
+       int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
+       int cachable;
+
+       if (uiop->uio_iovcnt != 1)
+               panic("nfs rdirlook");
+       nmp = VFSTONFS(vp->v_mount);
+       tresid = uiop->uio_resid;
+       ndp->ni_dvp = vp;
+       newvp = NULLVP;
+       /*
+        * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
+        * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
+        * The stopping criteria is EOF or buffer full.
+        */
+       while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
+               nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
+               nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
+                       NFSX_FH+3*NFSX_UNSIGNED);
+               nfsm_fhtom(vp);
+               nfsm_build(tl, u_long *, 3*NFSX_UNSIGNED);
+               *tl++ = txdr_unsigned(uiop->uio_offset);
+               *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
+                       nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
+               *tl = txdr_unsigned(nmp->nm_leaseterm);
+               reqtime = time.tv_sec;
+               nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
+               nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+               more_dirs = fxdr_unsigned(int, *tl);
+       
+               /* loop thru the dir entries, doctoring them to 4bsd form */
+               off = uiop->uio_offset;
+               bigenough = 1;
+               while (more_dirs && bigenough) {
+                       doit = 1;
+                       nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
+                       cachable = fxdr_unsigned(int, *tl++);
+                       ltime = reqtime + fxdr_unsigned(int, *tl++);
+                       fxdr_hyper(tl, &frev);
+                       nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
+                       if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
+                               VREF(vp);
+                               newvp = vp;
+                               np = VTONFS(vp);
+                       } else {
+                               if (error = nfs_nget(vp->v_mount, fhp, &np))
+                                       doit = 0;
+                               newvp = NFSTOV(np);
+                       }
+                       if (error = nfs_loadattrcache(&newvp, &md, &dpos,
+                               (struct vattr *)0))
+                               doit = 0;
+                       nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
+                       fileno = fxdr_unsigned(u_long, *tl++);
+                       len = fxdr_unsigned(int, *tl);
+                       if (len <= 0 || len > NFS_MAXNAMLEN) {
+                               error = EBADRPC;
+                               m_freem(mrep);
+                               goto nfsmout;
+                       }
+                       tlen = (len + 4) & ~0x3;
+                       if ((tlen + DIRHDSIZ) > uiop->uio_resid)
+                               bigenough = 0;
+                       if (bigenough && doit) {
+                               dp = (struct direct *)uiop->uio_iov->iov_base;
+                               dp->d_ino = fileno;
+                               dp->d_namlen = len;
+                               dp->d_reclen = tlen + DIRHDSIZ;
+                               uiop->uio_resid -= DIRHDSIZ;
+                               uiop->uio_iov->iov_base += DIRHDSIZ;
+                               uiop->uio_iov->iov_len -= DIRHDSIZ;
+                               ndp->ni_ptr = uiop->uio_iov->iov_base;
+                               ndp->ni_namelen = len;
+                               ndp->ni_vp = newvp;
+                               nfsm_mtouio(uiop, len);
+                               cp = uiop->uio_iov->iov_base;
+                               tlen -= len;
+                               for (i = 0; i < tlen; i++)
+                                       *cp++ = '\0';
+                               uiop->uio_iov->iov_base += tlen;
+                               uiop->uio_iov->iov_len -= tlen;
+                               uiop->uio_resid -= tlen;
+                               ndp->ni_hash = 0;
+                               for (cp = ndp->ni_ptr, i = 1; i <= len; i++, cp++)
+                                       ndp->ni_hash += (unsigned char)*cp * i;
+                               if (ltime > time.tv_sec) {
+                                       if (np->n_tnext) {
+                                               if (np->n_tnext == (struct nfsnode *)nmp)
+                                                       nmp->nm_tprev = np->n_tprev;
+                                               else
+                                                       np->n_tnext->n_tprev = np->n_tprev;
+                                               if (np->n_tprev == (struct nfsnode *)nmp)
+                                                       nmp->nm_tnext = np->n_tnext;
+                                               else
+                                                       np->n_tprev->n_tnext = np->n_tnext;
+                                       } else
+                                               np->n_flag &= ~NQNFSWRITE;
+                                       if (cachable)
+                                               np->n_flag &= ~NQNFSNONCACHE;
+                                       else
+                                               np->n_flag |= NQNFSNONCACHE;
+                                       np->n_expiry = ltime;
+                                       np->n_lrev = frev;
+                                       tp = nmp->nm_tprev;
+                                       while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry)
+                                               tp = tp->n_tprev;
+                                       if (tp == (struct nfsnode *)nmp) {
+                                               np->n_tnext = nmp->nm_tnext;
+                                               nmp->nm_tnext = np;
+                                       } else {
+                                               np->n_tnext = tp->n_tnext;
+                                               tp->n_tnext = np;
+                                       }
+                                       np->n_tprev = tp;
+                                       if (np->n_tnext == (struct nfsnode *)nmp)
+                                               nmp->nm_tprev = np;
+                                       else
+                                               np->n_tnext->n_tprev = np;
+                                       cache_enter(ndp);
+                               }
+                       } else {
+                               nfsm_adv(nfsm_rndup(len));
+                       }
+                       if (newvp != NULLVP) {
+                               vrele(newvp);
+                               newvp = NULLVP;
+                       }
+                       nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
+                       if (bigenough)
+                               endoff = off = fxdr_unsigned(off_t, *tl++);
+                       else
+                               endoff = fxdr_unsigned(off_t, *tl++);
+                       more_dirs = fxdr_unsigned(int, *tl);
+               }
+               /*
+                * If at end of rpc data, get the eof boolean
+                */
+               if (!more_dirs) {
+                       nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+                       more_dirs = (fxdr_unsigned(int, *tl) == 0);
+
+                       /*
+                        * If at EOF, cache directory offset
+                        */
+                       if (!more_dirs)
+                               VTONFS(vp)->n_direofoffset = endoff;
+               }
+               if (uiop->uio_resid < tresid)
+                       uiop->uio_offset = off;
+               else
+                       more_dirs = 0;
+               m_freem(mrep);
+       }
+       /*
+        * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
+        * by increasing d_reclen for the last record.
+        */
+       if (uiop->uio_resid < tresid) {
+               len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
+               if (len > 0) {
+                       dp->d_reclen += len;
+                       uiop->uio_iov->iov_base += len;
+                       uiop->uio_iov->iov_len -= len;
+                       uiop->uio_resid -= len;
+               }
+       }
+nfsmout:
+       if (newvp != NULLVP)
+               vrele(newvp);
+       return (error);
+}
 static char hextoasc[] = "0123456789abcdef";
 
 /*
 static char hextoasc[] = "0123456789abcdef";
 
 /*
@@ -1381,16 +1607,14 @@ nfs_sillyrename(ndp, p)
        int error;
        short pid;
 
        int error;
        short pid;
 
-       np = VTONFS(ndp->ni_dvp);
        cache_purge(ndp->ni_dvp);
        cache_purge(ndp->ni_dvp);
+       np = VTONFS(ndp->ni_vp);
 #ifdef SILLYSEPARATE
        MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
                M_NFSREQ, M_WAITOK);
 #else
        sp = &np->n_silly;
 #endif
 #ifdef SILLYSEPARATE
        MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
                M_NFSREQ, M_WAITOK);
 #else
        sp = &np->n_silly;
 #endif
-       bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH);
-       np = VTONFS(ndp->ni_vp);
        sp->s_cred = crdup(ndp->ni_cred);
        sp->s_dvp = ndp->ni_dvp;
        VREF(sp->s_dvp);
        sp->s_cred = crdup(ndp->ni_cred);
        sp->s_dvp = ndp->ni_dvp;
        VREF(sp->s_dvp);
@@ -1432,10 +1656,10 @@ bad:
  * into the nfsnode table.
  * If fhp != NULL it copies the returned file handle out
  */
  * into the nfsnode table.
  * If fhp != NULL it copies the returned file handle out
  */
-nfs_lookitup(sp, fhp, p)
+nfs_lookitup(sp, fhp, procp)
        register struct sillyrename *sp;
        nfsv2fh_t *fhp;
        register struct sillyrename *sp;
        nfsv2fh_t *fhp;
-       struct proc *p;
+       struct proc *procp;
 {
        register struct vnode *vp = sp->s_dvp;
        register u_long *tl;
 {
        register struct vnode *vp = sp->s_dvp;
        register u_long *tl;
@@ -1449,12 +1673,12 @@ nfs_lookitup(sp, fhp, p)
 
        nfsstats.rpccnt[NFSPROC_LOOKUP]++;
        len = sp->s_namlen;
 
        nfsstats.rpccnt[NFSPROC_LOOKUP]++;
        len = sp->s_namlen;
-       nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], sp->s_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
+       nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
        nfsm_fhtom(vp);
        nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
        nfsm_fhtom(vp);
        nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
-       nfsm_request(vp, NFSPROC_LOOKUP, p, 1);
+       nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
        if (fhp != NULL) {
        if (fhp != NULL) {
-               nfsm_disect(cp, caddr_t, NFSX_FH);
+               nfsm_dissect(cp, caddr_t, NFSX_FH);
                bcopy(cp, (caddr_t)fhp, NFSX_FH);
        }
        nfsm_reqdone;
                bcopy(cp, (caddr_t)fhp, NFSX_FH);
        }
        nfsm_reqdone;
@@ -1481,7 +1705,7 @@ nfs_bmap(vp, bn, vpp, bnp)
        if (vpp != NULL)
                *vpp = vp;
        if (bnp != NULL)
        if (vpp != NULL)
                *vpp = vp;
        if (bnp != NULL)
-               *bnp = bn * btodb(vp->v_mount->mnt_stat.f_bsize);
+               *bnp = bn * btodb(vp->v_mount->mnt_stat.f_iosize);
        return (0);
 }
 
        return (0);
 }
 
@@ -1565,7 +1789,7 @@ nfs_doio(bp)
        uiop->uio_iov = &io;
        uiop->uio_iovcnt = 1;
        uiop->uio_segflg = UIO_SYSSPACE;
        uiop->uio_iov = &io;
        uiop->uio_iovcnt = 1;
        uiop->uio_segflg = UIO_SYSSPACE;
-       uiop->uio_procp = (struct proc *)0;
+       uiop->uio_procp = bp->b_proc;
 
        /*
         * For phys i/o, map the b_addr into kernel virtual space using
 
        /*
         * For phys i/o, map the b_addr into kernel virtual space using
@@ -1619,7 +1843,10 @@ nfs_doio(bp)
                        case VDIR:
                                uiop->uio_offset = bp->b_lblkno;
                                nfsstats.readdir_bios++;
                        case VDIR:
                                uiop->uio_offset = bp->b_lblkno;
                                nfsstats.readdir_bios++;
-                               error = nfs_readdirrpc(vp, uiop, bp->b_rcred);
+                               if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_RDIRALOOK)
+                                   error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred);
+                               else
+                                   error = nfs_readdirrpc(vp, uiop, bp->b_rcred);
                                /*
                                 * Save offset cookie in b_blkno.
                                 */
                                /*
                                 * Save offset cookie in b_blkno.
                                 */
@@ -1721,12 +1948,6 @@ nfs_print(vp)
        if (vp->v_type == VFIFO)
                fifo_printinfo(vp);
 #endif /* FIFO */
        if (vp->v_type == VFIFO)
                fifo_printinfo(vp);
 #endif /* FIFO */
-       printf("%s\n", (np->n_flag & NLOCKED) ? " (LOCKED)" : "");
-       if (np->n_lockholder == 0)
-               return;
-       printf("\towner pid %d", np->n_lockholder);
-       if (np->n_lockwaiter)
-               printf(" waiting pid %d", np->n_lockwaiter);
        printf("\n");
 }
 
        printf("\n");
 }
 
index 4acdf54..4e1cba2 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfsdiskless.h       7.1 (Berkeley) %G%
+ *     @(#)nfsdiskless.h       7.2 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
  * This structure is used by nfs_mountroot() to set up the root and swap
  * vnodes plus do a partial ifconfig(8) and route(8) so that the critical net
  * interface can communicate with the server.
  * This structure is used by nfs_mountroot() to set up the root and swap
  * vnodes plus do a partial ifconfig(8) and route(8) so that the critical net
  * interface can communicate with the server.
- * For now it is statically initialized in swapvmunix.c, but someday a primary
- * bootstrap should fill it in.
+ * The primary bootstrap is expected to fill in the appropriate fields before
+ * starting vmunix. Whether or not the swap area is nfs mounted is determined
+ * by the value in swdevt[0]. (equal to NODEV --> swap over nfs)
+ * Currently only works for AF_INET protocols.
+ * NB: All fields are stored in net byte order to avoid hassles with
+ * client/server byte ordering differences.
  */
 struct nfs_diskless {
  */
 struct nfs_diskless {
-       struct ifaliasreq myif;         /* Info. for partial ifconfig */
-       struct sockaddr mygateway;      /* Default gateway for "route add" */
-       struct nfs_args swap_args;      /* Mount args for swap file */
-       u_char          swap_fh[NFS_FHSIZE]; /* Swap file's file handle */
-       struct sockaddr swap_saddr;     /* Address of swap server */
-       char            *swap_hostnam;  /* Host name for mount pt */
-       struct nfs_args root_args;      /* Mount args for root fs */
-       u_char          root_fh[NFS_FHSIZE]; /* File handle of root dir */
-       struct sockaddr root_saddr;     /* Address of root server */
-       char            *root_hostnam;  /* Host name for mount pt */
+       struct ifaliasreq myif;                 /* Default interface */
+       struct sockaddr_in mygateway;           /* Default gateway */
+       struct nfs_args swap_args;              /* Mount args for swap file */
+       u_char          swap_fh[NFS_FHSIZE];    /* Swap file's file handle */
+       struct sockaddr_in swap_saddr;          /* Address of swap server */
+       char            swap_hostnam[MNAMELEN]; /* Host name for mount pt */
+       int             swap_nblks;             /* Size of server swap file */
+       struct nfs_args root_args;              /* Mount args for root fs */
+       u_char          root_fh[NFS_FHSIZE];    /* File handle of root dir */
+       struct sockaddr_in root_saddr;          /* Address of root server */
+       char            root_hostnam[MNAMELEN]; /* Host name for mount pt */
 };
 };
index a0376fd..3006304 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfsm_subs.h 7.11 (Berkeley) %G%
+ *     @(#)nfsm_subs.h 7.12 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
 extern struct mbuf *nfsm_reqh();
 
 #define        M_HASCL(m)      ((m)->m_flags & M_EXT)
 extern struct mbuf *nfsm_reqh();
 
 #define        M_HASCL(m)      ((m)->m_flags & M_EXT)
-#define        NFSMGETHDR(m) \
-               MGETHDR(m, M_WAIT, MT_DATA); \
-               (m)->m_pkthdr.len = 0; \
-               (m)->m_pkthdr.rcvif = (struct ifnet *)0
 #define        NFSMINOFF(m) \
                if (M_HASCL(m)) \
                        (m)->m_data = (m)->m_ext.ext_buf; \
 #define        NFSMINOFF(m) \
                if (M_HASCL(m)) \
                        (m)->m_data = (m)->m_ext.ext_buf; \
+               else if ((m)->m_flags & M_PKTHDR) \
+                       (m)->m_data = (m)->m_pktdat; \
                else \
                        (m)->m_data = (m)->m_dat
 #define        NFSMADV(m, s)   (m)->m_data += (s)
                else \
                        (m)->m_data = (m)->m_dat
 #define        NFSMADV(m, s)   (m)->m_data += (s)
@@ -48,10 +46,8 @@ extern struct mbuf *nfsm_reqh();
  * unions.
  */
 
  * unions.
  */
 
-#ifndef lint
 #define        nfsm_build(a,c,s) \
 #define        nfsm_build(a,c,s) \
-               t1 = NFSMSIZ(mb); \
-               if ((s) > (t1-mb->m_len)) { \
+               { if ((s) > M_TRAILINGSPACE(mb)) { \
                        MGET(mb2, M_WAIT, MT_DATA); \
                        if ((s) > MLEN) \
                                panic("build > MLEN"); \
                        MGET(mb2, M_WAIT, MT_DATA); \
                        if ((s) > MLEN) \
                                panic("build > MLEN"); \
@@ -62,24 +58,10 @@ extern struct mbuf *nfsm_reqh();
                } \
                (a) = (c)(bpos); \
                mb->m_len += (s); \
                } \
                (a) = (c)(bpos); \
                mb->m_len += (s); \
-               bpos += (s)
-#else /* lint */
-#define        nfsm_build(a,c,s) \
-               t1 = NFSMSIZ(mb); \
-               if ((s) > (t1-mb->m_len)) { \
-                       MGET(mb2, M_WAIT, MT_DATA); \
-                       mb->m_next = mb2; \
-                       mb = mb2; \
-                       mb->m_len = 0; \
-                       bpos = mtod(mb, caddr_t); \
-               } \
-               (a) = (c)(bpos); \
-               mb->m_len += (s); \
-               bpos += (s)
-#endif /* lint */
+               bpos += (s); }
 
 
-#define        nfsm_disect(a,c,s) \
-               t1 = mtod(md, caddr_t)+md->m_len-dpos; \
+#define        nfsm_dissect(a,c,s) \
+               t1 = mtod(md, caddr_t)+md->m_len-dpos; \
                if (t1 >= (s)) { \
                        (a) = (c)(dpos); \
                        dpos += (s); \
                if (t1 >= (s)) { \
                        (a) = (c)(dpos); \
                        dpos += (s); \
@@ -88,10 +70,10 @@ extern struct mbuf *nfsm_reqh();
                        goto nfsmout; \
                } else { \
                        (a) = (c)cp2; \
                        goto nfsmout; \
                } else { \
                        (a) = (c)cp2; \
-               }
+               } }
 
 
-#define        nfsm_disecton(a,c,s) \
-               t1 = mtod(md, caddr_t)+md->m_len-dpos; \
+#define        nfsm_dissecton(a,c,s) \
+               t1 = mtod(md, caddr_t)+md->m_len-dpos; \
                if (t1 >= (s)) { \
                        (a) = (c)(dpos); \
                        dpos += (s); \
                if (t1 >= (s)) { \
                        (a) = (c)(dpos); \
                        dpos += (s); \
@@ -100,7 +82,7 @@ extern struct mbuf *nfsm_reqh();
                        goto nfsmout; \
                } else { \
                        (a) = (c)cp2; \
                        goto nfsmout; \
                } else { \
                        (a) = (c)cp2; \
-               }
+               } }
 
 #define nfsm_fhtom(v) \
                nfsm_build(cp,caddr_t,NFSX_FH); \
 
 #define nfsm_fhtom(v) \
                nfsm_build(cp,caddr_t,NFSX_FH); \
@@ -112,7 +94,7 @@ extern struct mbuf *nfsm_reqh();
 
 #define nfsm_mtofh(d,v) \
                { struct nfsnode *np; nfsv2fh_t *fhp; \
 
 #define nfsm_mtofh(d,v) \
                { struct nfsnode *np; nfsv2fh_t *fhp; \
-               nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH); \
+               nfsm_dissect(fhp,nfsv2fh_t *,NFSX_FH); \
                if (error = nfs_nget((d)->v_mount, fhp, &np)) { \
                        m_freem(mrep); \
                        goto nfsmout; \
                if (error = nfs_nget((d)->v_mount, fhp, &np)) { \
                        m_freem(mrep); \
                        goto nfsmout; \
@@ -130,19 +112,19 @@ extern struct mbuf *nfsm_reqh();
                (v) = tvp; }
 
 #define        nfsm_strsiz(s,m) \
                (v) = tvp; }
 
 #define        nfsm_strsiz(s,m) \
-               nfsm_disect(tl,u_long *,NFSX_UNSIGNED); \
+               { nfsm_dissect(tl,u_long *,NFSX_UNSIGNED); \
                if (((s) = fxdr_unsigned(long,*tl)) > (m)) { \
                        m_freem(mrep); \
                        error = EBADRPC; \
                        goto nfsmout; \
                if (((s) = fxdr_unsigned(long,*tl)) > (m)) { \
                        m_freem(mrep); \
                        error = EBADRPC; \
                        goto nfsmout; \
-               }
+               } }
 
 #define        nfsm_srvstrsiz(s,m) \
 
 #define        nfsm_srvstrsiz(s,m) \
-               nfsm_disect(tl,u_long *,NFSX_UNSIGNED); \
+               { nfsm_dissect(tl,u_long *,NFSX_UNSIGNED); \
                if (((s) = fxdr_unsigned(long,*tl)) > (m) || (s) <= 0) { \
                        error = EBADRPC; \
                        nfsm_reply(0); \
                if (((s) = fxdr_unsigned(long,*tl)) > (m) || (s) <= 0) { \
                        error = EBADRPC; \
                        nfsm_reply(0); \
-               }
+               } }
 
 #define nfsm_mtouio(p,s) \
                if ((s) > 0 && \
 
 #define nfsm_mtouio(p,s) \
                if ((s) > 0 && \
@@ -157,20 +139,17 @@ extern struct mbuf *nfsm_reqh();
                        goto nfsmout; \
                }
 
                        goto nfsmout; \
                }
 
-#define        nfsm_reqhead(a,c,s) \
-               if ((mreq = nfsm_reqh(nfs_prog,nfs_vers,(a),(c),(s),&bpos,&mb,&xid)) == NULL) { \
-                       error = ENOBUFS; \
-                       goto nfsmout; \
-               }
+#define        nfsm_reqhead(v,a,s) \
+               mb = mreq = nfsm_reqh((v),(a),(s),&bpos)
 
 #define nfsm_reqdone   m_freem(mrep); \
                nfsmout: 
 
 #define nfsm_rndup(a)  (((a)+3)&(~0x3))
 
 
 #define nfsm_reqdone   m_freem(mrep); \
                nfsmout: 
 
 #define nfsm_rndup(a)  (((a)+3)&(~0x3))
 
-#define        nfsm_request(v, t, p, h)        \
-               if (error = nfs_request((v), mreq, xid, (t), (p), (h), \
-                  (v)->v_mount, &mrep, &md, &dpos)) \
+#define        nfsm_request(v, t, p, c)        \
+               if (error = nfs_request((v), mreq, (t), (p), \
+                  (c), &mrep, &md, &dpos)) \
                        goto nfsmout
 
 #define        nfsm_strtom(a,s,m) \
                        goto nfsmout
 
 #define        nfsm_strtom(a,s,m) \
@@ -180,7 +159,7 @@ extern struct mbuf *nfsm_reqh();
                        goto nfsmout; \
                } \
                t2 = nfsm_rndup(s)+NFSX_UNSIGNED; \
                        goto nfsmout; \
                } \
                t2 = nfsm_rndup(s)+NFSX_UNSIGNED; \
-               if(t2<=(NFSMSIZ(mb)-mb->m_len)){ \
+               if (t2 <= M_TRAILINGSPACE(mb)) { \
                        nfsm_build(tl,u_long *,t2); \
                        *tl++ = txdr_unsigned(s); \
                        *(tl+((t2>>2)-2)) = 0; \
                        nfsm_build(tl,u_long *,t2); \
                        *tl++ = txdr_unsigned(s); \
                        *(tl+((t2>>2)-2)) = 0; \
@@ -194,34 +173,20 @@ extern struct mbuf *nfsm_reqh();
                nfsmout: \
                return(error)
 
                nfsmout: \
                return(error)
 
-#ifndef lint
-#define        nfsm_reply(s) \
-               { \
-               *repstat = error; \
-               if (error) \
-                       nfs_rephead(0, xid, error, mrq, &mb, &bpos); \
-               else \
-                       nfs_rephead((s), xid, error, mrq, &mb, &bpos); \
-               m_freem(mrep); \
-               mreq = *mrq; \
-               if (error) \
-                       return(0); \
-               }
-#else  /* lint */
 #define        nfsm_reply(s) \
                { \
 #define        nfsm_reply(s) \
                { \
-               *repstat = error; \
+               nfsd->nd_repstat = error; \
                if (error) \
                if (error) \
-                       nfs_rephead(0, xid, error, mrq, &mb, &bpos); \
+                  (void) nfs_rephead(0, nfsd, error, cache, &frev, \
+                       mrq, &mb, &bpos); \
                else \
                else \
-                       nfs_rephead((s), xid, error, mrq, &mb, &bpos); \
+                  (void) nfs_rephead((s), nfsd, error, cache, &frev, \
+                       mrq, &mb, &bpos); \
                m_freem(mrep); \
                mreq = *mrq; \
                m_freem(mrep); \
                mreq = *mrq; \
-               mrep = mreq; \
                if (error) \
                        return(0); \
                }
                if (error) \
                        return(0); \
                }
-#endif /* lint */
 
 #define        nfsm_adv(s) \
                t1 = mtod(md, caddr_t)+md->m_len-dpos; \
 
 #define        nfsm_adv(s) \
                t1 = mtod(md, caddr_t)+md->m_len-dpos; \
@@ -233,20 +198,18 @@ extern struct mbuf *nfsm_reqh();
                }
 
 #define nfsm_srvmtofh(f) \
                }
 
 #define nfsm_srvmtofh(f) \
-               nfsm_disecton(tl, u_long *, NFSX_FH); \
+               nfsm_dissecton(tl, u_long *, NFSX_FH); \
                bcopy((caddr_t)tl, (caddr_t)f, NFSX_FH)
 
 #define        nfsm_clget \
                if (bp >= be) { \
                bcopy((caddr_t)tl, (caddr_t)f, NFSX_FH)
 
 #define        nfsm_clget \
                if (bp >= be) { \
+                       if (mp == mb) \
+                               mp->m_len += bp-bpos; \
                        MGET(mp, M_WAIT, MT_DATA); \
                        MCLGET(mp, M_WAIT); \
                        mp->m_len = NFSMSIZ(mp); \
                        MGET(mp, M_WAIT, MT_DATA); \
                        MCLGET(mp, M_WAIT); \
                        mp->m_len = NFSMSIZ(mp); \
-                       if (mp3 == NULL) \
-                               mp3 = mp2 = mp; \
-                       else { \
-                               mp2->m_next = mp; \
-                               mp2 = mp; \
-                       } \
+                       mp2->m_next = mp; \
+                       mp2 = mp; \
                        bp = mtod(mp, caddr_t); \
                        be = bp+mp->m_len; \
                } \
                        bp = mtod(mp, caddr_t); \
                        be = bp+mp->m_len; \
                } \
index b7c5fe0..5419060 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfsmount.h  7.8 (Berkeley) %G%
+ *     @(#)nfsmount.h  7.9 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
 struct nfsmount {
        int     nm_flag;                /* Flags for soft/hard... */
        struct  mount *nm_mountp;       /* Vfs structure for this filesystem */
 struct nfsmount {
        int     nm_flag;                /* Flags for soft/hard... */
        struct  mount *nm_mountp;       /* Vfs structure for this filesystem */
+       int     nm_numgrps;             /* Max. size of groupslist */
        nfsv2fh_t nm_fh;                /* File handle of root dir */
        struct  socket *nm_so;          /* Rpc socket */
        int     nm_sotype;              /* Type of socket */
        int     nm_soproto;             /* and protocol */
        int     nm_soflags;             /* pr_flags for socket protocol */
        struct  mbuf *nm_nam;           /* Addr of server */
        nfsv2fh_t nm_fh;                /* File handle of root dir */
        struct  socket *nm_so;          /* Rpc socket */
        int     nm_sotype;              /* Type of socket */
        int     nm_soproto;             /* and protocol */
        int     nm_soflags;             /* pr_flags for socket protocol */
        struct  mbuf *nm_nam;           /* Addr of server */
-       short   nm_retry;               /* Max retry count */
-       short   nm_rexmit;              /* Rexmit on previous request */
-       short   nm_rtt;                 /* Round trip timer ticks @ NFS_HZ */
-       short   nm_rto;                 /* Current timeout */
-       short   nm_srtt;                /* Smoothed round trip time */
-       short   nm_rttvar;              /* RTT variance */
-       short   nm_currto;              /* Current rto of any nfsmount */
-       short   nm_currexmit;           /* Max rexmit count of nfsmounts */
-       short   nm_sent;                /* Request send count */
-       short   nm_window;              /* Request send window (max) */
-       short   nm_winext;              /* Window incremental value */
-       short   nm_ssthresh;            /* Slowstart threshold */
-       short   nm_salen;               /* Actual length of nm_sockaddr */
+       int     nm_timeo;               /* Init timer for NFSMNT_DUMBTIMR */
+       int     nm_retry;               /* Max retries */
+       int     nm_srtt[4];             /* Timers for rpcs */
+       int     nm_sdrtt[4];
+       int     nm_sent;                /* Request send count */
+       int     nm_cwnd;                /* Request send window */
+       int     nm_timeouts;            /* Request timeouts */
+       int     nm_deadthresh;          /* Threshold of timeouts-->dead server*/
        int     nm_rsize;               /* Max size of read rpc */
        int     nm_wsize;               /* Max size of write rpc */
        int     nm_rsize;               /* Max size of read rpc */
        int     nm_wsize;               /* Max size of write rpc */
+       int     nm_readahead;           /* Num. of blocks to readahead */
+       int     nm_leaseterm;           /* Term (sec) for NQNFS lease */
+       struct nfsnode *nm_tnext;       /* Head of lease timer queue */
+       struct nfsnode *nm_tprev;
+       struct vnode *nm_inprog;        /* Vnode in prog by nqnfs_clientd() */
+       uid_t   nm_authuid;             /* Uid for authenticator */
+       int     nm_authtype;            /* Authenticator type */
+       int     nm_authlen;             /* and length */
+       char    *nm_authstr;            /* Authenticator string */
 };
 
 #ifdef KERNEL
 };
 
 #ifdef KERNEL
@@ -84,6 +89,7 @@ int   nfs_sync __P((
 int    nfs_fhtovp __P((
                struct mount *mp,
                struct fid *fhp,
 int    nfs_fhtovp __P((
                struct mount *mp,
                struct fid *fhp,
+               int setgen,
                struct vnode **vpp));
 int    nfs_vptofh __P((
                struct vnode *vp,
                struct vnode **vpp));
 int    nfs_vptofh __P((
                struct vnode *vp,
index 75c19fd..67f6989 100644 (file)
@@ -7,9 +7,20 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfsnode.h   7.15 (Berkeley) %G%
+ *     @(#)nfsnode.h   7.16 (Berkeley) %G%
  */
 
  */
 
+/*
+ * Silly rename structure that hangs off the nfsnode until the name
+ * can be removed by nfs_inactive()
+ */
+struct sillyrename {
+       struct  ucred *s_cred;
+       struct  vnode *s_dvp;
+       long    s_namlen;
+       char    s_name[20];
+};
+
 /*
  * The nfsnode is the nfs equivalent to ufs's inode. Any similarity
  * is purely coincidental.
 /*
  * The nfsnode is the nfs equivalent to ufs's inode. Any similarity
  * is purely coincidental.
@@ -22,21 +33,38 @@ struct nfsnode {
        struct  nfsnode *n_chain[2];    /* must be first */
        nfsv2fh_t n_fh;                 /* NFS File Handle */
        long    n_flag;                 /* Flag for locking.. */
        struct  nfsnode *n_chain[2];    /* must be first */
        nfsv2fh_t n_fh;                 /* NFS File Handle */
        long    n_flag;                 /* Flag for locking.. */
-       struct  vnode *n_vnode; /* vnode associated with this nfsnode */
-       time_t  n_attrstamp;    /* Time stamp (sec) for attributes */
-       struct  vattr n_vattr;  /* Vnode attribute cache */
-       struct  sillyrename *n_sillyrename;     /* Ptr to silly rename struct */
-       u_long  n_size;         /* Current size of file */
-       time_t  n_mtime;        /* Prev modify time to maintain data cache consistency*/
-       time_t  n_ctime;        /* Prev create time for name cache consistency*/
-       int     n_error;        /* Save write error value */
-       pid_t   n_lockholder;   /* holder of nfsnode lock */
-       pid_t   n_lockwaiter;   /* most recent waiter for nfsnode lock */
-       u_long  n_direofoffset; /* Dir. EOF offset cache */
-       struct  sillyrename n_silly;    /* allocate here since we have room */
-       long    n_spare[7];     /* round up to size 256 */
+       struct  vnode *n_vnode;         /* vnode associated with this node */
+       time_t  n_attrstamp;            /* Time stamp for cached attributes */
+       struct  vattr n_vattr;          /* Vnode attribute cache */
+       struct  sillyrename *n_sillyrename; /* Ptr to silly rename struct */
+       u_long  n_size;                 /* Current size of file */
+       int     n_error;                /* Save write error value */
+       u_long  n_direofoffset;         /* Dir. EOF offset cache */
+       union {
+               struct {
+                       time_t  un_mtime; /* Prev modify time. */
+                       time_t  un_ctime; /* Prev create time. */
+               } un_nfs;
+               struct {
+                       u_quad_t un_brev; /* Modify rev when cached */
+                       u_quad_t un_lrev; /* Modify rev for lease */
+                       time_t  un_expiry; /* Lease expiry time */
+                       struct  nfsnode *un_tnext; /* Nqnfs timer chain */
+                       struct  nfsnode *un_tprev;
+               } un_nqnfs;
+       } n_un;
+       struct  sillyrename n_silly;    /* Silly rename struct */
+       long    n_spare[11];            /* Up to a power of 2 */
 };
 
 };
 
+#define        n_mtime         n_un.un_nfs.un_mtime
+#define        n_ctime         n_un.un_nfs.un_ctime
+#define        n_brev          n_un.un_nqnfs.un_brev
+#define        n_lrev          n_un.un_nqnfs.un_lrev
+#define        n_expiry        n_un.un_nqnfs.un_expiry
+#define        n_tnext         n_un.un_nqnfs.un_tnext
+#define        n_tprev         n_un.un_nqnfs.un_tprev
+
 #define        n_forw          n_chain[0]
 #define        n_back          n_chain[1]
 
 #define        n_forw          n_chain[0]
 #define        n_back          n_chain[1]
 
@@ -50,10 +78,11 @@ struct nfsnode {
 /*
  * Flags for n_flag
  */
 /*
  * Flags for n_flag
  */
-#define        NLOCKED         0x1     /* Lock the node for other local accesses */
-#define        NWANT           0x2     /* Want above lock */
-#define        NMODIFIED       0x4     /* Might have a modified buffer in bio */
-#define        NWRITEERR       0x8     /* Flag write errors so close will know */
+#define        NMODIFIED       0x0004  /* Might have a modified buffer in bio */
+#define        NWRITEERR       0x0008  /* Flag write errors so close will know */
+#define        NQNFSNONCACHE   0x0020  /* Non-cachable lease */
+#define        NQNFSWRITE      0x0040  /* Write lease */
+#define        NQNFSEVICTED    0x0080  /* Has been evicted */
 
 /*
  * Prototypes for NFS vnode operations
 
 /*
  * Prototypes for NFS vnode operations
index 5b64934..165c47b 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfsproto.h  7.8 (Berkeley) %G%
+ *     @(#)nfsproto.h  7.9 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -29,7 +29,7 @@
 #define        NFS_FHSIZE      32
 #define        NFS_MAXPKTHDR   404
 #define NFS_MAXPACKET  (NFS_MAXPKTHDR+NFS_MAXDATA)
 #define        NFS_FHSIZE      32
 #define        NFS_MAXPKTHDR   404
 #define NFS_MAXPACKET  (NFS_MAXPKTHDR+NFS_MAXDATA)
-#define        NFS_NPROCS      18
+#define        NFS_MINPACKET   20
 #define        NFS_FABLKSIZE   512     /* Size in bytes of a block wrt fa_blocks */
 
 /* Stat numbers for rpc returns */
 #define        NFS_FABLKSIZE   512     /* Size in bytes of a block wrt fa_blocks */
 
 /* Stat numbers for rpc returns */
@@ -46,7 +46,7 @@
 #define        NFSERR_FBIG     27
 #define        NFSERR_NOSPC    28
 #define        NFSERR_ROFS     30
 #define        NFSERR_FBIG     27
 #define        NFSERR_NOSPC    28
 #define        NFSERR_ROFS     30
-#define        NFSERR_NAMETOOLONG      63
+#define        NFSERR_NAMETOL  63
 #define        NFSERR_NOTEMPTY 66
 #define        NFSERR_DQUOT    69
 #define        NFSERR_STALE    70
 #define        NFSERR_NOTEMPTY 66
 #define        NFSERR_DQUOT    69
 #define        NFSERR_STALE    70
 #define        NFSPROC_NULL            0
 #define        NFSPROC_GETATTR         1
 #define        NFSPROC_SETATTR         2
 #define        NFSPROC_NULL            0
 #define        NFSPROC_GETATTR         1
 #define        NFSPROC_SETATTR         2
-#define        NFSPROC_ROOT            3               /* Obsolete */
+#define        NFSPROC_NOOP            3
+#define        NFSPROC_ROOT            NFSPROC_NOOP    /* Obsolete */
 #define        NFSPROC_LOOKUP          4
 #define        NFSPROC_READLINK        5
 #define        NFSPROC_READ            6
 #define        NFSPROC_LOOKUP          4
 #define        NFSPROC_READLINK        5
 #define        NFSPROC_READ            6
-#define        NFSPROC_WRITECACHE      7               /* Obsolete */
+#define        NFSPROC_WRITECACHE      NFSPROC_NOOP    /* Obsolete */
 #define        NFSPROC_WRITE           8
 #define        NFSPROC_CREATE          9
 #define        NFSPROC_REMOVE          10
 #define        NFSPROC_WRITE           8
 #define        NFSPROC_CREATE          9
 #define        NFSPROC_REMOVE          10
 #define        NFSPROC_READDIR         16
 #define        NFSPROC_STATFS          17
 
 #define        NFSPROC_READDIR         16
 #define        NFSPROC_STATFS          17
 
+/* NQ nfs numbers */
+#define        NQNFSPROC_READDIRLOOK   18
+#define        NQNFSPROC_GETLEASE      19
+#define        NQNFSPROC_VACATED       20
+#define        NQNFSPROC_EVICTED       21
+
+#define        NFS_NPROCS              22
 /* Conversion macros */
 extern int             vttoif_tab[];
 #define        vtonfs_mode(t,m) \
 /* Conversion macros */
 extern int             vttoif_tab[];
 #define        vtonfs_mode(t,m) \
index d39be73..9a42bbc 100644 (file)
@@ -7,44 +7,39 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfsrvcache.h        7.3 (Berkeley) %G%
+ *     @(#)nfsrvcache.h        7.4 (Berkeley) %G%
  */
 
 /*
  * Definitions for the server recent request cache
  */
 
  */
 
 /*
  * Definitions for the server recent request cache
  */
 
-#define        NFSRVCACHESIZ   128
-#define        NFSRCHSZ        32
+#define        NFSRVCACHESIZ   256
+#define        NFSRCHSZ        256
 
 struct nfsrvcache {
        struct  nfsrvcache *rc_chain[2];        /* Hash chain links */
 
 struct nfsrvcache {
        struct  nfsrvcache *rc_chain[2];        /* Hash chain links */
-       struct  nfsrvcache *rc_next;    /* Lru list */
-       struct  nfsrvcache *rc_prev;
-       int     rc_state;               /* Current state of request */
-       int     rc_flag;                /* Flag bits */
-       struct  mbuf rc_nam;            /* Sockaddr of requestor */
-       u_long  rc_xid;                 /* rpc id number */
-       int     rc_proc;                /* rpc proc number */
-       long    rc_timestamp;           /* Time stamp */
+       struct  nfsrvcache *rc_lchain[2];       /* Lru list */
+       u_long  rc_xid;                         /* rpc id number */
+       time_t  rc_timestamp;                   /* Time stamp */
        union {
        union {
-               struct mbuf *rc_repmb;  /* Reply mbuf list OR */
-               int rc_repstat;         /* Reply status */
+               struct mbuf *ru_repmb;          /* Reply mbuf list OR */
+               int ru_repstat;                 /* Reply status */
        } rc_un;
        } rc_un;
+       union nethostaddr rc_haddr;             /* Host address */
+       short   rc_proc;                        /* rpc proc number */
+       u_char  rc_state;               /* Current state of request */
+       u_char  rc_flag;                /* Flag bits */
 };
 
 #define        rc_forw         rc_chain[0]
 #define        rc_back         rc_chain[1]
 };
 
 #define        rc_forw         rc_chain[0]
 #define        rc_back         rc_chain[1]
-#define        rc_status       rc_un.rc_repstat
-#define        rc_reply        rc_un.rc_repmb
-
-#define        put_at_head(rp) \
-               (rp)->rc_prev->rc_next = (rp)->rc_next; \
-               (rp)->rc_next->rc_prev = (rp)->rc_prev; \
-               (rp)->rc_next = nfsrvcachehead.rc_next; \
-               (rp)->rc_next->rc_prev = (rp); \
-               nfsrvcachehead.rc_next = (rp); \
-               (rp)->rc_prev = &nfsrvcachehead
+#define        rc_next         rc_lchain[0]
+#define        rc_prev         rc_lchain[1]
+#define        rc_reply        rc_un.ru_repmb
+#define        rc_status       rc_un.ru_repstat
+#define        rc_inetaddr     rc_haddr.had_inetaddr
+#define        rc_nam          rc_haddr.had_nam
 
 /* Cache entry states */
 #define        RC_UNUSED       0
 
 /* Cache entry states */
 #define        RC_UNUSED       0
@@ -57,10 +52,13 @@ struct nfsrvcache {
 #define        RC_DOIT         2
 
 /* Flag bits */
 #define        RC_DOIT         2
 
 /* Flag bits */
-#define        RC_LOCKED       0x1
-#define        RC_WANTED       0x2
-#define        RC_REPSTATUS    0x4
-#define        RC_REPMBUF      0x8
+#define        RC_LOCKED       0x01
+#define        RC_WANTED       0x02
+#define        RC_REPSTATUS    0x04
+#define        RC_REPMBUF      0x08
+#define        RC_NQNFS        0x10
+#define        RC_INETADDR     0x20
+#define        RC_NAM          0x40
 
 /* Delay time after completion that request is dropped */
 #define        RC_DELAY        2               /* seconds */
 
 /* Delay time after completion that request is dropped */
 #define        RC_DELAY        2               /* seconds */
index 2a952cb..522692d 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)rpcv2.h     7.4 (Berkeley) %G%
+ *     @(#)rpcv2.h     7.5 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -22,6 +22,7 @@
 #define        RPCAUTH_NULL    0
 #define        RPCAUTH_UNIX    1
 #define        RPCAUTH_SHORT   2
 #define        RPCAUTH_NULL    0
 #define        RPCAUTH_UNIX    1
 #define        RPCAUTH_SHORT   2
+#define        RPCAUTH_NQNFS   300000
 #define        RPCAUTH_MAXSIZ  400
 #define        RPCAUTH_UNIXGIDS 16
 
 #define        RPCAUTH_MAXSIZ  400
 #define        RPCAUTH_UNIXGIDS 16
 
@@ -35,7 +36,7 @@
 #define        RPC_PROCUNAVAIL 3
 #define        RPC_GARBAGE     4               /* I like this one */
 #define        RPC_MISMATCH    0
 #define        RPC_PROCUNAVAIL 3
 #define        RPC_GARBAGE     4               /* I like this one */
 #define        RPC_MISMATCH    0
-#define        RPC_AUTHFAIL    1
+#define        RPC_AUTHERR     1
 
 /* Authentication failures */
 #define        AUTH_BADCRED    1
 
 /* Authentication failures */
 #define        AUTH_BADCRED    1
index da6b82a..bcf0516 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)xdr_subs.h  7.3 (Berkeley) %G%
+ *     @(#)xdr_subs.h  7.4 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
  * These use the MACHINE DEPENDENT routines ntohl, htonl
  * As defined by "XDR: External Data Representation Standard" RFC1014
  */
  * These use the MACHINE DEPENDENT routines ntohl, htonl
  * As defined by "XDR: External Data Representation Standard" RFC1014
  */
-/* From xdr to machine */
+#if BYTE_ORDER == LITTLE_ENDIAN
 #define fxdr_unsigned(t, v)    ((t)ntohl((long)(v)))
 #define fxdr_unsigned(t, v)    ((t)ntohl((long)(v)))
-#define        fxdr_time(f, t)         {((struct timeval *)(t))->tv_sec=ntohl( \
-                               ((struct timeval *)(f))->tv_sec); \
-                               ((struct timeval *)(t))->tv_usec=ntohl( \
-                               ((struct timeval *)(f))->tv_usec);}
+#define        fxdr_time(f, t) { \
+       ((struct timeval *)(t))->tv_sec = \
+               ntohl(((struct timeval *)(f))->tv_sec); \
+       ((struct timeval *)(t))->tv_usec = \
+               ntohl(((struct timeval *)(f))->tv_usec); \
+}
+
+/*
+ * To handle quad conversions, define a struct of two longs and use
+ * ntohl and htonl. Maybe someday there should be ntohq and htonq?
+ */
+union _hq {
+       quad_t  hq;
+       struct {
+               long val[2];
+       } lq;
+};
+#define        fxdr_hyper(f, t) { \
+       ((union _hq *)(t))->lq.val[1] = ntohl(((union _hq *)(f))->lq.val[0]); \
+       ((union _hq *)(t))->lq.val[0] = ntohl(((union _hq *)(f))->lq.val[1]); \
+}
+#define        txdr_hyper(f, t) { \
+       ((union _hq *)(t))->lq.val[0] = htonl(((union _hq *)(f))->lq.val[1]); \
+       ((union _hq *)(t))->lq.val[1] = htonl(((union _hq *)(f))->lq.val[0]); \
+}
 
 
-/* from machine to xdr */
 #define        txdr_unsigned(v)        (htonl((long)(v)))
 #define        txdr_unsigned(v)        (htonl((long)(v)))
-#define        txdr_time(f, t)         {((struct timeval *)(t))->tv_sec=htonl( \
-                               ((struct timeval *)(f))->tv_sec); \
-                               ((struct timeval *)(t))->tv_usec=htonl( \
-                               ((struct timeval *)(f))->tv_usec);}
+#define        txdr_time(f, t) { \
+       ((struct timeval *)(t))->tv_sec = \
+               htonl(((struct timeval *)(f))->tv_sec); \
+       ((struct timeval *)(t))->tv_usec = \
+               htonl(((struct timeval *)(f))->tv_usec); \
+}
+#else  /* BIG_ENDIAN */
+#define fxdr_unsigned(t, v)    ((t)(v))
+#define        fxdr_time(f, t) \
+       *((struct timeval *)(t)) = *((struct timeval *)(f))
+#define        fxdr_hyper(f, t) \
+       *((quad_t *)(t)) = *((quad_t *)(f))
 
 
+#define        txdr_unsigned(v)        ((long)(v))
+#define        txdr_time(f, t) \
+       *((struct timeval *)(t)) = *((struct timeval *)(f))
+#define        txdr_hyper(f, t) \
+       *((quad_t *)(t)) = *((quad_t *)(f))
+#endif /* ENDIAN */