--- //depot/user/rwatson/netperf/sys/nfsserver/nfs.h 2004/04/04 14:07:19 +++ //depot/user/rwatson/net/sys/nfsserver/nfs.h 2004/04/06 12:56:33 @@ -120,6 +120,13 @@ #ifdef _KERNEL +extern struct mtx nfsd_mtx; +#define NFSD_LOCK_ASSERT() mtx_assert(&nfsd_mtx, MA_OWNED) +#define NFSD_UNLOCK_ASSERT() mtx_assert(&nfsd_mtx, MA_NOTOWNED) +#define NFSD_LOCK_DONTCARE() +#define NFSD_LOCK() mtx_lock(&nfsd_mtx) +#define NFSD_UNLOCK() mtx_unlock(&nfsd_mtx) + #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_NFSRVDESC); MALLOC_DECLARE(M_NFSD); --- //depot/user/rwatson/netperf/sys/nfsserver/nfs_serv.c 2004/03/12 21:34:00 +++ //depot/user/rwatson/net/sys/nfsserver/nfs_serv.c 2004/04/06 13:32:27 @@ -183,6 +183,9 @@ u_long testmode, nfsmode; int v3 = (nfsd->nd_flag & ND_NFSV3); + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); if (!v3) panic("nfsrv3_access: v3 proc called on a v2 connection"); @@ -215,8 +218,10 @@ if ((nfsmode & testmode) && nfsrv_access(vp, VEXEC, cred, rdonly, td, 0)) nfsmode &= ~testmode; + NFSD_UNLOCK(); getret = VOP_GETATTR(vp, vap, cred, td); vput(vp); + NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, vap); @@ -249,6 +254,9 @@ int error = 0, rdonly; struct mbuf *mb, *mreq; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); @@ -258,8 +266,10 @@ error = 0; goto nfsmout; } + NFSD_UNLOCK(); error = VOP_GETATTR(vp, vap, cred, td); vput(vp); + NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); if (error) { @@ -303,14 +313,20 @@ struct timespec guard; struct mount *mp = NULL; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); + /* XXXRW: need to drop NFSD lock here? */ if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { error = ESTALE; goto out; } + NFSD_UNLOCK(); (void) vn_start_write(NULL, &mp, V_WAIT); + NFSD_LOCK(); VATTR_NULL(vap); if (v3) { nfsm_srvsattr(vap); @@ -367,13 +383,17 @@ * vp now an active resource, pay careful attention to cleanup */ if (v3) { + NFSD_UNLOCK(); error = preat_ret = VOP_GETATTR(vp, &preat, cred, td); + NFSD_LOCK(); if (!error && gcheck && (preat.va_ctime.tv_sec != guard.tv_sec || preat.va_ctime.tv_nsec != guard.tv_nsec)) error = NFSERR_NOT_SYNC; if (error) { + NFSD_UNLOCK(); vput(vp); + NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_WCCDATA(v3)); if (v3) @@ -400,13 +420,19 @@ td, 0)) != 0) goto out; } + NFSD_UNLOCK(); error = VOP_SETATTR(vp, vap, cred, td); postat_ret = VOP_GETATTR(vp, vap, cred, td); + NFSD_LOCK(); if (!error) error = postat_ret; out: - if (vp != NULL) + if (vp != NULL) { + NFSD_UNLOCK(); vput(vp); + NFSD_LOCK(); + } + vp = NULL; nfsm_reply(NFSX_WCCORFATTR(v3)); if (v3) { @@ -420,9 +446,11 @@ /* fall through */ nfsmout: + NFSD_UNLOCK(); if (vp) vput(vp); vn_finished_write(mp); + NFSD_LOCK(); return(error); } @@ -448,6 +476,9 @@ struct mbuf *mb, *mreq; struct vattr va, dirattr, *vap = &va; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); ndclear(&nd); @@ -470,7 +501,9 @@ if (error) { if (dirp) { + NFSD_UNLOCK(); vrele(dirp); + NFSD_LOCK(); dirp = NULL; } nfsm_reply(NFSX_POSTOPATTR(v3)); @@ -502,6 +535,7 @@ * via the original nd. Confused? You aren't alone! */ ind = nd; + NFSD_UNLOCK(); VOP_UNLOCK(nd.ni_vp, 0, td); ind.ni_pathlen = strlen(nfs_pub.np_index); ind.ni_cnd.cn_nameptr = ind.ni_cnd.cn_pnbuf = @@ -525,6 +559,7 @@ nd.ni_startdir = NULL; ndp = &ind; } + NFSD_LOCK(); error = 0; } /* @@ -535,14 +570,18 @@ */ if (ndp->ni_vp->v_mount != nfs_pub.np_mount) { + NFSD_UNLOCK(); vput(nd.ni_vp); + NFSD_LOCK(); nd.ni_vp = NULL; error = EPERM; } } if (dirp) { + NFSD_UNLOCK(); vrele(dirp); + NFSD_LOCK(); dirp = NULL; } @@ -565,6 +604,7 @@ * is not as critical as ni_dvp resources in other routines, but * it helps. */ + NFSD_UNLOCK(); vrele(ndp->ni_startdir); ndp->ni_startdir = NULL; NDFREE(&nd, NDF_ONLY_PNBUF); @@ -581,6 +621,7 @@ error = VOP_GETATTR(vp, vap, cred, td); vput(vp); + NFSD_LOCK(); ndp->ni_vp = NULL; nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3)); if (error) { @@ -599,6 +640,7 @@ } nfsmout: + NFSD_UNLOCK(); if (dirp) vrele(dirp); NDFREE(&nd, NDF_ONLY_PNBUF); @@ -606,6 +648,7 @@ vrele(ndp->ni_startdir); if (ndp->ni_vp) vput(ndp->ni_vp); + NFSD_LOCK(); return (error); } @@ -634,6 +677,9 @@ fhandle_t *fhp; struct uio io, *uiop = &io; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); #ifndef nolint mp = NULL; @@ -643,6 +689,7 @@ nfsm_srvmtofh(fhp); len = 0; i = 0; + NFSD_UNLOCK(); while (len < NFS_MAXPATHLEN) { MGET(nmp, M_TRYWAIT, MT_DATA); MCLGET(nmp, M_TRYWAIT); @@ -670,6 +717,7 @@ uiop->uio_rw = UIO_READ; uiop->uio_segflg = UIO_SYSSPACE; uiop->uio_td = NULL; + NFSD_LOCK(); error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); if (error) { nfsm_reply(2 * NFSX_UNSIGNED); @@ -678,17 +726,17 @@ error = 0; goto nfsmout; } + NFSD_UNLOCK(); if (vp->v_type != VLNK) { if (v3) error = EINVAL; else error = ENXIO; - goto out; - } - error = VOP_READLINK(vp, uiop, cred); -out: + } else + error = VOP_READLINK(vp, uiop, cred); getret = VOP_GETATTR(vp, &attr, cred, td); vput(vp); + NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED); if (v3) @@ -709,8 +757,11 @@ nfsmout: if (mp3) m_freem(mp3); - if (vp) + if (vp) { + NFSD_UNLOCK(); vput(vp); + NFSD_LOCK(); + } return(error); } @@ -745,6 +796,9 @@ off_t off; int ioflag = 0; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); @@ -783,11 +837,13 @@ if ((error = nfsrv_access(vp, VREAD, cred, rdonly, td, 1)) != 0) error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 1); } + NFSD_UNLOCK(); getret = VOP_GETATTR(vp, vap, cred, td); if (!error) error = getret; if (error) { vput(vp); + NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_POSTOPATTR(v3)); if (v3) @@ -795,6 +851,7 @@ error = 0; goto nfsmout; } + NFSD_LOCK(); /* * Calculate byte count to read @@ -874,6 +931,7 @@ tl += (NFSX_V2FATTR / sizeof (u_int32_t)); } len = left = nfsm_rndup(cnt); + NFSD_UNLOCK(); if (cnt > 0) { /* * Generate the mbuf list with the uio_iov ref. to it. @@ -928,6 +986,7 @@ error = getret; m_freem(mreq); vput(vp); + NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_POSTOPATTR(v3)); if (v3) @@ -939,6 +998,7 @@ uiop->uio_resid = 0; } vput(vp); + NFSD_LOCK(); vp = NULL; nfsm_srvfillattr(vap, fp); tlen = len - uiop->uio_resid; @@ -955,8 +1015,10 @@ } *tl = txdr_unsigned(cnt); nfsmout: + NFSD_UNLOCK(); if (vp) vput(vp); + NFSD_LOCK(); return(error); } @@ -992,6 +1054,9 @@ off_t off; struct mount *mntp = NULL; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); if (mrep == NULL) { *mrq = NULL; @@ -1067,8 +1132,11 @@ error = 0; goto nfsmout; } - if (v3) + if (v3) { + NFSD_UNLOCK(); forat_ret = VOP_GETATTR(vp, &forat, cred, td); + NFSD_LOCK(); + } if (vp->v_type != VREG) { if (v3) error = EINVAL; @@ -1078,7 +1146,9 @@ if (!error) error = nfsrv_access(vp, VWRITE, cred, rdonly, td, 1); if (error) { + NFSD_UNLOCK(); vput(vp); + NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_WCCDATA(v3)); if (v3) @@ -1087,6 +1157,7 @@ goto nfsmout; } + NFSD_UNLOCK(); if (len > 0) { MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP, M_WAITOK); @@ -1121,11 +1192,13 @@ uiop->uio_td = NULL; uiop->uio_offset = off; error = VOP_WRITE(vp, uiop, ioflags, cred); + /* XXXRW: unlocked write. */ nfsrvstats.srvvop_writes++; FREE((caddr_t)iv, M_TEMP); } aftat_ret = VOP_GETATTR(vp, vap, cred, td); vput(vp); + NFSD_LOCK(); vp = NULL; if (!error) error = aftat_ret; @@ -1163,9 +1236,11 @@ } error = 0; nfsmout: + NFSD_UNLOCK(); if (vp) vput(vp); vn_finished_write(mntp); + NFSD_LOCK(); return(error); } @@ -1199,6 +1274,9 @@ u_quad_t cur_usec; struct mount *mntp = NULL; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); #ifndef nolint i = 0; @@ -1352,8 +1430,11 @@ error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp, nfsd->nd_nam, &rdonly, TRUE); if (!error) { - if (v3) + if (v3) { + NFSD_UNLOCK(); forat_ret = VOP_GETATTR(vp, &forat, cred, td); + NFSD_LOCK(); + } if (vp->v_type != VREG) { if (v3) error = EINVAL; @@ -1365,6 +1446,7 @@ } if (!error) error = nfsrv_access(vp, VWRITE, cred, rdonly, td, 1); + NFSD_UNLOCK(); if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE) ioflags = IO_NODELOCKED; else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC) @@ -1406,6 +1488,7 @@ } if (!error) { error = VOP_WRITE(vp, uiop, ioflags, cred); + /* XXXRW: unlocked write. */ nfsrvstats.srvvop_writes++; vn_finished_write(mntp); } @@ -1417,6 +1500,7 @@ vput(vp); vp = NULL; } + NFSD_LOCK(); /* * Loop around generating replies for all write rpcs that have @@ -1511,6 +1595,8 @@ struct mbuf *mp; struct nfsrv_descript *p; + NFSD_LOCK_ASSERT(); + NFS_DPF(WG, ("C%03x-%03x", nfsd->nd_retxid & 0xfff, owp->nd_retxid & 0xfff)); LIST_REMOVE(nfsd, nd_hash); @@ -1577,6 +1663,9 @@ u_char cverf[NFSX_V3CREATEVERF]; struct mount *mp = NULL; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); #ifndef nolint rdev = 0; @@ -1589,7 +1678,9 @@ error = ESTALE; goto ereply; } + NFSD_UNLOCK(); (void) vn_start_write(NULL, &mp, V_WAIT); + NFSD_LOCK(); nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; @@ -1608,7 +1699,9 @@ error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, &dirp, v3, &dirfor, &dirfor_ret, td, FALSE); if (dirp && !v3) { + NFSD_UNLOCK(); vrele(dirp); + NFSD_LOCK(); dirp = NULL; } if (error) { @@ -1683,6 +1776,7 @@ * The only possible error we can have at this point is EEXIST. * nd.ni_vp will also be non-NULL in that case. */ + NFSD_UNLOCK(); if (nd.ni_vp == NULL) { if (vap->va_mode == (mode_t)VNOVAL) vap->va_mode = 0; @@ -1801,6 +1895,7 @@ } } ereply: + NFSD_LOCK(); nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3)); if (v3) { if (!error) { @@ -1817,6 +1912,7 @@ error = 0; nfsmout: + NFSD_UNLOCK(); if (nd.ni_startdir) { vrele(nd.ni_startdir); nd.ni_startdir = NULL; @@ -1833,6 +1929,7 @@ if (nd.ni_vp) vput(nd.ni_vp); vn_finished_write(mp); + NFSD_LOCK(); return (error); } @@ -1862,6 +1959,9 @@ struct mount *mp = NULL; int v3 = (nfsd->nd_flag & ND_NFSV3); + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); if (!v3) panic("nfsrv_mknod: v3 proc called on a v2 connection"); @@ -1873,7 +1973,9 @@ error = ESTALE; goto ereply; } + NFSD_UNLOCK(); (void) vn_start_write(NULL, &mp, V_WAIT); + NFSD_LOCK(); nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; @@ -1919,6 +2021,7 @@ vap->va_type = vtyp; if (vap->va_mode == (mode_t)VNOVAL) vap->va_mode = 0; + NFSD_UNLOCK(); if (vtyp == VSOCK) { vrele(nd.ni_startdir); nd.ni_startdir = NULL; @@ -1991,6 +2094,7 @@ VOP_UNLOCK(dirp, 0, td); } ereply: + NFSD_LOCK(); nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1)); if (v3) { if (!error) { @@ -1999,9 +2103,12 @@ } nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); } + NFSD_UNLOCK(); vn_finished_write(mp); + NFSD_LOCK(); return (0); nfsmout: + NFSD_UNLOCK(); if (dirp) vrele(dirp); if (nd.ni_startdir) @@ -2016,6 +2123,7 @@ if (nd.ni_vp) vput(nd.ni_vp); vn_finished_write(mp); + NFSD_LOCK(); return (error); } @@ -2041,6 +2149,9 @@ fhandle_t *fhp; struct mount *mp = NULL; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); ndclear(&nd); @@ -2050,7 +2161,9 @@ error = ESTALE; goto ereply; } + NFSD_UNLOCK(); (void) vn_start_write(NULL, &mp, V_WAIT); + NFSD_LOCK(); nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; @@ -2058,6 +2171,7 @@ nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, &dirp, v3, &dirfor, &dirfor_ret, td, FALSE); + NFSD_UNLOCK(); if (dirp && !v3) { vrele(dirp); dirp = NULL; @@ -2103,6 +2217,7 @@ vrele(dirp); dirp = NULL; } + NFSD_LOCK(); ereply: nfsm_reply(NFSX_WCCDATA(v3)); if (v3) { @@ -2110,6 +2225,7 @@ error = 0; } nfsmout: + NFSD_UNLOCK(); NDFREE(&nd, NDF_ONLY_PNBUF); if (nd.ni_dvp) { if (nd.ni_dvp == nd.ni_vp) @@ -2120,6 +2236,7 @@ if (nd.ni_vp) vput(nd.ni_vp); vn_finished_write(mp); + NFSD_LOCK(); return(error); } @@ -2148,6 +2265,9 @@ uid_t saved_uid; struct mount *mp = NULL; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); #ifndef nolint fvp = NULL; @@ -2180,7 +2300,9 @@ error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md, &dpos, &fdirp, v3, &fdirfor, &fdirfor_ret, td, FALSE); if (fdirp && !v3) { + NFSD_UNLOCK(); vrele(fdirp); + NFSD_LOCK(); fdirp = NULL; } if (error) { @@ -2201,6 +2323,7 @@ tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; error = nfs_namei(&tond, tfhp, len2, slp, nam, &md, &dpos, &tdirp, v3, &tdirfor, &tdirfor_ret, td, FALSE); + NFSD_UNLOCK(); if (tdirp && !v3) { vrele(tdirp); tdirp = NULL; @@ -2286,9 +2409,11 @@ /* fall through */ out1: + NFSD_LOCK(); nfsm_reply(2 * NFSX_WCCDATA(v3)); if (v3) { /* Release existing locks to prevent deadlock. */ + NFSD_UNLOCK(); if (tond.ni_dvp) { if (tond.ni_dvp == tond.ni_vp) vrele(tond.ni_dvp); @@ -2310,6 +2435,7 @@ tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, td); VOP_UNLOCK(tdirp, 0, td); } + NFSD_LOCK(); nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); } @@ -2320,6 +2446,7 @@ /* * Clear out tond related fields */ + NFSD_UNLOCK(); if (tdirp) vrele(tdirp); if (tond.ni_startdir) @@ -2348,6 +2475,7 @@ vrele(fromnd.ni_vp); vn_finished_write(mp); + NFSD_LOCK(); return (error); } @@ -2373,6 +2501,9 @@ fhandle_t *fhp, *dfhp; struct mount *mp = NULL; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); ndclear(&nd); @@ -2383,7 +2514,9 @@ error = ESTALE; goto ereply; } + NFSD_UNLOCK(); (void) vn_start_write(NULL, &mp, V_WAIT); + NFSD_LOCK(); nfsm_srvmtofh(dfhp); nfsm_srvnamesiz(len); @@ -2398,6 +2531,7 @@ error = 0; goto nfsmout; } + NFSD_UNLOCK(); if (v3) getret = VOP_GETATTR(vp, &at, cred, td); if (vp->v_type == VDIR) { @@ -2408,8 +2542,10 @@ nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT; + NFSD_LOCK(); error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos, &dirp, v3, &dirfor, &dirfor_ret, td, FALSE); + NFSD_UNLOCK(); if (dirp && !v3) { vrele(dirp); dirp = NULL; @@ -2463,6 +2599,7 @@ VOP_UNLOCK(dirp, 0, td); } } + NFSD_LOCK(); ereply: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); if (v3) { @@ -2473,6 +2610,7 @@ /* fall through */ nfsmout: + NFSD_UNLOCK(); NDFREE(&nd, NDF_ONLY_PNBUF); if (dirp) vrele(dirp); @@ -2487,6 +2625,7 @@ if (nd.ni_vp) vrele(nd.ni_vp); vn_finished_write(mp); + NFSD_LOCK(); return(error); } @@ -2516,6 +2655,9 @@ fhandle_t *fhp; struct mount *mp = NULL; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); ndclear(&nd); @@ -2525,13 +2667,16 @@ error = ESTALE; goto out; } + NFSD_UNLOCK(); (void) vn_start_write(NULL, &mp, V_WAIT); + NFSD_LOCK(); nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, &dirp, v3, &dirfor, &dirfor_ret, td, FALSE); + NFSD_UNLOCK(); if (dirp && !v3) { vrele(dirp); dirp = NULL; @@ -2630,6 +2775,7 @@ vrele(nd.ni_startdir); nd.ni_startdir = NULL; } + NFSD_LOCK(); nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); if (v3) { if (!error) { @@ -2642,6 +2788,7 @@ /* fall through */ nfsmout: + NFSD_UNLOCK(); NDFREE(&nd, NDF_ONLY_PNBUF); if (nd.ni_dvp) { if (nd.ni_dvp == nd.ni_vp) @@ -2659,6 +2806,7 @@ FREE(pathcp, M_TEMP); vn_finished_write(mp); + NFSD_LOCK(); return (error); } @@ -2688,6 +2836,9 @@ fhandle_t *fhp; struct mount *mp = NULL; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); ndclear(&nd); @@ -2697,7 +2848,9 @@ error = ESTALE; goto out; } + NFSD_UNLOCK(); (void) vn_start_write(NULL, &mp, V_WAIT); + NFSD_LOCK(); nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = CREATE; @@ -2706,7 +2859,9 @@ error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, &dirp, v3, &dirfor, &dirfor_ret, td, FALSE); if (dirp && !v3) { + NFSD_UNLOCK(); vrele(dirp); + NFSD_LOCK(); dirp = NULL; } if (error) { @@ -2729,6 +2884,7 @@ * nd.ni_vp, if it exists, is referenced but not locked. */ + NFSD_UNLOCK(); vap->va_type = VDIR; if (nd.ni_vp != NULL) { NDFREE(&nd, NDF_ONLY_PNBUF); @@ -2783,6 +2939,7 @@ VOP_UNLOCK(dirp, 0, td); } } + NFSD_LOCK(); nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); if (v3) { if (!error) { @@ -2800,6 +2957,7 @@ /* fall through */ nfsmout: + NFSD_UNLOCK(); if (dirp) vrele(dirp); if (nd.ni_dvp) { @@ -2816,6 +2974,7 @@ vrele(nd.ni_vp); } vn_finished_write(mp); + NFSD_LOCK(); return (error); } @@ -2841,6 +3000,9 @@ struct nameidata nd; struct mount *mp = NULL; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); ndclear(&nd); @@ -2850,7 +3012,9 @@ error = ESTALE; goto out; } + NFSD_UNLOCK(); (void) vn_start_write(NULL, &mp, V_WAIT); + NFSD_LOCK(); nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = DELETE; @@ -2890,6 +3054,7 @@ * Issue or abort op. Since SAVESTART is not set, path name * component is freed by the VOP after either. */ + NFSD_UNLOCK(); if (!error) error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); NDFREE(&nd, NDF_ONLY_PNBUF); @@ -2914,6 +3079,7 @@ VOP_UNLOCK(dirp, 0, td); } } + NFSD_LOCK(); nfsm_reply(NFSX_WCCDATA(v3)); error = 0; if (v3) @@ -2921,6 +3087,7 @@ /* fall through */ nfsmout: + NFSD_UNLOCK(); NDFREE(&nd, NDF_ONLY_PNBUF); if (dirp) vrele(dirp); @@ -2934,6 +3101,7 @@ vput(nd.ni_vp); vn_finished_write(mp); + NFSD_LOCK(); return(error); } @@ -3003,6 +3171,9 @@ u_quad_t off, toff, verf; u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */ + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); @@ -3029,7 +3200,9 @@ error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); if (!error && vp->v_type != VDIR) { error = ENOTDIR; + NFSD_UNLOCK(); vput(vp); + NFSD_LOCK(); vp = NULL; } if (error) { @@ -3043,6 +3216,7 @@ /* * Obtain lock on vnode for this section of the code */ + NFSD_UNLOCK(); if (v3) { error = getret = VOP_GETATTR(vp, &at, cred, td); #if 0 @@ -3053,10 +3227,14 @@ error = NFSERR_BAD_COOKIE; #endif } - if (!error) + if (!error) { + NFSD_LOCK(); error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0); + NFSD_UNLOCK(); + } if (error) { vput(vp); + NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_POSTOPATTR(v3)); if (v3) @@ -3102,6 +3280,7 @@ free((caddr_t)rbuf, M_TEMP); if (cookies) free((caddr_t)cookies, M_TEMP); + NFSD_LOCK(); nfsm_reply(NFSX_POSTOPATTR(v3)); if (v3) nfsm_srvpostop_attr(getret, &at); @@ -3118,6 +3297,7 @@ if (siz == 0) { vrele(vp); vp = NULL; + NFSD_LOCK(); nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + 2 * NFSX_UNSIGNED); if (v3) { @@ -3165,6 +3345,7 @@ goto again; } + NFSD_LOCK(); len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz); if (v3) { @@ -3241,7 +3422,9 @@ cookiep++; ncookies--; } + NFSD_UNLOCK(); vrele(vp); + NFSD_LOCK(); vp = NULL; nfsm_clget; *tl = nfsrv_nfs_false; @@ -3261,8 +3444,11 @@ FREE((caddr_t)cookies, M_TEMP); nfsmout: - if (vp) + if (vp) { + NFSD_UNLOCK(); vrele(vp); + NFSD_LOCK(); + } return(error); } @@ -3296,6 +3482,9 @@ u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */ int v3 = (nfsd->nd_flag & ND_NFSV3); + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); if (!v3) panic("nfsrv_readdirplus: v3 proc called on a v2 connection"); @@ -3328,6 +3517,7 @@ error = 0; goto nfsmout; } + NFSD_UNLOCK(); error = getret = VOP_GETATTR(vp, &at, cred, td); #if 0 /* @@ -3336,10 +3526,14 @@ if (!error && toff && verf && verf != at.va_filerev) error = NFSERR_BAD_COOKIE; #endif - if (!error) + if (!error) { + NFSD_LOCK(); error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0); + NFSD_UNLOCK(); + } if (error) { vput(vp); + NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_V3POSTOPATTR); nfsm_srvpostop_attr(getret, &at); @@ -3378,6 +3572,7 @@ if (cookies) free((caddr_t)cookies, M_TEMP); free((caddr_t)rbuf, M_TEMP); + NFSD_LOCK(); nfsm_reply(NFSX_V3POSTOPATTR); nfsm_srvpostop_attr(getret, &at); error = 0; @@ -3392,6 +3587,7 @@ */ if (siz == 0) { vrele(vp); + NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED); @@ -3448,12 +3644,14 @@ vp = NULL; free((caddr_t)cookies, M_TEMP); free((caddr_t)rbuf, M_TEMP); + NFSD_LOCK(); nfsm_reply(NFSX_V3POSTOPATTR); nfsm_srvpostop_attr(getret, &at); error = 0; goto nfsmout; } vput(nvp); + NFSD_LOCK(); nvp = NULL; dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + @@ -3466,6 +3664,7 @@ bp = bpos; be = bp + M_TRAILINGSPACE(mp); + NFSD_UNLOCK(); /* Loop through the records and build reply */ while (cpos < cend && ncookies > 0) { if (dp->d_fileno != 0 && dp->d_type != DT_WHT) { @@ -3578,6 +3777,7 @@ ncookies--; } vrele(vp); + NFSD_LOCK(); vp = NULL; nfsm_clget; *tl = nfsrv_nfs_false; @@ -3596,8 +3796,11 @@ FREE((caddr_t)cookies, M_TEMP); FREE((caddr_t)rbuf, M_TEMP); nfsmout: - if (vp) + if (vp) { + NFSD_UNLOCK(); vrele(vp); + NFSD_LOCK(); + } return(error); } @@ -3624,6 +3827,9 @@ struct mount *mp = NULL; int v3 = (nfsd->nd_flag & ND_NFSV3); + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); if (!v3) panic("nfsrv_commit: v3 proc called on a v2 connection"); @@ -3633,7 +3839,9 @@ error = ESTALE; goto ereply; } + NFSD_UNLOCK(); (void) vn_start_write(NULL, &mp, V_WAIT); + NFSD_LOCK(); tl = nfsm_dissect(u_int32_t *, 3 * NFSX_UNSIGNED); /* @@ -3650,6 +3858,7 @@ error = 0; goto nfsmout; } + NFSD_UNLOCK(); for_ret = VOP_GETATTR(vp, &bfor, cred, td); if (cnt > MAX_COMMIT_COUNT) { @@ -3738,6 +3947,7 @@ aft_ret = VOP_GETATTR(vp, &aft, cred, td); vput(vp); vp = NULL; + NFSD_LOCK(); ereply: nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF); nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); @@ -3751,9 +3961,11 @@ error = 0; } nfsmout: + NFSD_UNLOCK(); if (vp) vput(vp); vn_finished_write(mp); + NFSD_LOCK(); return(error); } @@ -3781,6 +3993,9 @@ struct statfs statfs; u_quad_t tval; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); @@ -3793,9 +4008,11 @@ goto nfsmout; } sf = &statfs; + NFSD_UNLOCK(); error = VFS_STATFS(vp->v_mount, sf, td); getret = VOP_GETATTR(vp, &at, cred, td); vput(vp); + NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3)); if (v3) @@ -3830,8 +4047,11 @@ sfp->sf_bavail = txdr_unsigned(sf->f_bavail); } nfsmout: - if (vp) + if (vp) { + NFSD_UNLOCK(); vput(vp); + NFSD_LOCK(); + } return(error); } @@ -3858,6 +4078,9 @@ struct statfs sb; int v3 = (nfsd->nd_flag & ND_NFSV3); + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); if (!v3) panic("nfsrv_fsinfo: v3 proc called on a v2 connection"); @@ -3871,12 +4094,14 @@ goto nfsmout; } + NFSD_UNLOCK(); /* XXX Try to make a guess on the max file size. */ VFS_STATFS(vp->v_mount, &sb, td); maxfsize = (u_quad_t)0x80000000 * sb.f_bsize - 1; getret = VOP_GETATTR(vp, &at, cred, td); vput(vp); + NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO); nfsm_srvpostop_attr(getret, &at); @@ -3905,8 +4130,11 @@ NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | NFSV3FSINFO_CANSETTIME); nfsmout: - if (vp) + if (vp) { + NFSD_UNLOCK(); vput(vp); + NFSD_LOCK(); + } return(error); } @@ -3932,6 +4160,9 @@ fhandle_t *fhp; int v3 = (nfsd->nd_flag & ND_NFSV3); + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); if (!v3) panic("nfsrv_pathconf: v3 proc called on a v2 connection"); @@ -3944,6 +4175,7 @@ error = 0; goto nfsmout; } + NFSD_UNLOCK(); error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax); if (!error) error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax); @@ -3953,6 +4185,7 @@ error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc); getret = VOP_GETATTR(vp, &at, cred, td); vput(vp); + NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF); nfsm_srvpostop_attr(getret, &at); @@ -3975,8 +4208,11 @@ pc->pc_caseinsensitive = nfsrv_nfs_false; pc->pc_casepreserving = nfsrv_nfs_true; nfsmout: - if (vp) + if (vp) { + NFSD_UNLOCK(); vput(vp); + NFSD_LOCK(); + } return(error); } @@ -3993,6 +4229,8 @@ int error = NFSERR_RETVOID; struct mbuf *mb, *mreq; + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); nfsm_reply(0); nfsmout: @@ -4012,6 +4250,8 @@ int error; struct mbuf *mb, *mreq; + NFSD_LOCK_ASSERT(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); if (nfsd->nd_repstat) error = nfsd->nd_repstat; @@ -4044,6 +4284,10 @@ struct vattr vattr; int error; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + NFSD_UNLOCK(); + nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); if (flags & VWRITE) { /* Just vn_writechk() changed to check rdonly */ @@ -4057,7 +4301,8 @@ case VREG: case VDIR: case VLNK: - return (EROFS); + error = EROFS; + goto out; default: break; } @@ -4071,7 +4316,7 @@ } error = VOP_GETATTR(vp, &vattr, cred, td); if (error) - return (error); + goto out; error = VOP_ACCESS(vp, flags, cred, td); /* * Allow certain operations for the owner (reads and writes @@ -4079,5 +4324,7 @@ */ if (override && error == EACCES && cred->cr_uid == vattr.va_uid) error = 0; +out: + NFSD_LOCK(); return error; } --- //depot/user/rwatson/netperf/sys/nfsserver/nfs_srvcache.c 2004/04/04 14:07:19 +++ //depot/user/rwatson/net/sys/nfsserver/nfs_srvcache.c 2004/04/06 12:56:33 @@ -48,7 +48,9 @@ #include #include #include +#include #include +#include #include #include /* for sodupsockaddr */ @@ -158,6 +160,8 @@ caddr_t bpos; int ret; + NFSD_LOCK_ASSERT(); + /* * Don't cache recent requests for reliable transport protocols. * (Maybe we should for the case of a reconnect, but..) @@ -171,7 +175,8 @@ NFS_DPF(RC, ("H%03x", rp->rc_xid & 0xfff)); if ((rp->rc_flag & RC_LOCKED) != 0) { rp->rc_flag |= RC_WANTED; - (void) tsleep(rp, PZERO-1, "nfsrc", 0); + (void) msleep(rp, &nfsd_mtx, PZERO-1, + "nfsrc", 0); goto loop; } rp->rc_flag |= RC_LOCKED; @@ -192,8 +197,10 @@ ret = RC_REPLY; } else if (rp->rc_flag & RC_REPMBUF) { nfsrvstats.srvcache_nonidemdonehits++; + NFSD_UNLOCK(); *repp = m_copym(rp->rc_reply, 0, M_COPYALL, M_TRYWAIT); + NFSD_LOCK(); ret = RC_REPLY; } else { nfsrvstats.srvcache_idemdonehits++; @@ -211,15 +218,17 @@ nfsrvstats.srvcache_misses++; NFS_DPF(RC, ("M%03x", nd->nd_retxid & 0xfff)); if (numnfsrvcache < desirednfsrvcache) { + NFSD_UNLOCK(); rp = (struct nfsrvcache *)malloc((u_long)sizeof *rp, M_NFSD, M_WAITOK | M_ZERO); + NFSD_LOCK(); numnfsrvcache++; rp->rc_flag = RC_LOCKED; } else { rp = TAILQ_FIRST(&nfsrvlruhead); while ((rp->rc_flag & RC_LOCKED) != 0) { rp->rc_flag |= RC_WANTED; - (void) tsleep(rp, PZERO-1, "nfsrc", 0); + (void) msleep(rp, &nfsd_mtx, PZERO-1, "nfsrc", 0); rp = TAILQ_FIRST(&nfsrvlruhead); } rp->rc_flag |= RC_LOCKED; @@ -265,6 +274,8 @@ { struct nfsrvcache *rp; + NFSD_LOCK_ASSERT(); + if (!nd->nd_nam2) return; loop: @@ -274,7 +285,8 @@ NFS_DPF(RC, ("U%03x", rp->rc_xid & 0xfff)); if ((rp->rc_flag & RC_LOCKED) != 0) { rp->rc_flag |= RC_WANTED; - (void) tsleep(rp, PZERO-1, "nfsrc", 0); + (void) msleep(rp, &nfsd_mtx, PZERO-1, + "nfsrc", 0); goto loop; } rp->rc_flag |= RC_LOCKED; @@ -302,8 +314,10 @@ rp->rc_status = nd->nd_repstat; rp->rc_flag |= RC_REPSTATUS; } else { + NFSD_UNLOCK(); rp->rc_reply = m_copym(repmbuf, 0, M_COPYALL, M_TRYWAIT); + NFSD_LOCK(); rp->rc_flag |= RC_REPMBUF; } } @@ -326,6 +340,8 @@ { struct nfsrvcache *rp, *nextrp; + NFSD_LOCK_ASSERT(); + for (rp = TAILQ_FIRST(&nfsrvlruhead); rp != 0; rp = nextrp) { nextrp = TAILQ_NEXT(rp, rc_lru); LIST_REMOVE(rp, rc_hash); --- //depot/user/rwatson/netperf/sys/nfsserver/nfs_srvsock.c 2004/04/04 14:46:50 +++ //depot/user/rwatson/net/sys/nfsserver/nfs_srvsock.c 2004/04/06 16:11:56 @@ -144,9 +144,13 @@ 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; /* @@ -159,6 +163,7 @@ 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); @@ -240,13 +245,18 @@ 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; } @@ -285,6 +295,8 @@ int error = 0; struct mbuf *mrep, *md; + NFSD_LOCK_ASSERT(); + mrep = nd->nd_mrep; md = nd->nd_md; dpos = nd->nd_dpos; @@ -414,6 +426,9 @@ struct uio auio; int flags, error; + NFSD_UNLOCK_ASSERT(); + + /* XXXRW: Unlocked read. */ if ((slp->ns_flag & SLP_VALID) == 0) return; #ifdef notdef @@ -421,6 +436,7 @@ * Define this to test for nfsds handling this under heavy load. */ if (waitflag == M_DONTWAIT) { + NFSD_LOCK(); slp->ns_flag |= SLP_NEEDQ; goto dorecs; } @@ -437,11 +453,12 @@ * caller is likely holding a lock on the PCB for the socket, * not to mention the socket buffer, etc. */ +#if 0 slp->ns_flag |= SLP_NEEDQ; goto dorecs; +#endif - GIANT_REQUIRED; - + NFSD_LOCK(); auio.uio_td = NULL; if (so->so_type == SOCK_STREAM) { /* @@ -460,8 +477,10 @@ */ auio.uio_resid = 1000000000; flags = MSG_DONTWAIT; + NFSD_UNLOCK(); error = so->so_proto->pr_usrreqs->pru_soreceive (so, &nam, &auio, &mp, NULL, &flags); + NFSD_LOCK(); if (error || mp == NULL) { if (error == EWOULDBLOCK) slp->ns_flag |= SLP_NEEDQ; @@ -495,6 +514,7 @@ do { auio.uio_resid = 1000000000; flags = MSG_DONTWAIT; + NFSD_UNLOCK(); error = so->so_proto->pr_usrreqs->pru_soreceive (so, &nam, &auio, &mp, NULL, &flags); if (mp) { @@ -506,13 +526,16 @@ if (nam) FREE(nam, M_SONAME); m_freem(mp); + NFSD_LOCK(); continue; } + NFSD_LOCK(); nfs_realign(&mp, 10 * NFSX_UNSIGNED); rec->nr_address = nam; rec->nr_packet = mp; STAILQ_INSERT_TAIL(&slp->ns_rec, rec, nr_link); - } + } else + NFSD_LOCK(); if (error) { if ((so->so_proto->pr_flags & PR_CONNREQUIRED) && error != EWOULDBLOCK) { @@ -531,6 +554,7 @@ (STAILQ_FIRST(&slp->ns_rec) != NULL || (slp->ns_flag & (SLP_NEEDQ | SLP_DISCONN)))) nfsrv_wakenfsd(slp); + NFSD_UNLOCK(); } /* @@ -547,6 +571,8 @@ struct mbuf *om, *m2, *recm; u_int32_t recmark; + NFSD_LOCK_ASSERT(); + if (slp->ns_flag & SLP_GETSTREAM) panic("nfs getstream"); slp->ns_flag |= SLP_GETSTREAM; @@ -605,8 +631,10 @@ while (len < slp->ns_reclen) { if ((len + m->m_len) > slp->ns_reclen) { + NFSD_UNLOCK(); m2 = m_copym(m, 0, slp->ns_reclen - len, waitflag); + NFSD_LOCK(); if (m2) { if (om) { om->m_next = m2; @@ -649,8 +677,10 @@ *mpp = recm; if (slp->ns_flag & SLP_LASTFRAG) { struct nfsrv_rec *rec; + NFSD_UNLOCK(); rec = malloc(sizeof(struct nfsrv_rec), M_NFSRVDESC, waitflag == M_DONTWAIT ? M_NOWAIT : M_WAITOK); + NFSD_LOCK(); if (!rec) { m_freem(slp->ns_frag); } else { @@ -677,6 +707,8 @@ struct nfsrv_descript *nd; int error; + NFSD_LOCK_ASSERT(); + *ndp = NULL; if ((slp->ns_flag & SLP_VALID) == 0 || STAILQ_FIRST(&slp->ns_rec) == NULL) @@ -686,8 +718,10 @@ nam = rec->nr_address; m = rec->nr_packet; free(rec, M_NFSRVDESC); + NFSD_UNLOCK(); MALLOC(nd, struct nfsrv_descript *, sizeof (struct nfsrv_descript), M_NFSRVDESC, M_WAITOK); + NFSD_LOCK(); nd->nd_md = nd->nd_mrep = m; nd->nd_nam2 = nam; nd->nd_dpos = mtod(m, caddr_t); @@ -714,6 +748,8 @@ { struct nfsd *nd; + NFSD_LOCK_ASSERT(); + if ((slp->ns_flag & SLP_VALID) == 0) return; TAILQ_FOREACH(nd, &nfsd_head, nfsd_chain) { @@ -745,6 +781,14 @@ int error, soflags, flags; NET_ASSERT_GIANT(); + /* + * XXXRW: I think this is a good idea to avoid socket locking + * problems. There's certainly no need to hold the lock here, + * assuming the socket won't fall away from under us (which + * should be ensured by the caller). However, I'm not 100% + * sure: the BSD/OS code doesn't appear to. + */ + NFSD_UNLOCK_ASSERT(); soflags = so->so_proto->pr_flags; if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED)) @@ -785,6 +829,7 @@ u_quad_t cur_usec; s = splnet(); + NFSD_LOCK(); /* * Scan the write gathering queues for writes that need to be * completed now. @@ -795,6 +840,7 @@ LIST_FIRST(&slp->ns_tq)->nd_time <= cur_usec) nfsrv_wakenfsd(slp); } + NFSD_UNLOCK(); splx(s); callout_reset(&nfsrv_callout, nfsrv_ticks, nfsrv_timer, NULL); } --- //depot/user/rwatson/netperf/sys/nfsserver/nfs_srvsubs.c 2004/04/04 14:07:19 +++ //depot/user/rwatson/net/sys/nfsserver/nfs_srvsubs.c 2004/04/06 14:17:41 @@ -104,6 +104,8 @@ static int nfs_prev_nfssvc_sy_narg; static sy_call_t *nfs_prev_nfssvc_sy_call; +struct mtx nfsd_mtx; + /* * Mapping of old NFS Version 2 RPC numbers to generic numbers. */ @@ -526,6 +528,7 @@ switch (type) { case MOD_LOAD: + mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF); nfsrv_rpc_vers = txdr_unsigned(RPC_VER2); nfsrv_rpc_call = txdr_unsigned(RPC_CALL); nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY); @@ -542,10 +545,11 @@ if (nfsrv_ticks < 1) nfsrv_ticks = 1; + nfsrv_initcache(); /* Init the server request cache */ + NFSD_LOCK(); nfsrv_init(0); /* Init server data structures */ - nfsrv_initcache(); /* Init the server request cache */ - callout_init(&nfsrv_callout, 0); + NFSD_UNLOCK(); nfsrv_timer(0); nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; @@ -559,6 +563,7 @@ callout_stop(&nfsrv_callout); sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; + mtx_destroy(&nfsd_mtx); break; } return 0; @@ -605,6 +610,10 @@ struct componentname *cnp = &ndp->ni_cnd; int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0; + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + NFSD_UNLOCK(); + *retdirp = NULL; cnp->cn_flags |= NOMACCHECK; cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); @@ -648,8 +657,10 @@ /* * Extract and set starting directory. */ + NFSD_LOCK(); error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, nam, &rdonly, pubflag); + NFSD_UNLOCK(); if (error) goto out; if (dp->v_type != VDIR) { @@ -870,6 +881,7 @@ } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { ndp->ni_dvp = NULL; } + NFSD_LOCK(); return (error); } @@ -884,6 +896,8 @@ int count, i; char *cp; + NFSD_LOCK_DONTCARE(); + /* * Trim from tail. Scan the mbuf chain, * calculating its length and finding the last mbuf. @@ -1045,6 +1059,9 @@ struct sockaddr_int *saddr; #endif + GIANT_REQUIRED; /* VFS */ + NFSD_LOCK_ASSERT(); + *vpp = NULL; if (nfs_ispublicfh(fhp)) { @@ -1056,12 +1073,13 @@ mp = vfs_getvfs(&fhp->fh_fsid); if (!mp) return (ESTALE); + NFSD_UNLOCK(); error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); if (error) - return (error); + goto out; error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); if (error) - return (error); + goto out; #ifdef MNT_EXNORESPORT if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { saddr = (struct sockaddr_in *)nam; @@ -1071,7 +1089,7 @@ ntohs(saddr->sin_port) >= IPPORT_RESERVED) { vput(*vpp); *vpp = NULL; - return (NFSERR_AUTHERR | AUTH_TOOWEAK); + error = NFSERR_AUTHERR | AUTH_TOOWEAK; } } #endif @@ -1093,6 +1111,8 @@ if (!lockflag) VOP_UNLOCK(*vpp, 0, td); +out: + NFSD_LOCK(); return (0); } @@ -1108,6 +1128,8 @@ char *cp = (char *)fhp; int i; + NFSD_LOCK_DONTCARE(); + for (i = 0; i < NFSX_V3FH; i++) if (*cp++ != 0) return (FALSE); @@ -1126,6 +1148,8 @@ { struct sockaddr_in *inetaddr; + NFSD_LOCK_DONTCARE(); + switch (family) { case AF_INET: inetaddr = (struct sockaddr_in *)nam; @@ -1164,6 +1188,8 @@ const short *defaulterrp, *errp; int e; + NFSD_LOCK_DONTCARE(); + if (nd->nd_flag & ND_NFSV3) { if (nd->nd_procnum <= NFSPROC_COMMIT) { errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; @@ -1189,6 +1215,12 @@ nfsrv_object_create(struct vnode *vp) { + /* + * XXXRW: Don't want to hold nfsd_mtx across VFS operation that + * may block. + */ + NFSD_UNLOCK_ASSERT(); + if (vp == NULL || vp->v_type != VREG) return (1); return (vfs_object_create(vp, curthread, curthread->td_ucred)); @@ -1205,6 +1237,8 @@ int i, j; gid_t v; + NFSD_LOCK_DONTCARE(); + /* Insertion sort. */ for (i = 1; i < num; i++) { v = list[i]; @@ -1223,6 +1257,8 @@ { int i; + NFSD_LOCK_DONTCARE(); + bzero((caddr_t)outcred, sizeof (struct ucred)); outcred->cr_ref = 1; outcred->cr_uid = incred->cr_uid; @@ -1241,6 +1277,8 @@ { u_int32_t *tl; + NFSD_LOCK_DONTCARE(); + if (v3) { tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); *tl++ = txdr_unsigned(NFSX_V3FH); @@ -1267,6 +1305,8 @@ { u_int32_t *tl; + NFSD_LOCK_DONTCARE(); + tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); if (tl == NULL) return EBADRPC; @@ -1281,6 +1321,8 @@ { u_int32_t *tl; + NFSD_LOCK_DONTCARE(); + tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); if (tl == NULL) return EBADRPC; @@ -1298,6 +1340,8 @@ { struct mbuf *nmp; + NFSD_LOCK_DONTCARE(); + if (*bp >= *be) { if (*mp == mb) (*mp)->m_len += *bp - bpos; @@ -1319,6 +1363,8 @@ u_int32_t *tl; int fhlen; + NFSD_LOCK_DONTCARE(); + if (nfsd->nd_flag & ND_NFSV3) { tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); if (tl == NULL) @@ -1345,6 +1391,8 @@ { u_int32_t *tl; + NFSD_LOCK_DONTCARE(); + tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); if (tl == NULL) return EBADRPC; --- //depot/user/rwatson/netperf/sys/nfsserver/nfs_syscalls.c 2004/04/04 14:46:50 +++ //depot/user/rwatson/net/sys/nfsserver/nfs_syscalls.c 2004/04/06 18:10:47 @@ -147,10 +147,13 @@ if (error) return (error); mtx_lock(&Giant); + NFSD_LOCK(); while (nfssvc_sockhead_flag & SLP_INIT) { nfssvc_sockhead_flag |= SLP_WANTINIT; - (void) tsleep(&nfssvc_sockhead, PSOCK, "nfsd init", 0); + (void) msleep(&nfssvc_sockhead, &nfsd_mtx, PSOCK, + "nfsd init", 0); } + NFSD_UNLOCK(); if (uap->flag & NFSSVC_ADDSOCK) { error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg)); if (error) @@ -199,10 +202,17 @@ struct socket *so; int error, s; + /* + * XXXRW: Maybe should be NET_GIANT_ASSERT()? + */ GIANT_REQUIRED; so = fp->f_data; #if 0 + /* + * XXXRW: If this code is ever enabled, there's a race when running + * MPSAFE. + */ tslp = NULL; /* * Add it to the list, as required. @@ -267,12 +277,16 @@ malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK | M_ZERO); STAILQ_INIT(&slp->ns_rec); + NFSD_LOCK(); TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); slp->ns_so = so; slp->ns_nam = mynam; fhold(fp); slp->ns_fp = fp; + /* + * XXXRW: Socket locking here? + */ s = splnet(); so->so_upcallarg = (caddr_t)slp; so->so_upcall = nfsrv_rcv; @@ -280,6 +294,7 @@ slp->ns_flag = (SLP_VALID | SLP_NEEDQ); nfsrv_wakenfsd(slp); splx(s); + NFSD_UNLOCK(); return (0); } @@ -306,6 +321,8 @@ nfsd = (struct nfsd *) malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK | M_ZERO); s = splnet(); + NFSD_LOCK(); + nfsd->nfsd_td = td; TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain); nfs_numnfsd++; @@ -319,8 +336,8 @@ (nfsd_head_flag & NFSD_CHECKSLP) == 0) { nfsd->nfsd_flag |= NFSD_WAITING; nfsd_waiting++; - error = tsleep(nfsd, PSOCK | PCATCH, - "-", 0); + error = msleep(nfsd, &nfsd_mtx, + PSOCK | PCATCH, "-", 0); nfsd_waiting--; if (error) goto done; @@ -347,8 +364,10 @@ else if (slp->ns_flag & SLP_NEEDQ) { slp->ns_flag &= ~SLP_NEEDQ; (void) nfs_slplock(slp, 1); + NFSD_UNLOCK(); nfsrv_rcv(slp->ns_so, (caddr_t)slp, M_TRYWAIT); + NFSD_LOCK(); nfs_slpunlock(slp); } error = nfsrv_dorec(slp, nfsd, &nd); @@ -462,6 +481,7 @@ nd->nd_mrep = NULL; /* FALLTHROUGH */ case RC_REPLY: + NFSD_UNLOCK(); siz = m_length(mreq, NULL); if (siz <= 0 || siz > NFS_MAXPACKET) { printf("mbuf siz=%d\n",siz); @@ -478,11 +498,14 @@ M_PREPEND(m, NFSX_UNSIGNED, M_TRYWAIT); *mtod(m, u_int32_t *) = htonl(0x80000000 | siz); } + NFSD_LOCK(); if (slp->ns_so->so_proto->pr_flags & PR_CONNREQUIRED) (void) nfs_slplock(slp, 1); - if (slp->ns_flag & SLP_VALID) + if (slp->ns_flag & SLP_VALID) { + NFSD_UNLOCK(); error = nfsrv_send(slp->ns_so, nd->nd_nam2, m); - else { + NFSD_LOCK(); + } else { error = EPIPE; m_freem(m); } @@ -539,6 +562,7 @@ free((caddr_t)nfsd, M_NFSD); if (--nfs_numnfsd == 0) nfsrv_init(TRUE); /* Reinitialize everything */ + NFSD_UNLOCK(); return (error); } @@ -558,12 +582,17 @@ struct nfsrv_rec *rec; int s; + NFSD_LOCK_ASSERT(); + + /* + * XXXRW: By clearing all flags, other threads/etc should ignore + * this slp and we can safely release nfsd_mtx so we can clean + * up the slp safely. + */ slp->ns_flag &= ~SLP_ALLFLAGS; fp = slp->ns_fp; if (fp) { - /* - * XXXRW: socket locking. - */ + NFSD_UNLOCK(); slp->ns_fp = NULL; so = slp->ns_so; so->so_rcv.sb_flags &= ~SB_UPCALL; @@ -571,6 +600,7 @@ so->so_upcallarg = NULL; soshutdown(so, SHUT_RDWR); closef(fp, NULL); + NFSD_LOCK(); if (slp->ns_nam) FREE(slp->ns_nam, M_SONAME); m_freem(slp->ns_raw); @@ -600,6 +630,8 @@ nfsrv_slpderef(struct nfssvc_sock *slp) { + NFSD_LOCK_ASSERT(); + if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) { TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); free((caddr_t)slp, M_NFSSVC); @@ -617,11 +649,13 @@ { int *statep = &slp->ns_solock; + NFSD_LOCK_ASSERT(); + if (!wait && (*statep & NFSRV_SNDLOCK)) return(0); /* already locked, fail */ while (*statep & NFSRV_SNDLOCK) { *statep |= NFSRV_WANTSND; - (void) tsleep(statep, PZERO - 1, "nfsslplck", 0); + (void) msleep(statep, &nfsd_mtx, PZERO - 1, "nfsslplck", 0); } *statep |= NFSRV_SNDLOCK; return (1); @@ -635,6 +669,8 @@ { int *statep = &slp->ns_solock; + NFSD_LOCK_ASSERT(); + if ((*statep & NFSRV_SNDLOCK) == 0) panic("nfs slpunlock"); *statep &= ~NFSRV_SNDLOCK; @@ -654,6 +690,8 @@ { struct nfssvc_sock *slp, *nslp; + NFSD_LOCK_ASSERT(); + if (nfssvc_sockhead_flag & SLP_INIT) panic("nfsd init"); nfssvc_sockhead_flag |= SLP_INIT;