diff options
author | rwatson <rwatson@FreeBSD.org> | 2006-11-24 11:53:16 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2006-11-24 11:53:16 +0000 |
commit | 65d3526a649a6b8c43d95db3632ccd500d0435e7 (patch) | |
tree | e361363025d1a88f47fe0ef4f20658e774c2ac7d /sys/nfsserver/nfs_srvsubs.c | |
parent | 3caf2aa43d126fdf7524e1e18b68a6859dcbbf41 (diff) | |
download | FreeBSD-src-65d3526a649a6b8c43d95db3632ccd500d0435e7.zip FreeBSD-src-65d3526a649a6b8c43d95db3632ccd500d0435e7.tar.gz |
Push Giant a bit further off the NFS server in a number of straight
forward cases by converting from unconditional acquisition of Giant
around vnode operations to conditional acquisition:
- Remove nfsrv_access_withgiant(), and cause nfsrv_access() to now
assert that Giant will be held if it is required for the vnode.
- Add nfsrv_fhtovp_locked(), which will drop the NFS server lock if
required, and modify nfsrv_fhtovp() to conditionally acquire
Giant if required.
- In the VOP's not dealing with more than one vnode at a time (i.e.,
not involving a lookup), conditionally acquire Giant.
This removes Giant use for MPSAFE file systems for a number of quite
important RPCs, including getattr, read, write. It leaves
unconditional Giant acquisitions in vnode operations that interact
with the name space or more than one vnode at a time as these
require further work.
Tested by: kris
Reviewed by: kib
Diffstat (limited to 'sys/nfsserver/nfs_srvsubs.c')
-rw-r--r-- | sys/nfsserver/nfs_srvsubs.c | 42 |
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 |