now use modern list management methods
[unix-history] / usr / src / sys / nfs / nfs_serv.c
index c84e995..001bcee 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_serv.c  7.26 (Berkeley) %G%
+ *     @(#)nfs_serv.c  7.60 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
  *     a reply.
  */
 
  *     a reply.
  */
 
-#include "param.h"
-#include "user.h"
-#include "file.h"
-#include "vnode.h"
-#include "mount.h"
-#include "mbuf.h"
-#include "errno.h"
-#include "../ufs/quota.h"
-#include "../ufs/inode.h"
-#include "nfsv2.h"
-#include "nfs.h"
-#include "xdr_subs.h"
-#include "nfsm_subs.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/mbuf.h>
+#include <sys/dirent.h>
+#include <sys/stat.h>
+
+#include <vm/vm.h>
+
+#include <nfs/nfsv2.h>
+#include <nfs/rpcv2.h>
+#include <nfs/nfs.h>
+#include <nfs/xdr_subs.h>
+#include <nfs/nfsm_subs.h>
+#include <nfs/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 };
 
                      NFCHR, NFNON };
 
+/*
+ * nqnfs access service
+ */
+nqnfsrv_access(nfsd, mrep, md, dpos, cred, nam, mrq)
+       struct nfsd *nfsd;
+       struct mbuf *mrep, *md;
+       caddr_t dpos;
+       struct ucred *cred;
+       struct mbuf *nam, **mrq;
+{
+       struct vnode *vp;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0, rdonly, cache, mode = 0;
+       char *cp2;
+       struct mbuf *mb, *mb2, *mreq;
+       u_quad_t frev;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
+               nfsm_reply(0);
+       if (*tl++ == nfs_true)
+               mode |= VREAD;
+       if (*tl++ == nfs_true)
+               mode |= VWRITE;
+       if (*tl == nfs_true)
+               mode |= VEXEC;
+       error = nfsrv_access(vp, mode, cred, rdonly, nfsd->nd_procp);
+       vput(vp);
+       nfsm_reply(0);
+       nfsm_srvdone;
+}
+
 /*
  * nfs getattr service
  */
 /*
  * nfs getattr service
  */
-nfsrv_getattr(mrep, md, dpos, cred, xid, mrq, repstat)
-       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 mbuf *nam, **mrq;
 {
        register struct nfsv2_fattr *fp;
        struct vattr va;
 {
        register struct nfsv2_fattr *fp;
        struct vattr va;
@@ -70,21 +113,23 @@ nfsrv_getattr(mrep, md, dpos, cred, xid, mrq, repstat)
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
-       register u_long *p;
+       register u_long *tl;
        register long t1;
        caddr_t bpos;
        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);
+       nqsrv_getl(vp, NQL_READ);
+       error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
        vput(vp);
        vput(vp);
-       nfsm_reply(NFSX_FATTR);
-       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
        nfsm_srvfillattr;
        nfsm_srvdone;
 }
        nfsm_srvfillattr;
        nfsm_srvdone;
 }
@@ -92,13 +137,12 @@ nfsrv_getattr(mrep, md, dpos, cred, xid, mrq, repstat)
 /*
  * nfs setattr service
  */
 /*
  * nfs setattr service
  */
-nfsrv_setattr(mrep, md, dpos, cred, xid, mrq, repstat)
-       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 mbuf *nam, **mrq;
 {
        struct vattr va;
        register struct vattr *vap = &va;
 {
        struct vattr va;
        register struct vattr *vap = &va;
@@ -107,19 +151,21 @@ nfsrv_setattr(mrep, md, dpos, cred, xid, mrq, repstat)
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
-       register u_long *p;
+       register u_long *tl;
        register long t1;
        caddr_t bpos;
        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(nfsd->nd_nqlflag != NQL_NOVAL));
+       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))
+       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);
        /*
@@ -135,81 +181,113 @@ nfsrv_setattr(mrep, md, dpos, cred, xid, mrq, repstat)
                vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
        if (sp->sa_gid != nfs_xdrneg1)
                vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
                vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
        if (sp->sa_gid != nfs_xdrneg1)
                vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
-       if (sp->sa_size != nfs_xdrneg1)
-               vap->va_size = fxdr_unsigned(u_long, sp->sa_size);
-       /*
-        * The usec field of sa_atime is overloaded with the va_flags field
-        * for 4.4BSD clients. Hopefully other clients always set both the
-        * sec and usec fields to -1 when not setting the atime.
-        */
-       if (sp->sa_atime.tv_sec != nfs_xdrneg1) {
-               vap->va_atime.tv_sec = fxdr_unsigned(long, sp->sa_atime.tv_sec);
-               vap->va_atime.tv_usec = 0;
+       if (nfsd->nd_nqlflag == NQL_NOVAL) {
+               if (sp->sa_nfssize != nfs_xdrneg1)
+                       vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_nfssize);
+               /*
+                * The usec field of sa_atime is overloaded with the va_flags field
+                * for 4.4BSD clients. Hopefully other clients always set both the
+                * sec and usec fields to -1 when not setting the atime.
+                */
+               if (sp->sa_nfsatime.nfs_sec != nfs_xdrneg1) {
+                       vap->va_atime.ts_sec = fxdr_unsigned(long, sp->sa_nfsatime.nfs_sec);
+                       vap->va_atime.ts_nsec = 0;
+               }
+               if (sp->sa_nfsatime.nfs_usec != nfs_xdrneg1)
+                       vap->va_flags = fxdr_unsigned(u_long, sp->sa_nfsatime.nfs_usec);
+               if (sp->sa_nfsmtime.nfs_sec != nfs_xdrneg1)
+                       fxdr_nfstime(&sp->sa_nfsmtime, &vap->va_mtime);
+       } else {
+               fxdr_hyper(&sp->sa_nqsize, &vap->va_size);
+               fxdr_nqtime(&sp->sa_nqatime, &vap->va_atime);
+               fxdr_nqtime(&sp->sa_nqmtime, &vap->va_mtime);
+               vap->va_flags = fxdr_unsigned(u_long, sp->sa_nqflags);
        }
        }
-       if (sp->sa_atime.tv_usec != nfs_xdrneg1)
-               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)) {
+       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);
+       error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
 out:
        vput(vp);
 out:
        vput(vp);
-       nfsm_reply(NFSX_FATTR);
-       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 2*NFSX_UNSIGNED);
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
        nfsm_srvfillattr;
        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)
-       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 mbuf *nam, **mrq;
 {
        register struct nfsv2_fattr *fp;
 {
        register struct nfsv2_fattr *fp;
-       struct nameidata nami;
-       register struct nameidata *ndp = &nami;
+       struct nameidata nd;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        register caddr_t cp;
        struct vnode *vp;
        nfsv2fh_t nfh;
        fhandle_t *fhp;
        register caddr_t cp;
-       register u_long *p;
+       register u_long *tl;
        register long t1;
        caddr_t bpos;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 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;
 
 
-       ndinit(ndp);
        fhp = &nfh.fh_generic;
        fhp = &nfh.fh_generic;
+       if (nfsd->nd_nqlflag != NQL_NOVAL) {
+               nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+               duration2 = fxdr_unsigned(int, *tl);
+       }
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
-       ndp->ni_cred = cred;
-       ndp->ni_nameiop = LOOKUP | LOCKLEAF;
-       if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
+       nd.ni_cnd.cn_cred = cred;
+       nd.ni_cnd.cn_nameiop = LOOKUP;
+       nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
+       if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
+           nfsd->nd_procp))
                nfsm_reply(0);
                nfsm_reply(0);
-       vp = ndp->ni_vp;
+       nqsrv_getl(nd.ni_startdir, NQL_READ);
+       vrele(nd.ni_startdir);
+       FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
+       vp = nd.ni_vp;
        bzero((caddr_t)fhp, sizeof(nfh));
        fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
        if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
                vput(vp);
                nfsm_reply(0);
        }
        bzero((caddr_t)fhp, sizeof(nfh));
        fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
        if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
                vput(vp);
                nfsm_reply(0);
        }
-       error = VOP_GETATTR(vp, vap, cred);
+       if (duration2)
+               (void) nqsrv_getlease(vp, &duration2, NQL_READ, 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(nfsd->nd_nqlflag != NQL_NOVAL) + 5*NFSX_UNSIGNED);
+       if (nfsd->nd_nqlflag != NQL_NOVAL) {
+               if (duration2) {
+                       nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED);
+                       *tl++ = txdr_unsigned(NQL_READ);
+                       *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_srvfhtom(fhp);
-       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
        nfsm_srvfillattr;
        nfsm_srvdone;
 }
        nfsm_srvfillattr;
        nfsm_srvdone;
 }
@@ -217,28 +295,27 @@ nfsrv_lookup(mrep, md, dpos, cred, xid, mrq, repstat)
 /*
  * nfs readlink service
  */
 /*
  * nfs readlink service
  */
-nfsrv_readlink(mrep, md, dpos, cred, xid, mrq, repstat)
-       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 mbuf *nam, **mrq;
 {
        struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
        register struct iovec *ivp = iv;
        register struct mbuf *mp;
 {
        struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
        register struct iovec *ivp = iv;
        register struct mbuf *mp;
-       register u_long *p;
+       register u_long *tl;
        register long t1;
        caddr_t bpos;
        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);
@@ -270,7 +347,8 @@ nfsrv_readlink(mrep, md, dpos, cred, xid, mrq, repstat)
        uiop->uio_resid = len;
        uiop->uio_rw = UIO_READ;
        uiop->uio_segflg = UIO_SYSSPACE;
        uiop->uio_resid = len;
        uiop->uio_rw = UIO_READ;
        uiop->uio_segflg = UIO_SYSSPACE;
-       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) {
+       uiop->uio_procp = (struct proc *)0;
+       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);
        }
@@ -278,6 +356,7 @@ nfsrv_readlink(mrep, md, dpos, cred, xid, mrq, repstat)
                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);
@@ -289,8 +368,8 @@ out:
                tlen = nfsm_rndup(len);
                nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
        }
                tlen = nfsm_rndup(len);
                nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
        }
-       nfsm_build(p, u_long *, NFSX_UNSIGNED);
-       *p = txdr_unsigned(len);
+       nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+       *tl = txdr_unsigned(len);
        mb->m_next = mp3;
        nfsm_srvdone;
 }
        mb->m_next = mp3;
        nfsm_srvdone;
 }
@@ -298,120 +377,125 @@ out:
 /*
  * nfs read service
  */
 /*
  * nfs read service
  */
-nfsrv_read(mrep, md, dpos, cred, xid, mrq, repstat)
-       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 mbuf *nam, **mrq;
 {
        register struct iovec *iv;
        struct iovec *iv2;
        register struct mbuf *m;
        register struct nfsv2_fattr *fp;
 {
        register struct iovec *iv;
        struct iovec *iv2;
        register struct mbuf *m;
        register struct nfsv2_fattr *fp;
-       register u_long *p;
+       register u_long *tl;
        register long t1;
        caddr_t bpos;
        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(p, u_long *, NFSX_UNSIGNED);
-       off = fxdr_unsigned(off_t, *p);
+       if (nfsd->nd_nqlflag == NQL_NOVAL) {
+               nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+               off = (off_t)fxdr_unsigned(u_long, *tl);
+       } else {
+               nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
+               fxdr_hyper(tl, &off);
+       }
        nfsm_srvstrsiz(cnt, NFS_MAXDATA);
        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)) {
+       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;
-       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))
-               m_freem(m3);
+       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(nfsd->nd_nqlflag != NQL_NOVAL)+NFSX_UNSIGNED+nfsm_rndup(cnt));
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
+       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);
        vput(vp);
-       nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED);
-       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
        nfsm_srvfillattr;
        nfsm_srvfillattr;
-       if (uiop->uio_resid > 0) {
-               len -= uiop->uio_resid;
-               if (len > 0) {
-                       tlen = nfsm_rndup(len);
-                       nfsm_adj(m3, cnt-tlen, tlen-len);
-               } else {
-                       m_freem(m3);
-                       m3 = (struct mbuf *)0;
-               }
-       }
-       nfsm_build(p, u_long *, NFSX_UNSIGNED);
-       *p = txdr_unsigned(len);
-       mb->m_next = m3;
+       len -= uiop->uio_resid;
+       tlen = nfsm_rndup(len);
+       if (cnt != tlen || tlen != len)
+               nfsm_adj(mb, cnt-tlen, tlen-len);
+       *tl = txdr_unsigned(len);
        nfsm_srvdone;
 }
 
 /*
  * nfs write service
  */
        nfsm_srvdone;
 }
 
 /*
  * nfs write service
  */
-nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat)
-       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 mbuf *nam, **mrq;
 {
        register struct iovec *ivp;
        register struct mbuf *mp;
 {
        register struct iovec *ivp;
        register struct mbuf *mp;
@@ -419,10 +503,11 @@ nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat)
        struct iovec iv[NFS_MAXIOVEC];
        struct vattr va;
        register struct vattr *vap = &va;
        struct iovec iv[NFS_MAXIOVEC];
        struct vattr va;
        register struct vattr *vap = &va;
-       register u_long *p;
+       register u_long *tl;
        register long t1;
        caddr_t bpos;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, rdonly, cache, siz, len, xfer;
+       int ioflags = IO_SYNC | IO_NODELOCKED;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        struct vnode *vp;
        char *cp2;
        struct mbuf *mb, *mb2, *mreq;
        struct vnode *vp;
@@ -430,14 +515,21 @@ nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat)
        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(p, u_long *, 4*NFSX_UNSIGNED);
-       off = fxdr_unsigned(off_t, *++p);
-       p += 2;
-       len = fxdr_unsigned(long, *p);
+       nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
+       if (nfsd->nd_nqlflag == NQL_NOVAL) {
+               off = (off_t)fxdr_unsigned(u_long, *++tl);
+               tl += 2;
+       } else {
+               fxdr_hyper(tl, &off);
+               tl += 2;
+               if (fxdr_unsigned(u_long, *tl++))
+                       ioflags |= IO_APPEND;
+       }
+       len = fxdr_unsigned(long, *tl);
        if (len > NFS_MAXDATA || len <= 0) {
                error = EBADRPC;
                nfsm_reply(0);
        if (len > NFS_MAXDATA || len <= 0) {
                error = EBADRPC;
                nfsm_reply(0);
@@ -454,15 +546,17 @@ nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat)
                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)) {
+       nqsrv_getl(vp, NQL_WRITE);
+       if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) {
                vput(vp);
                nfsm_reply(0);
        }
        uiop->uio_resid = 0;
        uiop->uio_rw = UIO_WRITE;
        uiop->uio_segflg = UIO_SYSSPACE;
                vput(vp);
                nfsm_reply(0);
        }
        uiop->uio_resid = 0;
        uiop->uio_rw = UIO_WRITE;
        uiop->uio_segflg = UIO_SYSSPACE;
+       uiop->uio_procp = (struct proc *)0;
        /*
         * Do up to NFS_MAXIOVEC mbufs of write each iteration of the
         * loop until done.
        /*
         * Do up to NFS_MAXIOVEC mbufs of write each iteration of the
         * loop until done.
@@ -498,18 +592,21 @@ nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat)
                        nfsm_reply(0);
                }
                uiop->uio_resid = siz;
                        nfsm_reply(0);
                }
                uiop->uio_resid = siz;
-               if (error = VOP_WRITE(vp, uiop, IO_SYNC | IO_NODELOCKED,
-                       cred)) {
+               if (error = VOP_WRITE(vp, uiop, ioflags, cred)) {
                        vput(vp);
                        nfsm_reply(0);
                }
                off = uiop->uio_offset;
        }
                        vput(vp);
                        nfsm_reply(0);
                }
                off = uiop->uio_offset;
        }
-       error = VOP_GETATTR(vp, vap, cred);
+       error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
        vput(vp);
        vput(vp);
-       nfsm_reply(NFSX_FATTR);
-       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
        nfsm_srvfillattr;
        nfsm_srvfillattr;
+       if (nfsd->nd_nqlflag != NQL_NOVAL) {
+               nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
+               txdr_hyper(&vap->va_filerev, tl);
+       }
        nfsm_srvdone;
 }
 
        nfsm_srvdone;
 }
 
@@ -517,96 +614,133 @@ nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat)
  * 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)
-       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 mbuf *nam, **mrq;
 {
        register struct nfsv2_fattr *fp;
        struct vattr va;
        register struct vattr *vap = &va;
 {
        register struct nfsv2_fattr *fp;
        struct vattr va;
        register struct vattr *vap = &va;
-       struct nameidata nami;
-       register struct nameidata *ndp = &nami;
+       register struct nfsv2_sattr *sp;
+       register u_long *tl;
+       struct nameidata nd;
        register caddr_t cp;
        register caddr_t cp;
-       register u_long *p;
        register long t1;
        caddr_t bpos;
        register long t1;
        caddr_t bpos;
-       long rdev;
-       int error = 0;
+       int error = 0, rdev, cache, len, tsize;
        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;
 
 
-       ndinit(ndp);
+       nd.ni_cnd.cn_nameiop = 0;
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
-       ndp->ni_cred = cred;
-       ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF;
-       if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
+       nd.ni_cnd.cn_cred = cred;
+       nd.ni_cnd.cn_nameiop = CREATE;
+       nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
+       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(p, u_long *, NFSX_SATTR);
+       nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL));
        /*
         * Iff doesn't exist, create it
         * otherwise just truncate to 0 length
         *   should I set the mode too ??
         */
        /*
         * Iff doesn't exist, create it
         * otherwise just truncate to 0 length
         *   should I set the mode too ??
         */
-       if (ndp->ni_vp == NULL) {
-               vap->va_type = IFTOVT(fxdr_unsigned(u_long, *p));
+       if (nd.ni_vp == NULL) {
+               vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
                if (vap->va_type == VNON)
                        vap->va_type = VREG;
                if (vap->va_type == VNON)
                        vap->va_type = VREG;
-               vap->va_mode = nfstov_mode(*p);
-               rdev = fxdr_unsigned(long, *(p+3));
-               if (vap->va_type == VREG) {
-                       if (error = VOP_CREATE(ndp, vap))
+               vap->va_mode = nfstov_mode(sp->sa_mode);
+               if (nfsd->nd_nqlflag == NQL_NOVAL)
+                       rdev = fxdr_unsigned(long, sp->sa_nfssize);
+               else
+                       rdev = fxdr_unsigned(long, sp->sa_nqrdev);
+               if (vap->va_type == VREG || vap->va_type == VSOCK) {
+                       p->p_spare[1]--;
+                       vrele(nd.ni_startdir);
+                       nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+                       if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap))
                                nfsm_reply(0);
                                nfsm_reply(0);
+                       FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
                } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
                        vap->va_type == VFIFO) {
                        if (vap->va_type == VCHR && rdev == 0xffffffff)
                                vap->va_type = VFIFO;
                        if (vap->va_type == VFIFO) {
 #ifndef FIFO
                } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
                        vap->va_type == VFIFO) {
                        if (vap->va_type == VCHR && rdev == 0xffffffff)
                                vap->va_type = VFIFO;
                        if (vap->va_type == VFIFO) {
 #ifndef FIFO
-                               VOP_ABORTOP(ndp);
-                               vput(ndp->ni_dvp);
+                               VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+                               vput(nd.ni_dvp);
                                error = ENXIO;
                                error = ENXIO;
-                               nfsm_reply(0);
+                               goto out;
 #endif /* FIFO */
 #endif /* FIFO */
-                       } else if (error = suser(cred, (short *)0)) {
-                               VOP_ABORTOP(ndp);
-                               vput(ndp->ni_dvp);
-                               nfsm_reply(0);
+                       } else if (error = suser(cred, (u_short *)0)) {
+                               VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+                               vput(nd.ni_dvp);
+                               goto out;
                        } else
                                vap->va_rdev = (dev_t)rdev;
                        } else
                                vap->va_rdev = (dev_t)rdev;
-                       if (error = VOP_MKNOD(ndp, vap, cred))
+                       nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+                       if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
+                               p->p_spare[1]--;
+                               vrele(nd.ni_startdir);
+                               nfsm_reply(0);
+                       }
+                       nd.ni_cnd.cn_nameiop = LOOKUP;
+                       nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
+                       nd.ni_cnd.cn_proc = nfsd->nd_procp;
+                       nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred;
+                       if (error = lookup(&nd)) {
+                               free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
                                nfsm_reply(0);
                                nfsm_reply(0);
-                       ndp->ni_nameiop = LOOKUP | LOCKLEAF | HASBUF;
-                       if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
+                       }
+                       FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
+                       if (nd.ni_cnd.cn_flags & ISSYMLINK) {
+                               vrele(nd.ni_dvp);
+                               vput(nd.ni_vp);
+                               VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+                               error = EINVAL;
                                nfsm_reply(0);
                                nfsm_reply(0);
+                       }
                } else {
                } else {
-                       VOP_ABORTOP(ndp);
-                       vput(ndp->ni_dvp);
+                       VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+                       vput(nd.ni_dvp);
                        error = ENXIO;
                        error = ENXIO;
-                       nfsm_reply(0);
+                       goto out;
                }
                }
-               vp = ndp->ni_vp;
+               vp = nd.ni_vp;
        } else {
        } else {
-               vp = ndp->ni_vp;
-               ndp->ni_vp = NULLVP;
-               VOP_ABORTOP(ndp);
-               if (ndp->ni_dvp == vp)
-                       vrele(ndp->ni_dvp);
+               p->p_spare[1]--;
+               vrele(nd.ni_startdir);
+               free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
+               vp = nd.ni_vp;
+               if (nd.ni_dvp == vp)
+                       vrele(nd.ni_dvp);
                else
                else
-                       vput(ndp->ni_dvp);
-               vap->va_size = 0;
-               if (error = VOP_SETATTR(vp, vap, cred)) {
-                       vput(vp);
-                       nfsm_reply(0);
+                       vput(nd.ni_dvp);
+               VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+               if (nfsd->nd_nqlflag == NQL_NOVAL) {
+                       tsize = fxdr_unsigned(long, sp->sa_nfssize);
+                       if (tsize != -1)
+                               vap->va_size = (u_quad_t)tsize;
+                       else
+                               vap->va_size = -1;
+               } else
+                       fxdr_hyper(&sp->sa_nqsize, &vap->va_size);
+               if (vap->va_size != -1) {
+                       nqsrv_getl(vp, NQL_WRITE);
+                       if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) {
+                               vput(vp);
+                               nfsm_reply(0);
+                       }
                }
        }
        bzero((caddr_t)fhp, sizeof(nfh));
                }
        }
        bzero((caddr_t)fhp, sizeof(nfh));
@@ -615,77 +749,87 @@ nfsrv_create(mrep, md, dpos, cred, xid, mrq, repstat)
                vput(vp);
                nfsm_reply(0);
        }
                vput(vp);
                nfsm_reply(0);
        }
-       error = VOP_GETATTR(vp, vap, 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(nfsd->nd_nqlflag != NQL_NOVAL));
        nfsm_srvfhtom(fhp);
        nfsm_srvfhtom(fhp);
-       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
        nfsm_srvfillattr;
        return (error);
 nfsmout:
        nfsm_srvfillattr;
        return (error);
 nfsmout:
-       VOP_ABORTOP(ndp);
-       if (ndp->ni_dvp == ndp->ni_vp)
-               vrele(ndp->ni_dvp);
+       if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags)
+               p->p_spare[1]--, vrele(nd.ni_startdir);
+       VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+       if (nd.ni_dvp == nd.ni_vp)
+               vrele(nd.ni_dvp);
        else
        else
-               vput(ndp->ni_dvp);
-       if (ndp->ni_vp)
-               vput(ndp->ni_vp);
+               vput(nd.ni_dvp);
+       if (nd.ni_vp)
+               vput(nd.ni_vp);
        return (error);
        return (error);
+
+out:
+       p->p_spare[1]--;
+       vrele(nd.ni_startdir);
+       free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
+       nfsm_reply(0);
 }
 
 /*
  * nfs remove service
  */
 }
 
 /*
  * nfs remove service
  */
-nfsrv_remove(mrep, md, dpos, cred, xid, mrq, repstat)
-       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 mbuf *nam, **mrq;
 {
 {
-       struct nameidata nami;
-       register struct nameidata *ndp = &nami;
-       register u_long *p;
+       struct nameidata nd;
+       register u_long *tl;
        register long t1;
        caddr_t bpos;
        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;
 
 
-       ndinit(ndp);
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
-       ndp->ni_cred = cred;
-       ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
-       if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
+       nd.ni_cnd.cn_cred = cred;
+       nd.ni_cnd.cn_nameiop = DELETE;
+       nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
+       if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
+           nfsd->nd_procp))
                nfsm_reply(0);
                nfsm_reply(0);
-       vp = ndp->ni_vp;
+       vp = nd.ni_vp;
        if (vp->v_type == VDIR &&
        if (vp->v_type == VDIR &&
-               (error = suser(cred, (short *)0)))
+               (error = suser(cred, (u_short *)0)))
                goto out;
        /*
                goto out;
        /*
-        * Don't unlink a mounted file.
+        * The root of a mounted filesystem cannot be deleted.
         */
        if (vp->v_flag & VROOT) {
                error = EBUSY;
                goto out;
        }
        if (vp->v_flag & VTEXT)
         */
        if (vp->v_flag & VROOT) {
                error = EBUSY;
                goto out;
        }
        if (vp->v_flag & VTEXT)
-               xrele(vp);      /* try once to free text */
+               (void) vnode_pager_uncache(vp);
 out:
        if (!error) {
 out:
        if (!error) {
-               error = VOP_REMOVE(ndp);
+               nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+               nqsrv_getl(vp, NQL_WRITE);
+               error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
        } else {
        } else {
-               VOP_ABORTOP(ndp);
-               if (ndp->ni_dvp == vp)
-                       vrele(ndp->ni_dvp);
+               VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+               if (nd.ni_dvp == vp)
+                       vrele(nd.ni_dvp);
                else
                else
-                       vput(ndp->ni_dvp);
+                       vput(nd.ni_dvp);
                vput(vp);
        }
        nfsm_reply(0);
                vput(vp);
        }
        nfsm_reply(0);
@@ -695,55 +839,54 @@ out:
 /*
  * nfs rename service
  */
 /*
  * nfs rename service
  */
-nfsrv_rename(mrep, md, dpos, cred, xid, mrq, repstat)
-       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 mbuf *nam, **mrq;
 {
 {
-       register struct nameidata *ndp;
-       register u_long *p;
+       register u_long *tl;
        register long t1;
        caddr_t bpos;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, rdonly, cache, len, len2;
        char *cp2;
        struct mbuf *mb, *mreq;
        char *cp2;
        struct mbuf *mb, *mreq;
-       struct nameidata nami, tond;
+       struct nameidata fromnd, tond;
        struct vnode *fvp, *tvp, *tdvp;
        nfsv2fh_t fnfh, tnfh;
        fhandle_t *ffhp, *tfhp;
        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;
 
 
-       ndp = &nami;
-       ndinit(ndp);
        ffhp = &fnfh.fh_generic;
        tfhp = &tnfh.fh_generic;
        ffhp = &fnfh.fh_generic;
        tfhp = &tnfh.fh_generic;
+       fromnd.ni_cnd.cn_nameiop = 0;
+       tond.ni_cnd.cn_nameiop = 0;
        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++;
-       ndp->ni_cred = cred;
-       ndp->ni_nameiop = DELETE | WANTPARENT;
-       if (error = nfs_namei(ndp, ffhp, len, &md, &dpos))
+       saved_uid = cred->cr_uid;
+       fromnd.ni_cnd.cn_cred = cred;
+       fromnd.ni_cnd.cn_nameiop = DELETE;
+       fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
+       if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md,
+           &dpos, nfsd->nd_procp))
                nfsm_reply(0);
                nfsm_reply(0);
-       fvp = ndp->ni_vp;
+       fvp = fromnd.ni_vp;
        nfsm_srvmtofh(tfhp);
        nfsm_strsiz(len2, NFS_MAXNAMLEN);
        nfsm_srvmtofh(tfhp);
        nfsm_strsiz(len2, NFS_MAXNAMLEN);
-       if (rootflg)
-               cred->cr_uid = 0;
-       ndinit(&tond);
-       crhold(cred);
-       tond.ni_cred = cred;
-       tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
-       if (error = nfs_namei(&tond, tfhp, len2, &md, &dpos)) {
-               VOP_ABORTOP(ndp);
-               vrele(ndp->ni_dvp);
+       cred->cr_uid = saved_uid;
+       tond.ni_cnd.cn_cred = cred;
+       tond.ni_cnd.cn_nameiop = RENAME;
+       tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
+       if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md,
+           &dpos, nfsd->nd_procp)) {
+               VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
+               vrele(fromnd.ni_dvp);
                vrele(fvp);
                goto out1;
        }
                vrele(fvp);
                goto out1;
        }
@@ -757,99 +900,136 @@ nfsrv_rename(mrep, md, dpos, cred, xid, mrq, repstat)
                        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;
                goto out;
        }
        }
        if (fvp->v_mount != tdvp->v_mount) {
                error = EXDEV;
                goto out;
        }
-       if (fvp == tdvp || fvp == tvp)
+       if (fvp == tdvp)
                error = EINVAL;
                error = EINVAL;
+       /*
+        * If source is the same as the destination (that is the
+        * same vnode with the same name in the same directory),
+        * then there is nothing to do.
+        */
+       if (fvp == tvp && fromnd.ni_dvp == tdvp &&
+           fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
+           !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
+             fromnd.ni_cnd.cn_namelen))
+               error = -1;
 out:
        if (!error) {
 out:
        if (!error) {
-               VREF(ndp->ni_cdir);
-               VREF(tond.ni_cdir);
-               error = VOP_RENAME(ndp, &tond);
-               vrele(ndp->ni_cdir);
-               vrele(tond.ni_cdir);
+               nqsrv_getl(fromnd.ni_dvp, NQL_WRITE);
+               nqsrv_getl(tdvp, NQL_WRITE);
+               if (tvp)
+                       nqsrv_getl(tvp, NQL_WRITE);
+               error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
+                                  tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
        } else {
        } else {
-               VOP_ABORTOP(&tond);
+               VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
                if (tdvp == tvp)
                        vrele(tdvp);
                else
                        vput(tdvp);
                if (tvp)
                        vput(tvp);
                if (tdvp == tvp)
                        vrele(tdvp);
                else
                        vput(tdvp);
                if (tvp)
                        vput(tvp);
-               VOP_ABORTOP(ndp);
-               vrele(ndp->ni_dvp);
+               VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
+               vrele(fromnd.ni_dvp);
                vrele(fvp);
        }
                vrele(fvp);
        }
+       p->p_spare[1]--;
+       vrele(tond.ni_startdir);
+       FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
 out1:
 out1:
-       crfree(cred);
+       p->p_spare[1]--;
+       vrele(fromnd.ni_startdir);
+       FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
        nfsm_reply(0);
        return (error);
        nfsm_reply(0);
        return (error);
+
 nfsmout:
 nfsmout:
-       VOP_ABORTOP(ndp);
-       vrele(ndp->ni_dvp);
-       vrele(fvp);
+       if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) {
+               p->p_spare[1]--;
+               vrele(tond.ni_startdir);
+               FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
+       }
+       if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) {
+               p->p_spare[1]--;
+               vrele(fromnd.ni_startdir);
+               FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
+               VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
+               vrele(fromnd.ni_dvp);
+               vrele(fvp);
+       }
        return (error);
 }
 
 /*
  * nfs link service
  */
        return (error);
 }
 
 /*
  * nfs link service
  */
-nfsrv_link(mrep, md, dpos, cred, xid, mrq, repstat)
-       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 mbuf *nam, **mrq;
 {
 {
-       struct nameidata nami;
-       register struct nameidata *ndp = &nami;
-       register u_long *p;
+       struct nameidata nd;
+       register u_long *tl;
        register long t1;
        caddr_t bpos;
        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;
 
 
-       ndinit(ndp);
        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;
                goto out1;
-       ndp->ni_cred = cred;
-       ndp->ni_nameiop = CREATE | LOCKPARENT;
-       if (error = nfs_namei(ndp, dfhp, len, &md, &dpos))
+       nd.ni_cnd.cn_cred = cred;
+       nd.ni_cnd.cn_nameiop = CREATE;
+       nd.ni_cnd.cn_flags = LOCKPARENT;
+       if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos,
+           nfsd->nd_procp))
                goto out1;
                goto out1;
-       xp = ndp->ni_vp;
+       xp = nd.ni_vp;
        if (xp != NULL) {
                error = EEXIST;
                goto out;
        }
        if (xp != NULL) {
                error = EEXIST;
                goto out;
        }
-       xp = ndp->ni_dvp;
+       xp = nd.ni_dvp;
        if (vp->v_mount != xp->v_mount)
                error = EXDEV;
 out:
        if (!error) {
        if (vp->v_mount != xp->v_mount)
                error = EXDEV;
 out:
        if (!error) {
-               error = VOP_LINK(vp, ndp);
+               nqsrv_getl(vp, NQL_WRITE);
+               nqsrv_getl(xp, NQL_WRITE);
+               error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
        } else {
        } else {
-               VOP_ABORTOP(ndp);
-               if (ndp->ni_dvp == ndp->ni_vp)
-                       vrele(ndp->ni_dvp);
+               VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+               if (nd.ni_dvp == nd.ni_vp)
+                       vrele(nd.ni_dvp);
                else
                else
-                       vput(ndp->ni_dvp);
-               if (ndp->ni_vp)
-                       vrele(ndp->ni_vp);
+                       vput(nd.ni_dvp);
+               if (nd.ni_vp)
+                       vrele(nd.ni_vp);
        }
 out1:
        vrele(vp);
        }
 out1:
        vrele(vp);
@@ -860,37 +1040,38 @@ out1:
 /*
  * nfs symbolic link service
  */
 /*
  * nfs symbolic link service
  */
-nfsrv_symlink(mrep, md, dpos, cred, xid, mrq, repstat)
-       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 mbuf *nam, **mrq;
 {
        struct vattr va;
 {
        struct vattr va;
-       struct nameidata nami;
-       register struct nameidata *ndp = &nami;
+       struct nameidata nd;
        register struct vattr *vap = &va;
        register struct vattr *vap = &va;
-       register u_long *p;
+       register u_long *tl;
        register long t1;
        register long t1;
+       struct nfsv2_sattr *sp;
        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;
 
        pathcp = (char *)0;
-       ndinit(ndp);
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
-       ndp->ni_cred = cred;
-       ndp->ni_nameiop = CREATE | LOCKPARENT;
-       if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
+       nd.ni_cnd.cn_cred = cred;
+       nd.ni_cnd.cn_nameiop = CREATE;
+       nd.ni_cnd.cn_flags = LOCKPARENT;
+       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);
@@ -902,34 +1083,37 @@ nfsrv_symlink(mrep, md, dpos, cred, xid, mrq, repstat)
        io.uio_iovcnt = 1;
        io.uio_segflg = UIO_SYSSPACE;
        io.uio_rw = UIO_READ;
        io.uio_iovcnt = 1;
        io.uio_segflg = UIO_SYSSPACE;
        io.uio_rw = UIO_READ;
+       io.uio_procp = (struct proc *)0;
        nfsm_mtouio(&io, len2);
        nfsm_mtouio(&io, len2);
+       nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL));
        *(pathcp + len2) = '\0';
        *(pathcp + len2) = '\0';
-       if (ndp->ni_vp) {
-               VOP_ABORTOP(ndp);
-               if (ndp->ni_dvp == ndp->ni_vp)
-                       vrele(ndp->ni_dvp);
+       if (nd.ni_vp) {
+               VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+               if (nd.ni_dvp == nd.ni_vp)
+                       vrele(nd.ni_dvp);
                else
                else
-                       vput(ndp->ni_dvp);
-               vrele(ndp->ni_vp);
+                       vput(nd.ni_dvp);
+               vrele(nd.ni_vp);
                error = EEXIST;
                goto out;
        }
        VATTR_NULL(vap);
                error = EEXIST;
                goto out;
        }
        VATTR_NULL(vap);
-       vap->va_mode = 0777;
-       error = VOP_SYMLINK(ndp, vap, pathcp);
+       vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
+       nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+       error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
 out:
        if (pathcp)
                FREE(pathcp, M_TEMP);
        nfsm_reply(0);
        return (error);
 nfsmout:
 out:
        if (pathcp)
                FREE(pathcp, M_TEMP);
        nfsm_reply(0);
        return (error);
 nfsmout:
-       VOP_ABORTOP(ndp);
-       if (ndp->ni_dvp == ndp->ni_vp)
-               vrele(ndp->ni_dvp);
+       VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+       if (nd.ni_dvp == nd.ni_vp)
+               vrele(nd.ni_dvp);
        else
        else
-               vput(ndp->ni_dvp);
-       if (ndp->ni_vp);
-               vrele(ndp->ni_vp);
+               vput(nd.ni_dvp);
+       if (nd.ni_vp)
+               vrele(nd.ni_vp);
        if (pathcp)
                FREE(pathcp, M_TEMP);
        return (error);
        if (pathcp)
                FREE(pathcp, M_TEMP);
        return (error);
@@ -938,112 +1122,113 @@ nfsmout:
 /*
  * nfs mkdir service
  */
 /*
  * nfs mkdir service
  */
-nfsrv_mkdir(mrep, md, dpos, cred, xid, mrq, repstat)
-       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 mbuf *nam, **mrq;
 {
        struct vattr va;
        register struct vattr *vap = &va;
        register struct nfsv2_fattr *fp;
 {
        struct vattr va;
        register struct vattr *vap = &va;
        register struct nfsv2_fattr *fp;
-       struct nameidata nami;
-       register struct nameidata *ndp = &nami;
+       struct nameidata nd;
        register caddr_t cp;
        register caddr_t cp;
-       register u_long *p;
+       register u_long *tl;
        register long t1;
        caddr_t bpos;
        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;
 
 
-       ndinit(ndp);
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
-       ndp->ni_cred = cred;
-       ndp->ni_nameiop = CREATE | LOCKPARENT;
-       if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
+       nd.ni_cnd.cn_cred = cred;
+       nd.ni_cnd.cn_nameiop = CREATE;
+       nd.ni_cnd.cn_flags = LOCKPARENT;
+       if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
+           nfsd->nd_procp))
                nfsm_reply(0);
                nfsm_reply(0);
-       nfsm_disect(p, u_long *, NFSX_UNSIGNED);
+       nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
        VATTR_NULL(vap);
        vap->va_type = VDIR;
        VATTR_NULL(vap);
        vap->va_type = VDIR;
-       vap->va_mode = nfstov_mode(*p++);
-       vp = ndp->ni_vp;
+       vap->va_mode = nfstov_mode(*tl++);
+       vp = nd.ni_vp;
        if (vp != NULL) {
        if (vp != NULL) {
-               VOP_ABORTOP(ndp);
-               if (ndp->ni_dvp == vp)
-                       vrele(ndp->ni_dvp);
+               VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+               if (nd.ni_dvp == vp)
+                       vrele(nd.ni_dvp);
                else
                else
-                       vput(ndp->ni_dvp);
+                       vput(nd.ni_dvp);
                vrele(vp);
                error = EEXIST;
                nfsm_reply(0);
        }
                vrele(vp);
                error = EEXIST;
                nfsm_reply(0);
        }
-       if (error = VOP_MKDIR(ndp, vap))
+       nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+       if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap))
                nfsm_reply(0);
                nfsm_reply(0);
-       vp = ndp->ni_vp;
+       vp = nd.ni_vp;
        bzero((caddr_t)fhp, sizeof(nfh));
        fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
        if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
                vput(vp);
                nfsm_reply(0);
        }
        bzero((caddr_t)fhp, sizeof(nfh));
        fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
        if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
                vput(vp);
                nfsm_reply(0);
        }
-       error = VOP_GETATTR(vp, vap, 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(nfsd->nd_nqlflag != NQL_NOVAL));
        nfsm_srvfhtom(fhp);
        nfsm_srvfhtom(fhp);
-       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
        nfsm_srvfillattr;
        return (error);
 nfsmout:
        nfsm_srvfillattr;
        return (error);
 nfsmout:
-       VOP_ABORTOP(ndp);
-       if (ndp->ni_dvp == ndp->ni_vp)
-               vrele(ndp->ni_dvp);
+       VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+       if (nd.ni_dvp == nd.ni_vp)
+               vrele(nd.ni_dvp);
        else
        else
-               vput(ndp->ni_dvp);
-       if (ndp->ni_vp)
-               vrele(ndp->ni_vp);
+               vput(nd.ni_dvp);
+       if (nd.ni_vp)
+               vrele(nd.ni_vp);
        return (error);
 }
 
 /*
  * nfs rmdir service
  */
        return (error);
 }
 
 /*
  * nfs rmdir service
  */
-nfsrv_rmdir(mrep, md, dpos, cred, xid, mrq, repstat)
-       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 mbuf *nam, **mrq;
 {
 {
-       struct nameidata nami;
-       register struct nameidata *ndp = &nami;
-       register u_long *p;
+       register u_long *tl;
        register long t1;
        caddr_t bpos;
        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;
+       u_quad_t frev;
 
 
-       ndinit(ndp);
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
        nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
-       ndp->ni_cred = cred;
-       ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
-       if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
+       nd.ni_cnd.cn_cred = cred;
+       nd.ni_cnd.cn_nameiop = DELETE;
+       nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
+       if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
+           nfsd->nd_procp))
                nfsm_reply(0);
                nfsm_reply(0);
-       vp = ndp->ni_vp;
+       vp = nd.ni_vp;
        if (vp->v_type != VDIR) {
                error = ENOTDIR;
                goto out;
        if (vp->v_type != VDIR) {
                error = ENOTDIR;
                goto out;
@@ -1051,24 +1236,26 @@ nfsrv_rmdir(mrep, md, dpos, cred, xid, mrq, repstat)
        /*
         * No rmdir "." please.
         */
        /*
         * No rmdir "." please.
         */
-       if (ndp->ni_dvp == vp) {
+       if (nd.ni_dvp == vp) {
                error = EINVAL;
                goto out;
        }
        /*
                error = EINVAL;
                goto out;
        }
        /*
-        * Don't unlink a mounted file.
+        * The root of a mounted filesystem cannot be deleted.
         */
        if (vp->v_flag & VROOT)
                error = EBUSY;
 out:
        if (!error) {
         */
        if (vp->v_flag & VROOT)
                error = EBUSY;
 out:
        if (!error) {
-               error = VOP_RMDIR(ndp);
+               nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+               nqsrv_getl(vp, NQL_WRITE);
+               error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
        } else {
        } else {
-               VOP_ABORTOP(ndp);
-               if (ndp->ni_dvp == ndp->ni_vp)
-                       vrele(ndp->ni_dvp);
+               VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+               if (nd.ni_dvp == nd.ni_vp)
+                       vrele(nd.ni_dvp);
                else
                else
-                       vput(ndp->ni_dvp);
+                       vput(nd.ni_dvp);
                vput(vp);
        }
        nfsm_reply(0);
                vput(vp);
        }
        nfsm_reply(0);
@@ -1078,7 +1265,7 @@ out:
 /*
  * nfs readdir service
  * - mallocs what it thinks is enough to read
 /*
  * nfs readdir service
  * - mallocs what it thinks is enough to read
- *     count rounded up to a multiple of DIRBLKSIZ <= NFS_MAXREADDIR
+ *     count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
  * - calls VOP_READDIR()
  * - loops around building the reply
  *     if the output generated exceeds count break out of loop
  * - calls VOP_READDIR()
  * - loops around building the reply
  *     if the output generated exceeds count break out of loop
@@ -1088,13 +1275,14 @@ out:
  *     reads nothing
  * - as such one readdir rpc will return eof false although you are there
  *     and then the next will return eof
  *     reads nothing
  * - as such one readdir rpc will return eof false although you are there
  *     and then the next will return eof
- * - it trims out records with d_ino == 0
+ * - it trims out records with d_fileno == 0
  *     this doesn't matter for Unix clients, but they might confuse clients
  *     for other os'.
  * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
  *     than requested, but this may not apply to all filesystems. For
  *     example, client NFS does not { although it is never remote mounted
  *     anyhow }
  *     this doesn't matter for Unix clients, but they might confuse clients
  *     for other os'.
  * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
  *     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 ...
@@ -1103,51 +1291,56 @@ 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)
-       struct mbuf **mrq;
+struct flrep {
+       u_long fl_cachable;
+       u_long fl_duration;
+       u_long fl_frev[2];
+       nfsv2fh_t fl_nfh;
+       u_long fl_fattr[NFSX_NQFATTR / sizeof (u_long)];
+};
+
+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 mbuf *nam, **mrq;
 {
        register char *bp, *be;
        register struct mbuf *mp;
 {
        register char *bp, *be;
        register struct mbuf *mp;
-       register struct direct *dp;
+       register struct dirent *dp;
        register caddr_t cp;
        register caddr_t cp;
-       register u_long *p;
+       register u_long *tl;
        register long t1;
        caddr_t bpos;
        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;
-       u_long on;
-       char *rbuf;
-       off_t off, toff;
+       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, off, toff;
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
 
        fhp = &nfh.fh_generic;
        nfsm_srvmtofh(fhp);
-       nfsm_disect(p, u_long *, 2*NFSX_UNSIGNED);
-       toff = fxdr_unsigned(off_t, *p++);
-       off = (toff & ~(DIRBLKSIZ-1));
-       on = (toff & (DIRBLKSIZ-1));
-       cnt = fxdr_unsigned(int, *p);
-       siz = ((cnt+DIRBLKSIZ-1) & ~(DIRBLKSIZ-1));
+       nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
+       toff = fxdr_unsigned(u_long, *tl++);
+       off = (toff & ~(NFS_DIRBLKSIZ-1));
+       on = (toff & (NFS_DIRBLKSIZ-1));
+       cnt = fxdr_unsigned(int, *tl);
+       siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1));
        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)) {
+       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);
        }
@@ -1158,17 +1351,22 @@ again:
        iv.iov_len = fullsiz;
        io.uio_iov = &iv;
        io.uio_iovcnt = 1;
        iv.iov_len = fullsiz;
        io.uio_iov = &iv;
        io.uio_iovcnt = 1;
-       io.uio_offset = off;
+       io.uio_offset = (off_t)off;
        io.uio_resid = fullsiz;
        io.uio_segflg = UIO_SYSSPACE;
        io.uio_rw = UIO_READ;
        io.uio_resid = fullsiz;
        io.uio_segflg = UIO_SYSSPACE;
        io.uio_rw = UIO_READ;
-       error = VOP_READDIR(vp, &io, cred, &eofflag);
-       off = io.uio_offset;
+       io.uio_procp = (struct proc *)0;
+       error = VOP_READDIR(vp, &io, cred);
+       off = (off_t)io.uio_offset;
        if (error) {
                vrele(vp);
                free((caddr_t)rbuf, M_TEMP);
                nfsm_reply(0);
        }
        if (error) {
                vrele(vp);
                free((caddr_t)rbuf, M_TEMP);
                nfsm_reply(0);
        }
+       if (io.uio_resid < fullsiz)
+               eofflag = 0;
+       else
+               eofflag = 1;
        if (io.uio_resid) {
                siz -= io.uio_resid;
 
        if (io.uio_resid) {
                siz -= io.uio_resid;
 
@@ -1179,9 +1377,9 @@ again:
                if (siz == 0) {
                        vrele(vp);
                        nfsm_reply(2*NFSX_UNSIGNED);
                if (siz == 0) {
                        vrele(vp);
                        nfsm_reply(2*NFSX_UNSIGNED);
-                       nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
-                       *p++ = nfs_false;
-                       *p = nfs_true;
+                       nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
+                       *tl++ = nfs_false;
+                       *tl = nfs_true;
                        FREE((caddr_t)rbuf, M_TEMP);
                        return (0);
                }
                        FREE((caddr_t)rbuf, M_TEMP);
                        return (0);
                }
@@ -1193,10 +1391,10 @@ again:
         */
        cpos = rbuf + on;
        cend = rbuf + siz;
         */
        cpos = rbuf + on;
        cend = rbuf + siz;
-       dp = (struct direct *)cpos;
-       while (cpos < cend && dp->d_ino == 0) {
+       dp = (struct dirent *)cpos;
+       while (cpos < cend && dp->d_fileno == 0) {
                cpos += dp->d_reclen;
                cpos += dp->d_reclen;
-               dp = (struct direct *)cpos;
+               dp = (struct dirent *)cpos;
        }
        if (cpos >= cend) {
                toff = off;
        }
        if (cpos >= cend) {
                toff = off;
@@ -1207,42 +1405,274 @@ again:
 
        cpos = rbuf + on;
        cend = rbuf + siz;
 
        cpos = rbuf + on;
        cend = rbuf + siz;
-       dp = (struct direct *)cpos;
-       vrele(vp);
+       dp = (struct dirent *)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);
+
+       /* Loop through the records and build reply */
+       while (cpos < cend) {
+               if (dp->d_fileno != 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 dirent entry.
+                        */
+                       nfsm_clget;
+                       *tl = nfs_true;
+                       bp += NFSX_UNSIGNED;
+                       nfsm_clget;
+                       *tl = txdr_unsigned(dp->d_fileno);
+                       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 dirent *)cpos;
+       }
+       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 dirent *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;
+       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, toff;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED);
+       toff = fxdr_unsigned(u_long, *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_t)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);
+       off = (u_long)io.uio_offset;
+       if (error) {
+               vrele(vp);
+               free((caddr_t)rbuf, M_TEMP);
+               nfsm_reply(0);
+       }
+       if (io.uio_resid < fullsiz)
+               eofflag = 0;
+       else
+               eofflag = 1;
+       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 dirent *)cpos;
+       while (cpos < cend && dp->d_fileno == 0) {
+               cpos += dp->d_reclen;
+               dp = (struct dirent *)cpos;
+       }
+       if (cpos >= cend) {
+               toff = off;
+               siz = fullsiz;
+               on = 0;
+               goto again;
+       }
+
+       cpos = rbuf + on;
+       cend = rbuf + siz;
+       dp = (struct dirent *)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) {
 
        /* Loop through the records and build reply */
        while (cpos < cend) {
-               if (dp->d_ino != 0) {
+               if (dp->d_fileno != 0) {
                        nlen = dp->d_namlen;
                        rem = nfsm_rndup(nlen)-nlen;
        
                        /*
                        nlen = dp->d_namlen;
                        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);
+                       if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
+                               goto invalid;
+                       bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t));
+                       fl.fl_nfh.fh_generic.fh_fsid =
+                               nvp->v_mount->mnt_stat.f_fsid;
+                       if (VFS_VPTOFH(nvp, &fl.fl_nfh.fh_generic.fh_fid)) {
+                               vput(nvp);
+                               goto invalid;
+                       }
+                       if (duration2) {
+                               (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);
+                       } else
+                               fl.fl_duration = 0;
+                       if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) {
+                               vput(nvp);
+                               goto invalid;
+                       }
+                       vput(nvp);
+                       fp = (struct nfsv2_fattr *)&fl.fl_fattr;
+                       nfsm_srvfillattr;
+                       len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH
+                               + NFSX_NQFATTR);
                        if (len > cnt) {
                                eofflag = 0;
                                break;
                        }
                        if (len > cnt) {
                                eofflag = 0;
                                break;
                        }
-       
-                       /* Build the directory record xdr from the direct entry */
+                       /*
+                        * Build the directory record xdr from
+                        * the dirent entry.
+                        */
                        nfsm_clget;
                        nfsm_clget;
-                       *p = nfs_true;
+                       *tl = nfs_true;
                        bp += NFSX_UNSIGNED;
                        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;
                        nfsm_clget;
-                       *p = txdr_unsigned(dp->d_ino);
+                       *tl = txdr_unsigned(dp->d_fileno);
                        bp += NFSX_UNSIGNED;
                        nfsm_clget;
                        bp += NFSX_UNSIGNED;
                        nfsm_clget;
-                       *p = txdr_unsigned(nlen);
+                       *tl = txdr_unsigned(nlen);
                        bp += NFSX_UNSIGNED;
        
                        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) {
@@ -1264,25 +1694,29 @@ again:
        
                        /* Finish off the record */
                        toff += dp->d_reclen;
        
                        /* Finish off the record */
                        toff += dp->d_reclen;
-                       *p = txdr_unsigned(toff);
+                       *tl = txdr_unsigned(toff);
                        bp += NFSX_UNSIGNED;
                } else
                        bp += NFSX_UNSIGNED;
                } else
+invalid:
                        toff += dp->d_reclen;
                cpos += dp->d_reclen;
                        toff += dp->d_reclen;
                cpos += dp->d_reclen;
-               dp = (struct direct *)cpos;
+               dp = (struct dirent *)cpos;
        }
        }
+       vrele(vp);
        nfsm_clget;
        nfsm_clget;
-       *p = nfs_false;
+       *tl = nfs_false;
        bp += NFSX_UNSIGNED;
        nfsm_clget;
        if (eofflag)
        bp += NFSX_UNSIGNED;
        nfsm_clget;
        if (eofflag)
-               *p = nfs_true;
+               *tl = nfs_true;
        else
        else
-               *p = nfs_false;
+               *tl = nfs_false;
        bp += NFSX_UNSIGNED;
        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;
 }
@@ -1290,41 +1724,46 @@ again:
 /*
  * nfs statfs service
  */
 /*
  * nfs statfs service
  */
-nfsrv_statfs(mrep, md, dpos, cred, xid, mrq, repstat)
-       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 mbuf *nam, **mrq;
 {
        register struct statfs *sf;
        register struct nfsv2_statfs *sfp;
 {
        register struct statfs *sf;
        register struct nfsv2_statfs *sfp;
-       register u_long *p;
+       register u_long *tl;
        register long t1;
        caddr_t bpos;
        register long t1;
        caddr_t bpos;
-       int error = 0;
+       int error = 0, rdonly, cache, isnq;
        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;
 
        fhp = &nfh.fh_generic;
+       isnq = (nfsd->nd_nqlflag != NQL_NOVAL);
        nfsm_srvmtofh(fhp);
        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);
+       error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp);
        vput(vp);
        vput(vp);
-       nfsm_reply(NFSX_STATFS);
-       nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS);
-       sfp->sf_tsize = txdr_unsigned(NFS_MAXDATA);
-       sfp->sf_bsize = txdr_unsigned(sf->f_fsize);
+       nfsm_reply(NFSX_STATFS(isnq));
+       nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq));
+       sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
+       sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
        sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
        sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
        sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
        sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
        sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
        sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
+       if (isnq) {
+               sfp->sf_files = txdr_unsigned(sf->f_files);
+               sfp->sf_ffree = txdr_unsigned(sf->f_ffree);
+       }
        nfsm_srvdone;
 }
 
        nfsm_srvdone;
 }
 
@@ -1332,19 +1771,18 @@ nfsrv_statfs(mrep, md, dpos, cred, xid, mrq, repstat)
  * 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)
-       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 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);
 }
@@ -1353,19 +1791,22 @@ nfsrv_null(mrep, md, dpos, cred, xid, mrq, repstat)
  * No operation, used for obsolete procedures
  */
 /* ARGSUSED */
  * No operation, used for obsolete procedures
  */
 /* ARGSUSED */
-nfsrv_noop(mrep, md, dpos, cred, xid, mrq, repstat)
-       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 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);
 }
@@ -1374,49 +1815,46 @@ nfsrv_noop(mrep, md, dpos, cred, xid, mrq, repstat)
  * 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)
+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 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)) &&
-                       vp->v_type != VCHR &&
-                       vp->v_type != VBLK &&
-                       vp->v_type != VSOCK)
+               if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
+                       switch (vp->v_type) {
+                       case VREG: case VDIR: case VLNK:
                                return (EROFS);
                                return (EROFS);
+                       }
+               }
                /*
                 * If there's shared text associated with
                 * the inode, try to free it up once.  If
                 * we fail, we can't allow writing.
                 */
                /*
                 * If there's shared text associated with
                 * the inode, try to free it up once.  If
                 * we fail, we can't allow writing.
                 */
-               if (vp->v_flag & VTEXT)
-                       xrele(vp);
-               if (vp->v_flag & VTEXT)
+               if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
                        return (ETXTBSY);
                        return (ETXTBSY);
-               if (error = VOP_GETATTR(vp, &vattr, cred))
-                       return (error);
-               if (cred->cr_uid == vattr.va_uid)
-                       return (0);
-       } else {
-               if (error = VOP_GETATTR(vp, &vattr, cred))
-                       return (error);
-               if (cred->cr_uid == vattr.va_uid)
-                       return (0);
        }
        }
-       return (VOP_ACCESS(vp, flags, cred));
+       if (error = VOP_GETATTR(vp, &vattr, cred, p))
+               return (error);
+       if ((error = VOP_ACCESS(vp, flags, cred, p)) &&
+           cred->cr_uid != vattr.va_uid)
+               return (error);
+       return (0);
 }
 }