- 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
This commit is contained in:
Pawel Jakub Dawidek 2010-08-26 23:41:40 +00:00
parent 0778b1d117
commit 203a3b911e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=211854

View File

@ -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 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
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 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
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 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
cookiep++;
ncookies--;
}
vrele(vp);
if (!usevget && VOP_ISLOCKED(vp))
vput(vp);
else
vrele(vp);
vp = NULL;
nfsm_clget;
*tl = nfsrv_nfs_false;