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
This commit is contained in:
Robert Watson 2006-11-24 11:53:16 +00:00
parent df19774d2f
commit c2a9c542a9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=164585
3 changed files with 297 additions and 224 deletions

View File

@ -360,6 +360,9 @@ int nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
struct thread *td, struct mbuf **mrq);
int nfsrv_fhtovp(fhandle_t *, int, struct vnode **, struct ucred *,
struct nfssvc_sock *, struct sockaddr *, int *, int);
int nfsrv_fhtovp_locked(fhandle_t *, int, struct vnode **,
struct ucred *, struct nfssvc_sock *, struct sockaddr *, int *,
int);
int nfsrv_setpublicfs(struct mount *, struct netexport *,
struct export_args *);
int nfs_ispublicfh(fhandle_t *);

File diff suppressed because it is too large Load Diff

View File

@ -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 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
} 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