diff options
author | pjd <pjd@FreeBSD.org> | 2010-12-21 23:15:40 +0000 |
---|---|---|
committer | pjd <pjd@FreeBSD.org> | 2010-12-21 23:15:40 +0000 |
commit | f4e75b41ae7145e275808cc561d4cacf0f9a51a7 (patch) | |
tree | 451f3bc122f95438a761ab938d7dc7ba6b8dfced | |
parent | 8503dc84a4de95e9b6749bd39a6971cc902bcabe (diff) | |
download | FreeBSD-src-f4e75b41ae7145e275808cc561d4cacf0f9a51a7.zip FreeBSD-src-f4e75b41ae7145e275808cc561d4cacf0f9a51a7.tar.gz |
Use newly added NFSRV_FLAG_BUSY flag for nfsrv_fhtovp() to keep mount point
busy. This fixes a race where we can pass invalid mount point to VFS_VGET()
via vp->v_mount when exported file system was forcibly unmounted between
nfsrv_fhtovp() and VFS_VGET().
Reviewed by: kib
MFC after: 5 days
-rw-r--r-- | sys/nfsserver/nfs_serv.c | 25 |
1 files changed, 15 insertions, 10 deletions
diff --git a/sys/nfsserver/nfs_serv.c b/sys/nfsserver/nfs_serv.c index e304291..1fd7047 100644 --- a/sys/nfsserver/nfs_serv.c +++ b/sys/nfsserver/nfs_serv.c @@ -3036,9 +3036,11 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, int v3 = (nfsd->nd_flag & ND_NFSV3); int usevget = 1, vfslocked; struct componentname cn; + struct mount *mntp = NULL; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); vfslocked = 0; + vp_locked = 0; if (!v3) panic("nfsrv_readdirplus: v3 proc called on a v2 connection"); fhp = &nfh.fh_generic; @@ -3058,14 +3060,17 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, if (siz > xfer) siz = xfer; fullsiz = siz; - error = nfsrv_fhtovp(fhp, 0, &vp, &vfslocked, nfsd, slp, - nam, &rdonly, TRUE); - vp_locked = 1; - if (!error && vp->v_type != VDIR) { - error = ENOTDIR; - vput(vp); - vp = NULL; - vp_locked = 0; + error = nfsrv_fhtovp(fhp, NFSRV_FLAG_BUSY, &vp, &vfslocked, nfsd, slp, + nam, &rdonly); + if (!error) { + vp_locked = 1; + mntp = vp->v_mount; + if (vp->v_type != VDIR) { + error = ENOTDIR; + vput(vp); + vp = NULL; + vp_locked = 0; + } } if (error) { nfsm_reply(NFSX_UNSIGNED); @@ -3207,8 +3212,8 @@ again: * For readdir_and_lookup get the vnode using * the file number. */ - error = VFS_VGET(vp->v_mount, dp->d_fileno, - LK_SHARED, &nvp); + error = VFS_VGET(mntp, dp->d_fileno, LK_SHARED, + &nvp); if (error != 0 && error != EOPNOTSUPP) { error = 0; goto invalid; |