Modify readdirplus in the experimental NFS server in a

manner analogous to r216633 for the regular server. This
change busies the file system so that VFS_VGET() is
guaranteed to be using the correct mount point even
during a forced dismount attempt. Since nfsd_fhtovp() is
not called immediately before readdirplus, the patch is
actually a clone of pjd@'s nfs_serv.c.4.patch instead of
the one committed in r216633.

Reviewed by:	kib
MFC after:	10 days
This commit is contained in:
Rick Macklem 2011-01-09 02:10:54 +00:00
parent 70df11eaad
commit f9266eb1f9

View File

@ -1685,6 +1685,7 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
struct iovec iv;
struct componentname cn;
int not_zfs;
struct mount *mp;
if (nd->nd_repstat) {
nfsrv_postopattr(nd, getret, &at);
@ -1854,7 +1855,24 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
toff = off;
goto again;
}
/*
* Busy the file system so that the mount point won't go away
* and, as such, VFS_VGET() can be used safely.
*/
mp = vp->v_mount;
vfs_ref(mp);
VOP_UNLOCK(vp, 0);
nd->nd_repstat = vfs_busy(mp, 0);
vfs_rel(mp);
if (nd->nd_repstat != 0) {
vrele(vp);
free(cookies, M_TEMP);
free(rbuf, M_TEMP);
if (nd->nd_flag & ND_NFSV3)
nfsrv_postopattr(nd, getret, &at);
return (0);
}
/*
* Save this position, in case there is an error before one entry
@ -1914,9 +1932,8 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
vp, dp->d_fileno);
if (refp == NULL) {
if (usevget)
r = VFS_VGET(vp->v_mount,
dp->d_fileno, LK_SHARED,
&nvp);
r = VFS_VGET(mp, dp->d_fileno,
LK_SHARED, &nvp);
else
r = EOPNOTSUPP;
if (r == EOPNOTSUPP) {
@ -2035,6 +2052,7 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
ncookies--;
}
vrele(vp);
vfs_unbusy(mp);
/*
* If dirlen > cnt, we must strip off the last entry. If that