Author: pjd
Date: Thu Aug 26 23:41:40 2010
New Revision: 211854
URL: http://svn.freebsd.org/changeset/base/211854

Log:
  - When VFS_VGET() is not supported, switch to VOP_LOOKUP().
  - We are fine by only share-locking the vnode.
  - Remove assertion that doesn't hold for ZFS where we cross mount points
    boundaries by going into .zfs/snapshot/<name>/.
  
  Reviewed by:  rmacklem
  MFC after:    1 month

Modified:
  head/sys/nfsserver/nfs_serv.c

Modified: head/sys/nfsserver/nfs_serv.c
==============================================================================
--- head/sys/nfsserver/nfs_serv.c       Thu Aug 26 23:33:04 2010        
(r211853)
+++ head/sys/nfsserver/nfs_serv.c       Thu Aug 26 23:41:40 2010        
(r211854)
@@ -3041,7 +3041,8 @@ nfsrv_readdirplus(struct nfsrv_descript 
        u_quad_t off, toff, verf;
        u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */
        int v3 = (nfsd->nd_flag & ND_NFSV3);
-       int vfslocked;
+       int usevget = 1, vfslocked;
+       struct componentname cn;
 
        nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
        vfslocked = 0;
@@ -3186,28 +3187,6 @@ again:
                goto again;
        }
 
-       /*
-        * Probe one of the directory entries to see if the filesystem
-        * supports VGET.
-        */
-       error = VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE, &nvp);
-       if (error) {
-               if (error == EOPNOTSUPP)
-                       error = NFSERR_NOTSUPP;
-               else
-                       error = NFSERR_SERVERFAULT;
-               vrele(vp);
-               vp = NULL;
-               free((caddr_t)cookies, M_TEMP);
-               free((caddr_t)rbuf, M_TEMP);
-               nfsm_reply(NFSX_V3POSTOPATTR);
-               nfsm_srvpostop_attr(getret, &at);
-               error = 0;
-               goto nfsmout;
-       }
-       vput(nvp);
-       nvp = NULL;
-
        dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
            2 * NFSX_UNSIGNED;
        nfsm_reply(cnt);
@@ -3224,23 +3203,49 @@ again:
                        nlen = dp->d_namlen;
                        rem = nfsm_rndup(nlen)-nlen;
 
-                       /*
-                        * For readdir_and_lookup get the vnode using
-                        * the file number.
-                        */
-                       if (VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE,
-                           &nvp))
-                               goto invalid;
+                       if (usevget) {
+                               /*
+                                * For readdir_and_lookup get the vnode using
+                                * the file number.
+                                */
+                               error = VFS_VGET(vp->v_mount, dp->d_fileno,
+                                   LK_SHARED, &nvp);
+                               if (error != 0 && error != EOPNOTSUPP) {
+                                       error = 0;
+                                       goto invalid;
+                               } else if (error == EOPNOTSUPP) {
+                                       /*
+                                        * VFS_VGET() not supported?
+                                        * Let's switch to VOP_LOOKUP().
+                                        */
+                                       error = 0;
+                                       usevget = 0;
+                                       cn.cn_nameiop = LOOKUP;
+                                       cn.cn_flags = ISLASTCN | NOFOLLOW | \
+                                           LOCKSHARED | LOCKLEAF | MPSAFE;
+                                       cn.cn_lkflags = LK_SHARED | LK_RETRY;
+                                       cn.cn_cred = cred;
+                                       cn.cn_thread = curthread;
+                               }
+                       }
+                       if (!usevget) {
+                               cn.cn_nameptr = dp->d_name;
+                               cn.cn_namelen = dp->d_namlen;
+                               if (dp->d_namlen == 2 &&
+                                   dp->d_name[0] == '.' &&
+                                   dp->d_name[1] == '.') {
+                                       cn.cn_flags |= ISDOTDOT;
+                               } else {
+                                       cn.cn_flags &= ~ISDOTDOT;
+                               }
+                               if (!VOP_ISLOCKED(vp))
+                                       vn_lock(vp, LK_SHARED | LK_RETRY);
+                               if (VOP_LOOKUP(vp, &nvp, &cn) != 0)
+                                       goto invalid;
+                       }
+
                        bzero((caddr_t)nfhp, NFSX_V3FH);
-                       nfhp->fh_fsid =
-                               nvp->v_mount->mnt_stat.f_fsid;
-                       /*
-                        * XXXRW: Assert the mountpoints are the same so that
-                        * we know that acquiring Giant based on the
-                        * directory is the right thing for the child.
-                        */
-                       KASSERT(nvp->v_mount == vp->v_mount,
-                           ("nfsrv_readdirplus: nvp mount != vp mount"));
+                       nfhp->fh_fsid = nvp->v_mount->mnt_stat.f_fsid;
                        if (VOP_VPTOFH(nvp, &nfhp->fh_fid)) {
                                vput(nvp);
                                nvp = NULL;
@@ -3336,7 +3341,10 @@ invalid:
                cookiep++;
                ncookies--;
        }
-       vrele(vp);
+       if (!usevget && VOP_ISLOCKED(vp))
+               vput(vp);
+       else
+               vrele(vp);
        vp = NULL;
        nfsm_clget;
        *tl = nfsrv_nfs_false;
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to