add pathconf
[unix-history] / usr / src / sys / nfs / nfs_subs.c
index 6dc0d9b..20e7cc1 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_subs.c  7.46 (Berkeley) %G%
+ *     @(#)nfs_subs.c  7.70 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
  * the nfs op functions. They do things like create the rpc header and
  * copy data between mbuf chains and uio lists.
  */
  * the nfs op functions. They do things like create the rpc header and
  * copy data between mbuf chains and uio lists.
  */
-#include "param.h"
-#include "proc.h"
-#include "filedesc.h"
-#include "systm.h"
-#include "kernel.h"
-#include "mount.h"
-#include "file.h"
-#include "vnode.h"
-#include "namei.h"
-#include "mbuf.h"
-#include "map.h"
-#include "socket.h"
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/namei.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
 
 
-#include "ufs/ufs/quota.h"
-#include "ufs/ufs/inode.h"
-#include "ufs/ufs/ufsmount.h"
+#include <nfs/rpcv2.h>
+#include <nfs/nfsv2.h>
+#include <nfs/nfsnode.h>
+#include <nfs/nfs.h>
+#include <nfs/xdr_subs.h>
+#include <nfs/nfsm_subs.h>
+#include <nfs/nfsmount.h>
+#include <nfs/nqnfs.h>
+#include <nfs/nfsrtt.h>
 
 
-#include "rpcv2.h"
-#include "nfsv2.h"
-#include "nfsnode.h"
-#include "nfs.h"
-#include "xdr_subs.h"
-#include "nfsm_subs.h"
-#include "nfsmount.h"
-#include "nqnfs.h"
-#include "nfsrtt.h"
+#include <miscfs/specfs/specdev.h>
+
+#include <netinet/in.h>
+#ifdef ISO
+#include <netiso/iso.h>
+#endif
 
 #define TRUE   1
 #define        FALSE   0
 
 #define TRUE   1
 #define        FALSE   0
@@ -60,11 +61,10 @@ u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
 static u_long nfs_xid = 0;
 enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
 static u_long nfs_xid = 0;
 enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
+extern struct queue_entry nfs_bufq;
 extern struct nfsreq nfsreqh;
 extern int nqnfs_piggy[NFS_NPROCS];
 extern struct nfsrtt nfsrtt;
 extern struct nfsreq nfsreqh;
 extern int nqnfs_piggy[NFS_NPROCS];
 extern struct nfsrtt nfsrtt;
-extern union nqsrvthead nqthead;
-extern union nqsrvthead nqfhead[NQLCHSZ];
 extern time_t nqnfsstarttime;
 extern u_long nqnfs_prog, nqnfs_vers;
 extern int nqsrv_clockskew;
 extern time_t nqnfsstarttime;
 extern u_long nqnfs_prog, nqnfs_vers;
 extern int nqsrv_clockskew;
@@ -210,14 +210,14 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
                                mb->m_len = 0;
                                bpos = mtod(mb, caddr_t);
                        }
                                mb->m_len = 0;
                                bpos = mtod(mb, caddr_t);
                        }
-                       i = MIN(siz, M_TRAILINGSPACE(mb));
+                       i = min(siz, M_TRAILINGSPACE(mb));
                        bcopy(auth_str, bpos, i);
                        mb->m_len += i;
                        auth_str += i;
                        bpos += i;
                        siz -= i;
                }
                        bcopy(auth_str, bpos, i);
                        mb->m_len += i;
                        auth_str += i;
                        bpos += i;
                        siz -= i;
                }
-               if ((siz = nfsm_rndup(auth_len) - auth_len) > 0) {
+               if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
                        for (i = 0; i < siz; i++)
                                *bpos++ = '\0';
                        mb->m_len += siz;
                        for (i = 0; i < siz; i++)
                                *bpos++ = '\0';
                        mb->m_len += siz;
@@ -586,8 +586,10 @@ nfs_init()
        /* Ensure async daemons disabled */
        for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
                nfs_iodwant[i] = (struct proc *)0;
        /* Ensure async daemons disabled */
        for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
                nfs_iodwant[i] = (struct proc *)0;
+       queue_init(&nfs_bufq);
        nfs_xdrneg1 = txdr_unsigned(-1);
        nfs_nhinit();                   /* Init the nfsnode table */
        nfs_xdrneg1 = txdr_unsigned(-1);
        nfs_nhinit();                   /* Init the nfsnode table */
+       nfsrv_init(0);                  /* Init server data structures */
        nfsrv_initcache();              /* Init the server request cache */
 
        /*
        nfsrv_initcache();              /* Init the server request cache */
 
        /*
@@ -601,11 +603,7 @@ nfs_init()
                nqnfs_vers = txdr_unsigned(NQNFS_VER1);
                nqthead.th_head[0] = &nqthead;
                nqthead.th_head[1] = &nqthead;
                nqnfs_vers = txdr_unsigned(NQNFS_VER1);
                nqthead.th_head[0] = &nqthead;
                nqthead.th_head[1] = &nqthead;
-               for (i = 0; i < NQLCHSZ; i++) {
-                       lhp = &nqfhead[i];
-                       lhp->th_head[0] = lhp;
-                       lhp->th_head[1] = lhp;
-               }
+               nqfhead = hashinit(NQLCHSZ, M_NQLEASE, &nqfheadhash);
        }
 
        /*
        }
 
        /*
@@ -638,30 +636,36 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
        register struct vnode *vp = *vpp;
        register struct vattr *vap;
        register struct nfsv2_fattr *fp;
        register struct vnode *vp = *vpp;
        register struct vattr *vap;
        register struct nfsv2_fattr *fp;
-       extern struct vnodeops spec_nfsv2nodeops, spec_vnodeops;
-       register struct nfsnode *np;
+       extern int (**spec_nfsv2nodeop_p)();
+       register struct nfsnode *np, *nq, **nhpp;
        register long t1;
        caddr_t dpos, cp2;
        register long t1;
        caddr_t dpos, cp2;
-       int error = 0;
+       int error = 0, isnq;
        struct mbuf *md;
        enum vtype vtyp;
        u_short vmode;
        long rdev;
        struct mbuf *md;
        enum vtype vtyp;
        u_short vmode;
        long rdev;
-       struct timeval mtime;
+       struct timespec mtime;
        struct vnode *nvp;
 
        md = *mdp;
        dpos = *dposp;
        t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
        struct vnode *nvp;
 
        md = *mdp;
        dpos = *dposp;
        t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
-       if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2))
+       isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
+       if (error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, TRUE, &cp2))
                return (error);
        fp = (struct nfsv2_fattr *)cp2;
        vtyp = nfstov_type(fp->fa_type);
        vmode = fxdr_unsigned(u_short, fp->fa_mode);
                return (error);
        fp = (struct nfsv2_fattr *)cp2;
        vtyp = nfstov_type(fp->fa_type);
        vmode = fxdr_unsigned(u_short, fp->fa_mode);
-       if (vtyp == VNON)
+       if (vtyp == VNON || vtyp == VREG)
                vtyp = IFTOVT(vmode);
                vtyp = IFTOVT(vmode);
-       rdev = fxdr_unsigned(long, fp->fa_rdev);
-       fxdr_time(&fp->fa_mtime, &mtime);
+       if (isnq) {
+               rdev = fxdr_unsigned(long, fp->fa_nqrdev);
+               fxdr_nqtime(&fp->fa_nqmtime, &mtime);
+       } else {
+               rdev = fxdr_unsigned(long, fp->fa_nfsrdev);
+               fxdr_nfstime(&fp->fa_nfsmtime, &mtime);
+       }
        /*
         * If v_type == VNON it is a new node, so fill in the v_type,
         * n_mtime fields. Check to see if it represents a special 
        /*
         * If v_type == VNON it is a new node, so fill in the v_type,
         * n_mtime fields. Check to see if it represents a special 
@@ -677,34 +681,40 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
                        vp->v_type = vtyp;
                if (vp->v_type == VFIFO) {
 #ifdef FIFO
                        vp->v_type = vtyp;
                if (vp->v_type == VFIFO) {
 #ifdef FIFO
-                       extern struct vnodeops fifo_nfsv2nodeops;
-                       vp->v_op = &fifo_nfsv2nodeops;
+                       extern int (**fifo_nfsv2nodeop_p)();
+                       vp->v_op = fifo_nfsv2nodeop_p;
 #else
                        return (EOPNOTSUPP);
 #endif /* FIFO */
                }
                if (vp->v_type == VCHR || vp->v_type == VBLK) {
 #else
                        return (EOPNOTSUPP);
 #endif /* FIFO */
                }
                if (vp->v_type == VCHR || vp->v_type == VBLK) {
-                       vp->v_op = &spec_nfsv2nodeops;
+                       vp->v_op = spec_nfsv2nodeop_p;
                        if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) {
                                /*
                                 * Discard unneeded vnode, but save its nfsnode.
                                 */
                        if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) {
                                /*
                                 * Discard unneeded vnode, but save its nfsnode.
                                 */
-                               remque(np);
+                               if (nq = np->n_forw)
+                                       nq->n_back = np->n_back;
+                               *np->n_back = nq;
                                nvp->v_data = vp->v_data;
                                vp->v_data = NULL;
                                nvp->v_data = vp->v_data;
                                vp->v_data = NULL;
-                               vp->v_op = &spec_vnodeops;
+                               vp->v_op = spec_vnodeop_p;
                                vrele(vp);
                                vgone(vp);
                                /*
                                 * Reinitialize aliased node.
                                 */
                                np->n_vnode = nvp;
                                vrele(vp);
                                vgone(vp);
                                /*
                                 * Reinitialize aliased node.
                                 */
                                np->n_vnode = nvp;
-                               insque(np, nfs_hash(&np->n_fh));
+                               nhpp = (struct nfsnode **)nfs_hash(&np->n_fh);
+                               if (nq = *nhpp)
+                                       nq->n_back = &np->n_forw;
+                               np->n_forw = nq;
+                               np->n_back = nhpp;
+                               *nhpp = np;
                                *vpp = vp = nvp;
                        }
                }
                                *vpp = vp = nvp;
                        }
                }
-               if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0)
-                       np->n_mtime = mtime.tv_sec;
+               np->n_mtime = mtime.ts_sec;
        }
        vap = &np->n_vattr;
        vap->va_type = vtyp;
        }
        vap = &np->n_vattr;
        vap->va_type = vtyp;
@@ -712,34 +722,66 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
        vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
        vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
        vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
        vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
        vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
        vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
-       vap->va_size = fxdr_unsigned(u_long, fp->fa_size);
-       if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) {
-               np->n_size = vap->va_size;
-               vnode_pager_setsize(vp, np->n_size);
-       }
-       vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize);
        vap->va_rdev = (dev_t)rdev;
        vap->va_rdev = (dev_t)rdev;
-       vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE;
-       vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
-       vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid);
-       vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec);
-       vap->va_atime.tv_usec = 0;
-       vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec);
        vap->va_mtime = mtime;
        vap->va_mtime = mtime;
-       vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec);
-       vap->va_ctime.tv_usec = 0;
-       vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec);
-#ifdef _NOQUAD
-       vap->va_size_rsv = 0;
-       vap->va_bytes_rsv = 0;
-#endif
+       vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
+       if (isnq) {
+               fxdr_hyper(&fp->fa_nqsize, &vap->va_size);
+               vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize);
+               fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes);
+               vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid);
+               fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime);
+               vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags);
+               fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime);
+               vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen);
+               fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev);
+       } else {
+               vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize);
+               vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize);
+               vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE;
+               vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid);
+               fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime);
+               vap->va_flags = 0;
+               vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa_nfsctime.nfs_sec);
+               vap->va_ctime.ts_nsec = 0;
+               vap->va_gen = fxdr_unsigned(u_long, fp->fa_nfsctime.nfs_usec);
+               vap->va_filerev = 0;
+       }
+       if (vap->va_size != np->n_size) {
+               if (vap->va_type == VREG) {
+                       if (np->n_flag & NMODIFIED) {
+                               if (vap->va_size < np->n_size)
+                                       vap->va_size = np->n_size;
+                               else
+                                       np->n_size = vap->va_size;
+                       } else
+                               np->n_size = vap->va_size;
+                       vnode_pager_setsize(vp, (u_long)np->n_size);
+               } else
+                       np->n_size = vap->va_size;
+       }
        np->n_attrstamp = time.tv_sec;
        *dposp = dpos;
        *mdp = md;
        if (vaper != NULL) {
                bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
        np->n_attrstamp = time.tv_sec;
        *dposp = dpos;
        *mdp = md;
        if (vaper != NULL) {
                bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
-               if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size))
+#ifdef notdef
+               if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size)
+               if (np->n_size > vap->va_size)
                        vaper->va_size = np->n_size;
                        vaper->va_size = np->n_size;
+#endif
+               if (np->n_flag & NCHG) {
+                       if (np->n_flag & NACC) {
+                               vaper->va_atime.ts_sec = np->n_atim.tv_sec;
+                               vaper->va_atime.ts_nsec =
+                                   np->n_atim.tv_usec * 1000;
+                       }
+                       if (np->n_flag & NUPD) {
+                               vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
+                               vaper->va_mtime.ts_nsec =
+                                   np->n_mtim.tv_usec * 1000;
+                       }
+               }
        }
        return (0);
 }
        }
        return (0);
 }
@@ -749,29 +791,56 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
  * If the cache is valid, copy contents to *vap and return 0
  * otherwise return an error
  */
  * If the cache is valid, copy contents to *vap and return 0
  * otherwise return an error
  */
-nfs_getattrcache(vp, vap)
+nfs_getattrcache(vp, vaper)
        register struct vnode *vp;
        register struct vnode *vp;
-       struct vattr *vap;
+       struct vattr *vaper;
 {
 {
-       register struct nfsnode *np;
+       register struct nfsnode *np = VTONFS(vp);
+       register struct vattr *vap;
 
 
-       np = VTONFS(vp);
-       if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
+       if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) {
                if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
                        nfsstats.attrcache_misses++;
                        return (ENOENT);
                }
                if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
                        nfsstats.attrcache_misses++;
                        return (ENOENT);
                }
-       } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO) {
+       } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
                nfsstats.attrcache_misses++;
                return (ENOENT);
        }
        nfsstats.attrcache_hits++;
                nfsstats.attrcache_misses++;
                return (ENOENT);
        }
        nfsstats.attrcache_hits++;
-       bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr));
+       vap = &np->n_vattr;
+       if (vap->va_size != np->n_size) {
+               if (vap->va_type == VREG) {
+                       if (np->n_flag & NMODIFIED) {
+                               if (vap->va_size < np->n_size)
+                                       vap->va_size = np->n_size;
+                               else
+                                       np->n_size = vap->va_size;
+                       } else
+                               np->n_size = vap->va_size;
+                       vnode_pager_setsize(vp, (u_long)np->n_size);
+               } else
+                       np->n_size = vap->va_size;
+       }
+       bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
+#ifdef notdef
        if ((np->n_flag & NMODIFIED) == 0) {
        if ((np->n_flag & NMODIFIED) == 0) {
-               np->n_size = vap->va_size;
-               vnode_pager_setsize(vp, np->n_size);
-       } else if (np->n_size > vap->va_size)
-               vap->va_size = np->n_size;
+               np->n_size = vaper->va_size;
+               vnode_pager_setsize(vp, (u_long)np->n_size);
+       } else if (np->n_size > vaper->va_size)
+       if (np->n_size > vaper->va_size)
+               vaper->va_size = np->n_size;
+#endif
+       if (np->n_flag & NCHG) {
+               if (np->n_flag & NACC) {
+                       vaper->va_atime.ts_sec = np->n_atim.tv_sec;
+                       vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000;
+               }
+               if (np->n_flag & NUPD) {
+                       vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
+                       vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000;
+               }
+       }
        return (0);
 }
 
        return (0);
 }
 
@@ -792,19 +861,19 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
        register struct mbuf *md;
        register char *fromcp, *tocp;
        struct vnode *dp;
        register struct mbuf *md;
        register char *fromcp, *tocp;
        struct vnode *dp;
-       int flag, error, rdonly;
+       int error, rdonly;
+       struct componentname *cnp = &ndp->ni_cnd;
 
 
-       flag = ndp->ni_nameiop & OPMASK;
-       MALLOC(ndp->ni_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
+       MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
        /*
         * Copy the name from the mbuf list to ndp->ni_pnbuf
         * and set the various ndp fields appropriately.
         */
        fromcp = *dposp;
        /*
         * Copy the name from the mbuf list to ndp->ni_pnbuf
         * and set the various ndp fields appropriately.
         */
        fromcp = *dposp;
-       tocp = ndp->ni_pnbuf;
+       tocp = cnp->cn_pnbuf;
        md = *mdp;
        rem = mtod(md, caddr_t) + md->m_len - fromcp;
        md = *mdp;
        rem = mtod(md, caddr_t) + md->m_len - fromcp;
-       ndp->ni_hash = 0;
+       cnp->cn_hash = 0;
        for (i = 0; i < len; i++) {
                while (rem == 0) {
                        md = md->m_next;
        for (i = 0; i < len; i++) {
                while (rem == 0) {
                        md = md->m_next;
@@ -819,12 +888,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
                        error = EINVAL;
                        goto out;
                }
                        error = EINVAL;
                        goto out;
                }
-               if (*fromcp & 0200)
-                       if ((*fromcp&0377) == ('/'|0200) || flag != DELETE) {
-                               error = EINVAL;
-                               goto out;
-                       }
-               ndp->ni_hash += (unsigned char)*fromcp;
+               cnp->cn_hash += (unsigned char)*fromcp;
                *tocp++ = *fromcp++;
                rem--;
        }
                *tocp++ = *fromcp++;
                rem--;
        }
@@ -838,12 +902,13 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
                else if (error = nfs_adv(mdp, dposp, len, rem))
                        goto out;
        }
                else if (error = nfs_adv(mdp, dposp, len, rem))
                        goto out;
        }
-       ndp->ni_pathlen = tocp - ndp->ni_pnbuf;
-       ndp->ni_ptr = ndp->ni_pnbuf;
+       ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
+       cnp->cn_nameptr = cnp->cn_pnbuf;
        /*
         * Extract and set starting directory.
         */
        /*
         * Extract and set starting directory.
         */
-       if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred, slp, nam, &rdonly))
+       if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
+           nam, &rdonly))
                goto out;
        if (dp->v_type != VDIR) {
                vrele(dp);
                goto out;
        if (dp->v_type != VDIR) {
                vrele(dp);
@@ -852,19 +917,20 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
        }
        ndp->ni_startdir = dp;
        if (rdonly)
        }
        ndp->ni_startdir = dp;
        if (rdonly)
-               ndp->ni_nameiop |= (NOCROSSMOUNT | RDONLY);
+               cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
        else
        else
-               ndp->ni_nameiop |= NOCROSSMOUNT;
+               cnp->cn_flags |= NOCROSSMOUNT;
        /*
         * And call lookup() to do the real work
         */
        /*
         * And call lookup() to do the real work
         */
-       if (error = lookup(ndp, p))
+       cnp->cn_proc = p;
+       if (error = lookup(ndp))
                goto out;
        /*
         * Check for encountering a symbolic link
         */
                goto out;
        /*
         * Check for encountering a symbolic link
         */
-       if (ndp->ni_nameiop & ISSYMLINK) {
-               if ((ndp->ni_nameiop & LOCKPARENT) && ndp->ni_pathlen == 1)
+       if (cnp->cn_flags & ISSYMLINK) {
+               if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
                        vput(ndp->ni_dvp);
                else
                        vrele(ndp->ni_dvp);
                        vput(ndp->ni_dvp);
                else
                        vrele(ndp->ni_dvp);
@@ -876,12 +942,12 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
        /*
         * Check for saved name request
         */
        /*
         * Check for saved name request
         */
-       if (ndp->ni_nameiop & (SAVENAME | SAVESTART)) {
-               ndp->ni_nameiop |= HASBUF;
+       if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
+               cnp->cn_flags |= HASBUF;
                return (0);
        }
 out:
                return (0);
        }
 out:
-       FREE(ndp->ni_pnbuf, M_NAMEI);
+       FREE(cnp->cn_pnbuf, M_NAMEI);
        return (error);
 }
 
        return (error);
 }
 
@@ -950,10 +1016,9 @@ nfsm_adj(mp, len, nul)
 /*
  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
  *     - look up fsid in mount list (if not found ret error)
 /*
  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
  *     - look up fsid in mount list (if not found ret error)
- *     - check that it is exported
- *     - get vp by calling VFS_FHTOVP() macro
+ *     - get vp and export rights by calling VFS_FHTOVP()
+ *     - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
  *     - if not lockflag unlock it with VOP_UNLOCK()
  *     - if not lockflag unlock it with VOP_UNLOCK()
- *     - if cred->cr_uid == 0 or MNT_EXPORTANON set it to neth_anon
  */
 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
        fhandle_t *fhp;
  */
 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
        fhandle_t *fhp;
@@ -965,64 +1030,20 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
        int *rdonlyp;
 {
        register struct mount *mp;
        int *rdonlyp;
 {
        register struct mount *mp;
-       register struct netaddrhash *np;
-       register struct ufsmount *ump;
        register struct nfsuid *uidp;
        register struct nfsuid *uidp;
-       struct sockaddr *saddr;
-       int error;
+       register int i;
+       struct ucred *credanon;
+       int error, exflags;
 
        *vpp = (struct vnode *)0;
        if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
                return (ESTALE);
 
        *vpp = (struct vnode *)0;
        if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
                return (ESTALE);
-       if ((mp->mnt_flag & MNT_EXPORTED) == 0)
-               return (EACCES);
-
-       /*
-        * Get the export permission structure for this <mp, client> tuple.
-        */
-       ump = VFSTOUFS(mp);
-       if (nam) {
-
-               /*
-                * First search for a network match.
-                */
-               np = ump->um_netaddr[NETMASK_HASH];
-               while (np) {
-                   if (nfs_netaddr_match(np->neth_family, &np->neth_haddr,
-                       &np->neth_hmask, nam))
-                       break;
-                       np = np->neth_next;
-               }
-
-               /*
-                * If not found, try for an address match.
-                */
-               if (np == (struct netaddrhash *)0) {
-                   saddr = mtod(nam, struct sockaddr *);
-                   np = ump->um_netaddr[NETADDRHASH(saddr)];
-                   while (np) {
-                       if (nfs_netaddr_match(np->neth_family, &np->neth_haddr,
-                           (struct netaddrhash *)0, nam))
-                           break;
-                       np = np->neth_next;
-                   }
-               }
-       } else
-               np = (struct netaddrhash *)0;
-       if (np == (struct netaddrhash *)0) {
-
-               /*
-                * If no address match, use the default if it exists.
-                */
-               if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0)
-                       return (EACCES);
-               np = &ump->um_defexported;
-       }
-
+       if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon))
+               return (error);
        /*
         * Check/setup credentials.
         */
        /*
         * Check/setup credentials.
         */
-       if (np->neth_exflags & MNT_EXKERB) {
+       if (exflags & MNT_EXKERB) {
                uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)];
                while (uidp) {
                        if (uidp->nu_uid == cred->cr_uid)
                uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)];
                while (uidp) {
                        if (uidp->nu_uid == cred->cr_uid)
@@ -1030,16 +1051,19 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
                        uidp = uidp->nu_hnext;
                }
                if (uidp) {
                        uidp = uidp->nu_hnext;
                }
                if (uidp) {
-                       if (cred->cr_ref != 1)
-                               panic("nsrv fhtovp");
-                       *cred = uidp->nu_cr;
-               } else
+                       cred->cr_uid = uidp->nu_cr.cr_uid;
+                       for (i = 0; i < uidp->nu_cr.cr_ngroups; i++)
+                               cred->cr_groups[i] = uidp->nu_cr.cr_groups[i];
+               } else {
+                       vput(*vpp);
                        return (NQNFS_AUTHERR);
                        return (NQNFS_AUTHERR);
-       } else if (cred->cr_uid == 0 || (np->neth_exflags & MNT_EXPORTANON))
-               *cred = np->neth_anon;
-       if (error = VFS_FHTOVP(mp, &fhp->fh_fid, 0, vpp))
-               return (ESTALE);
-       if (np->neth_exflags & MNT_EXRDONLY)
+               }
+       } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
+               cred->cr_uid = credanon->cr_uid;
+               for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
+                       cred->cr_groups[i] = credanon->cr_groups[i];
+       }
+       if (exflags & MNT_EXRDONLY)
                *rdonlyp = 1;
        else
                *rdonlyp = 0;
                *rdonlyp = 1;
        else
                *rdonlyp = 0;
@@ -1047,3 +1071,45 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
                VOP_UNLOCK(*vpp);
        return (0);
 }
                VOP_UNLOCK(*vpp);
        return (0);
 }
+
+/*
+ * This function compares two net addresses by family and returns TRUE
+ * if they are the same host.
+ * If there is any doubt, return FALSE.
+ * The AF_INET family is handled as a special case so that address mbufs
+ * don't need to be saved to store "struct in_addr", which is only 4 bytes.
+ */
+netaddr_match(family, haddr, nam)
+       int family;
+       union nethostaddr *haddr;
+       struct mbuf *nam;
+{
+       register struct sockaddr_in *inetaddr;
+
+       switch (family) {
+       case AF_INET:
+               inetaddr = mtod(nam, struct sockaddr_in *);
+               if (inetaddr->sin_family == AF_INET &&
+                   inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
+                       return (1);
+               break;
+#ifdef ISO
+       case AF_ISO:
+           {
+               register struct sockaddr_iso *isoaddr1, *isoaddr2;
+
+               isoaddr1 = mtod(nam, struct sockaddr_iso *);
+               isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
+               if (isoaddr1->siso_family == AF_ISO &&
+                   isoaddr1->siso_nlen > 0 &&
+                   isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
+                   SAME_ISOADDR(isoaddr1, isoaddr2))
+                       return (1);
+               break;
+           }
+#endif /* ISO */
+       default:
+               break;
+       };
+       return (0);
+}