--- //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, &notrunc);
 	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 <sys/malloc.h>
 #include <sys/mount.h>
 #include <sys/systm.h>
+#include <sys/lock.h>
 #include <sys/mbuf.h>
+#include <sys/mutex.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>	/* 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;
