Author: rmacklem
Date: Mon Nov 23 16:08:15 2009
New Revision: 199715
URL: http://svn.freebsd.org/changeset/base/199715

Log:
  Modify the experimental nfs server so that it falls back to
  using VOP_LOOKUP() when VFS_VGET() returns EOPNOTSUPP in the
  ReaddirPlus RPC. This patch is based upon one by pjd@ for the
  regular nfs server which has not yet been committed. It is needed
  when a ZFS volume is exported and ReaddirPlus (which almost
  always happens for NFSv4) is performed by a client. The patch
  also simplifies vnode lock handling somewhat.
  
  MFC after:    2 weeks

Modified:
  head/sys/fs/nfsserver/nfs_nfsdport.c

Modified: head/sys/fs/nfsserver/nfs_nfsdport.c
==============================================================================
--- head/sys/fs/nfsserver/nfs_nfsdport.c        Mon Nov 23 16:00:16 2009        
(r199714)
+++ head/sys/fs/nfsserver/nfs_nfsdport.c        Mon Nov 23 16:08:15 2009        
(r199715)
@@ -1675,7 +1675,7 @@ nfsrvd_readdirplus(struct nfsrv_descript
        struct nfsvattr nva, at, *nvap = &nva;
        struct mbuf *mb0, *mb1;
        struct nfsreferral *refp;
-       int nlen, r, error = 0, getret = 1, vgetret;
+       int nlen, r, error = 0, getret = 1, usevget = 1;
        int siz, cnt, fullsiz, eofflag, ncookies, entrycnt;
        caddr_t bpos0, bpos1;
        u_int64_t off, toff, verf;
@@ -1683,6 +1683,7 @@ nfsrvd_readdirplus(struct nfsrv_descript
        nfsattrbit_t attrbits, rderrbits, savbits;
        struct uio io;
        struct iovec iv;
+       struct componentname cn;
 
        if (nd->nd_repstat) {
                nfsrv_postopattr(nd, getret, &at);
@@ -1761,8 +1762,6 @@ nfsrvd_readdirplus(struct nfsrv_descript
                return (0);
        }
 
-       NFSVOPUNLOCK(vp, 0, p);
-
        MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
 again:
        eofflag = 0;
@@ -1780,10 +1779,8 @@ again:
        io.uio_segflg = UIO_SYSSPACE;
        io.uio_rw = UIO_READ;
        io.uio_td = NULL;
-       NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
        nd->nd_repstat = VOP_READDIR(vp, &io, nd->nd_cred, &eofflag, &ncookies,
            &cookies);
-       NFSVOPUNLOCK(vp, 0, p);
        off = (u_int64_t)io.uio_offset;
        if (io.uio_resid)
                siz -= io.uio_resid;
@@ -1795,7 +1792,7 @@ again:
        if (!nd->nd_repstat)
                nd->nd_repstat = getret;
        if (nd->nd_repstat) {
-               vrele(vp);
+               vput(vp);
                if (cookies)
                        free((caddr_t)cookies, M_TEMP);
                free((caddr_t)rbuf, M_TEMP);
@@ -1808,7 +1805,7 @@ again:
         * rpc reply
         */
        if (siz == 0) {
-               vrele(vp);
+               vput(vp);
                if (nd->nd_flag & ND_NFSV3)
                        nfsrv_postopattr(nd, getret, &at);
                NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
@@ -1853,33 +1850,7 @@ again:
                toff = off;
                goto again;
        }
-
-       /*
-        * Probe one of the directory entries to see if the filesystem
-        * supports VGET for NFSv3. For NFSv4, it will return an
-        * error later, if attributes are required.
-        * (To be honest, most if not all NFSv4 clients will require
-        *  attributes, but??)
-        */
-       if ((nd->nd_flag & ND_NFSV3)) {
-               vgetret = VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE,
-                   &nvp);
-               if (vgetret != 0) {
-                       if (vgetret == EOPNOTSUPP)
-                               nd->nd_repstat = NFSERR_NOTSUPP;
-                       else
-                               nd->nd_repstat = NFSERR_SERVERFAULT;
-                       vrele(vp);
-                       if (cookies)
-                               free((caddr_t)cookies, M_TEMP);
-                       free((caddr_t)rbuf, M_TEMP);
-                       nfsrv_postopattr(nd, getret, &at);
-                       return (0);
-               }
-               if (!vgetret)
-                       vput(nvp);
-               nvp = NULL;
-       }
+       NFSVOPUNLOCK(vp, 0, p);
 
        /*
         * Save this position, in case there is an error before one entry
@@ -1937,9 +1908,41 @@ again:
                                if (nd->nd_flag & ND_NFSV4)
                                        refp = nfsv4root_getreferral(NULL,
                                            vp, dp->d_fileno);
-                               if (refp == NULL)
-                                       r = VFS_VGET(vp->v_mount, dp->d_fileno,
-                                           LK_EXCLUSIVE, &nvp);
+                               if (refp == NULL) {
+                                       if (usevget)
+                                               r = VFS_VGET(vp->v_mount,
+                                                   dp->d_fileno, LK_EXCLUSIVE,
+                                                   &nvp);
+                                       else
+                                               r = EOPNOTSUPP;
+                                       if (r == EOPNOTSUPP) {
+                                               if (usevget) {
+                                                       usevget = 0;
+                                                       cn.cn_nameiop = LOOKUP;
+                                                       cn.cn_lkflags =
+                                                           LK_EXCLUSIVE |
+                                                           LK_RETRY;
+                                                       cn.cn_cred =
+                                                           nd->nd_cred;
+                                                       cn.cn_thread = p;
+                                               }
+                                               cn.cn_nameptr = dp->d_name;
+                                               cn.cn_namelen = nlen;
+                                               cn.cn_flags = ISLASTCN |
+                                                   NOFOLLOW | LOCKLEAF |
+                                                   MPSAFE;
+                                               if (nlen == 2 &&
+                                                   dp->d_name[0] == '.' &&
+                                                   dp->d_name[1] == '.')
+                                                       cn.cn_flags |=
+                                                           ISDOTDOT;
+                                               if (!VOP_ISLOCKED(vp))
+                                                       vn_lock(vp,
+                                                           LK_EXCLUSIVE |
+                                                           LK_RETRY);
+                                               r = VOP_LOOKUP(vp, &nvp, &cn);
+                                       }
+                               }
                                if (!r) {
                                    if (refp == NULL &&
                                        ((nd->nd_flag & ND_NFSV3) ||
@@ -2018,7 +2021,10 @@ again:
                cookiep++;
                ncookies--;
        }
-       vrele(vp);
+       if (!usevget && VOP_ISLOCKED(vp))
+               vput(vp);
+       else
+               vrele(vp);
 
        /*
         * If dirlen > cnt, we must strip off the last entry. If that
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to