summaryrefslogtreecommitdiffstats
path: root/sys/nfsserver/nfs_srvsubs.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/nfsserver/nfs_srvsubs.c')
-rw-r--r--sys/nfsserver/nfs_srvsubs.c42
1 files changed, 31 insertions, 11 deletions
diff --git a/sys/nfsserver/nfs_srvsubs.c b/sys/nfsserver/nfs_srvsubs.c
index a6bcb8ea..e2238f1 100644
--- a/sys/nfsserver/nfs_srvsubs.c
+++ b/sys/nfsserver/nfs_srvsubs.c
@@ -624,7 +624,6 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
NFSD_LOCK_ASSERT();
NFSD_UNLOCK();
- mtx_lock(&Giant); /* VFS */
*retdirp = NULL;
cnp->cn_flags |= NOMACCHECK;
@@ -643,14 +642,14 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
md = md->m_next;
if (md == NULL) {
error = EBADRPC;
- goto out;
+ goto out_nogiant;
}
fromcp = mtod(md, caddr_t);
rem = md->m_len;
}
if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
error = EACCES;
- goto out;
+ goto out_nogiant;
}
*tocp++ = *fromcp++;
rem--;
@@ -663,17 +662,17 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
if (rem >= len)
*dposp += len;
else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
- goto out;
+ goto out_nogiant;
}
/*
* Extract and set starting directory.
+ *
+ * XXXRW: For now, acquire Giant unconditionally to avoid tracking it
+ * on multiple vnodes.
*/
- mtx_unlock(&Giant); /* VFS */
- NFSD_LOCK();
error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
nam, &rdonly, pubflag);
- NFSD_UNLOCK();
mtx_lock(&Giant); /* VFS */
if (error)
goto out;
@@ -889,6 +888,8 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
* cleanup state trivially.
*/
out:
+ mtx_unlock(&Giant); /* VFS */
+out_nogiant:
if (error) {
uma_zfree(namei_zone, cnp->cn_pnbuf);
ndp->ni_vp = NULL;
@@ -898,7 +899,6 @@ out:
} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
ndp->ni_dvp = NULL;
}
- mtx_unlock(&Giant); /* VFS */
NFSD_LOCK();
return (error);
}
@@ -1064,6 +1064,10 @@ nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
* - get vp and export rights by calling VFS_FHTOVP()
* - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
* - if not lockflag unlock it with VOP_UNLOCK()
+ *
+ * As this routine may acquire Giant and may sleep, it can't be called with
+ * nfsd_mtx. Caller should invoke nfsrv_fhtovp_locked() if the lock is held
+ * so that it can be automatically dropped and re-acquired.
*/
int
nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
@@ -1080,7 +1084,7 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
struct sockaddr_int *saddr;
#endif
- NFSD_LOCK_ASSERT();
+ NFSD_UNLOCK_ASSERT();
*vpp = NULL;
@@ -1093,7 +1097,6 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
mp = vfs_getvfs(&fhp->fh_fsid);
if (!mp)
return (ESTALE);
- NFSD_UNLOCK();
vfslocked = VFS_LOCK_GIANT(mp);
error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
if (error)
@@ -1133,10 +1136,27 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
out:
vfs_rel(mp);
VFS_UNLOCK_GIANT(vfslocked);
- NFSD_LOCK();
return (error);
}
+/*
+ * Version of nfsrv_fhtovp() that can be called holding nfsd_mtx: it will
+ * drop and re-acquire the lock for the caller.
+ */
+int
+nfsrv_fhtovp_locked(fhandle_t *fhp, int lockflag, struct vnode **vpp,
+ struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
+ int *rdonlyp, int pubflag)
+{
+ int error;
+
+ NFSD_LOCK_ASSERT();
+ NFSD_UNLOCK();
+ error = nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp,
+ pubflag);
+ NFSD_LOCK();
+ return (error);
+}
/*
* WebNFS: check if a filehandle is a public filehandle. For v3, this
OpenPOWER on IntegriCloud