summaryrefslogtreecommitdiffstats
path: root/sys/nfsserver
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2010-08-26 23:41:40 +0000
committerpjd <pjd@FreeBSD.org>2010-08-26 23:41:40 +0000
commitf8dd61b4d9fff5d70361faf092b957a5e8c0e013 (patch)
treea9592f1b11ab5a02fc356fc02b49620545924e0f /sys/nfsserver
parent2943e7b89949d2e113945a724dc70e5fef0ee340 (diff)
downloadFreeBSD-src-f8dd61b4d9fff5d70361faf092b957a5e8c0e013.zip
FreeBSD-src-f8dd61b4d9fff5d70361faf092b957a5e8c0e013.tar.gz
- 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
Diffstat (limited to 'sys/nfsserver')
-rw-r--r--sys/nfsserver/nfs_serv.c88
1 files changed, 48 insertions, 40 deletions
diff --git a/sys/nfsserver/nfs_serv.c b/sys/nfsserver/nfs_serv.c
index d1be5e5..833bfc7 100644
--- a/sys/nfsserver/nfs_serv.c
+++ b/sys/nfsserver/nfs_serv.c
@@ -3041,7 +3041,8 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
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;
OpenPOWER on IntegriCloud