- Turn all explicit giant acquires into conditional VFS_LOCK_GIANTs.

Only ops which used namei still remained.
 - Implement a scheme for reducing the overhead of tracking which vops
   require giant by constantly reducing the number of recursive giant
   acquires to one, leaving us with only one vfslocked variable.
 - Remove all NFSD lock acquisition and release from the individual nfs
   ops.  Careful examination has shown that they are not required.  This
   greatly simplifies the code.

Sponsored by:	Isilon Systems, Inc.
Discussed with:	rwatson
Tested by:	kkenn
Approved by:	re
This commit is contained in:
Jeff Roberson 2007-03-17 18:18:08 +00:00
parent 4499aff6ec
commit 37374fc852
7 changed files with 236 additions and 644 deletions

View File

@ -358,11 +358,8 @@ int nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
struct thread *td, struct mbuf **mrq);
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 *,
int nfsrv_fhtovp(fhandle_t *, int, struct vnode **, int *, 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

@ -218,9 +218,11 @@ loop:
ret = RC_DROPIT;
} else if (rp->rc_flag & RC_REPSTATUS) {
nfsrvstats.srvcache_nonidemdonehits++;
NFSD_UNLOCK();
*repp = nfs_rephead(0, nd, rp->rc_status,
&mb, &bpos);
ret = RC_REPLY;
NFSD_LOCK();
} else if (rp->rc_flag & RC_REPMBUF) {
nfsrvstats.srvcache_nonidemdonehits++;
NFSD_UNLOCK();

View File

@ -145,13 +145,9 @@ nfs_rephead(int siz, struct nfsrv_descript *nd, int err,
caddr_t bpos;
struct mbuf *mb;
/* XXXRW: not 100% clear the lock is needed here. */
NFSD_LOCK_ASSERT();
nd->nd_repstat = err;
if (err && (nd->nd_flag & ND_NFSV3) == 0) /* XXX recheck */
siz = 0;
NFSD_UNLOCK();
MGETHDR(mreq, M_TRYWAIT, MT_DATA);
mb = mreq;
/*
@ -164,7 +160,6 @@ nfs_rephead(int siz, struct nfsrv_descript *nd, int err,
MCLGET(mreq, M_TRYWAIT);
} else
mreq->m_data += min(max_hdr, M_TRAILINGSPACE(mreq));
NFSD_LOCK();
tl = mtod(mreq, u_int32_t *);
bpos = ((caddr_t)tl) + mreq->m_len;
*tl++ = txdr_unsigned(nd->nd_retxid);
@ -246,18 +241,13 @@ nfs_realign(struct mbuf **pm, int hsiz) /* XXX COMMON */
struct mbuf *n = NULL;
int off = 0;
/* XXXRW: may not need lock? */
NFSD_LOCK_ASSERT();
++nfs_realign_test;
while ((m = *pm) != NULL) {
if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) {
NFSD_UNLOCK();
MGET(n, M_TRYWAIT, MT_DATA);
if (m->m_len >= MINCLSIZE) {
MCLGET(n, M_TRYWAIT);
}
NFSD_LOCK();
n->m_len = 0;
break;
}

View File

@ -621,10 +621,11 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
int error, rdonly, linklen;
struct componentname *cnp = &ndp->ni_cnd;
int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0;
int dvfslocked;
int vfslocked;
NFSD_LOCK_ASSERT();
NFSD_UNLOCK();
vfslocked = 0;
dvfslocked = 0;
*retdirp = NULL;
cnp->cn_flags |= NOMACCHECK;
cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
@ -642,14 +643,14 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
md = md->m_next;
if (md == NULL) {
error = EBADRPC;
goto out_nogiant;
goto out;
}
fromcp = mtod(md, caddr_t);
rem = md->m_len;
}
if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
error = EACCES;
goto out_nogiant;
goto out;
}
*tocp++ = *fromcp++;
rem--;
@ -662,20 +663,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_nogiant;
goto out;
}
/*
* Extract and set starting directory.
*
* XXXRW: For now, acquire Giant unconditionally to avoid tracking it
* on multiple vnodes.
*/
error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
nam, &rdonly, pubflag);
mtx_lock(&Giant); /* VFS */
error = nfsrv_fhtovp(fhp, FALSE, &dp, &dvfslocked,
ndp->ni_cnd.cn_cred, slp, nam, &rdonly, pubflag);
if (error)
goto out;
vfslocked = VFS_LOCK_GIANT(dp->v_mount);
if (dp->v_type != VDIR) {
vrele(dp);
error = ENOTDIR;
@ -753,8 +751,14 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
if (pubflag) {
ndp->ni_rootdir = rootvnode;
ndp->ni_loopcnt = 0;
if (cnp->cn_pnbuf[0] == '/')
if (cnp->cn_pnbuf[0] == '/') {
int tvfslocked;
tvfslocked = VFS_LOCK_GIANT(rootvnode->v_mount);
VFS_UNLOCK_GIANT(vfslocked);
dp = rootvnode;
vfslocked = tvfslocked;
}
} else {
cnp->cn_flags |= NOCROSSMOUNT;
}
@ -779,7 +783,11 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
* In either case ni_startdir will be dereferenced and NULLed
* out.
*/
if (vfslocked)
ndp->ni_cnd.cn_flags |= GIANTHELD;
error = lookup(ndp);
vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
ndp->ni_cnd.cn_flags &= ~GIANTHELD;
if (error)
break;
@ -888,18 +896,27 @@ 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;
ndp->ni_dvp = NULL;
ndp->ni_startdir = NULL;
cnp->cn_flags &= ~HASBUF;
VFS_UNLOCK_GIANT(vfslocked);
vfslocked = 0;
} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
ndp->ni_dvp = NULL;
}
NFSD_LOCK();
/*
* This differs from normal namei() in that even on failure we may
* return with Giant held due to the dirp return. Make sure we only
* have not recursed however. The calling code only expects to drop
* one acquire.
*/
if (vfslocked || dvfslocked)
ndp->ni_cnd.cn_flags |= GIANTHELD;
if (vfslocked && dvfslocked)
VFS_UNLOCK_GIANT(vfslocked);
return (error);
}
@ -914,8 +931,6 @@ nfsm_adj(struct mbuf *mp, int len, int nul)
int count, i;
char *cp;
NFSD_LOCK_DONTCARE();
/*
* Trim from tail. Scan the mbuf chain,
* calculating its length and finding the last mbuf.
@ -1064,13 +1079,9 @@ 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,
nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, int *vfslockedp,
struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
int *rdonlyp, int pubflag)
{
@ -1079,13 +1090,12 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
int i;
struct ucred *credanon;
int error, exflags;
int vfslocked;
#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */
struct sockaddr_int *saddr;
#endif
int vfslocked;
NFSD_UNLOCK_ASSERT();
*vfslockedp = 0;
*vpp = NULL;
if (nfs_ispublicfh(fhp)) {
@ -1135,28 +1145,13 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
VOP_UNLOCK(*vpp, 0, td);
out:
vfs_rel(mp);
VFS_UNLOCK_GIANT(vfslocked);
if (error) {
VFS_UNLOCK_GIANT(vfslocked);
} else
*vfslockedp = vfslocked;
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
@ -1229,7 +1224,6 @@ nfsrv_errmap(struct nfsrv_descript *nd, int err)
const short *defaulterrp, *errp;
int e;
NFSD_LOCK_DONTCARE();
if (nd->nd_flag & ND_NFSV3) {
if (nd->nd_procnum <= NFSPROC_COMMIT) {
@ -1263,8 +1257,6 @@ nfsrvw_sort(gid_t *list, int num)
int i, j;
gid_t v;
NFSD_LOCK_DONTCARE();
/* Insertion sort. */
for (i = 1; i < num; i++) {
v = list[i];
@ -1283,8 +1275,6 @@ nfsrv_setcred(struct ucred *incred, struct ucred *outcred)
{
int i;
NFSD_LOCK_DONTCARE();
bzero((caddr_t)outcred, sizeof (struct ucred));
refcount_init(&outcred->cr_ref, 1);
outcred->cr_uid = incred->cr_uid;
@ -1303,8 +1293,6 @@ nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
{
u_int32_t *tl;
NFSD_LOCK_DONTCARE();
if (v3) {
tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
*tl++ = txdr_unsigned(NFSX_V3FH);
@ -1331,8 +1319,6 @@ nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
{
u_int32_t *tl;
NFSD_LOCK_DONTCARE();
tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
if (tl == NULL)
return EBADRPC;
@ -1365,8 +1351,6 @@ nfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
{
u_int32_t *tl;
NFSD_LOCK_DONTCARE();
tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
if (tl == NULL)
return EBADRPC;
@ -1380,26 +1364,17 @@ nfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
void
nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
char **bp, char **be, caddr_t bpos, int droplock)
char **bp, char **be, caddr_t bpos)
{
struct mbuf *nmp;
NFSD_LOCK_DONTCARE();
if (droplock)
NFSD_LOCK_ASSERT();
else
NFSD_UNLOCK_ASSERT();
NFSD_UNLOCK_ASSERT();
if (*bp >= *be) {
if (*mp == mb)
(*mp)->m_len += *bp - bpos;
if (droplock)
NFSD_UNLOCK();
MGET(nmp, M_TRYWAIT, MT_DATA);
MCLGET(nmp, M_TRYWAIT);
if (droplock)
NFSD_LOCK();
nmp->m_len = NFSMSIZ(nmp);
(*mp)->m_next = nmp;
*mp = nmp;
@ -1416,8 +1391,6 @@ nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
u_int32_t *tl;
int fhlen;
NFSD_LOCK_DONTCARE();
if (nfsd->nd_flag & ND_NFSV3) {
tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
if (tl == NULL)
@ -1445,8 +1418,6 @@ nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
u_int32_t *tl;
int toclient = 0;
NFSD_LOCK_DONTCARE();
tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
if (tl == NULL)
return EBADRPC;

View File

@ -467,6 +467,7 @@ nfssvc_nfsd(struct thread *td)
procrastinate = nfsrvw_procrastinate_v3;
else
procrastinate = nfsrvw_procrastinate;
NFSD_UNLOCK();
if (writes_todo || (!(nd->nd_flag & ND_NFSV3) &&
nd->nd_procnum == NFSPROC_WRITE &&
procrastinate > 0 && !notstarted))
@ -475,6 +476,7 @@ nfssvc_nfsd(struct thread *td)
else
error = (*(nfsrv3_procs[nd->nd_procnum]))(nd,
slp, nfsd->nfsd_td, &mreq);
NFSD_LOCK();
if (mreq == NULL)
break;
if (error != 0 && error != NFSERR_RETVOID) {

View File

@ -161,7 +161,7 @@ void nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb,
caddr_t *bpos);
void nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos);
void nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
char **bp, char **be, caddr_t bpos, int droplock);
char **bp, char **be, caddr_t bpos);
#define nfsm_srvfhtom(f, v3) \
nfsm_srvfhtom_xx((f), (v3), &mb, &bpos)
@ -179,9 +179,6 @@ void nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
nfsm_srvfattr(nfsd, (a), (f))
#define nfsm_clget \
nfsm_clget_xx(&tl, mb, &mp, &bp, &be, bpos, 1)
#define nfsm_clget_nolock \
nfsm_clget_xx(&tl, mb, &mp, &bp, &be, bpos, 0)
nfsm_clget_xx(&tl, mb, &mp, &bp, &be, bpos)
#endif