--- //depot/vendor/freebsd/src/sys/nfsserver/nfs.h	2006/08/01 16:27:53
+++ //depot/user/rwatson/nfs/src/sys/nfsserver/nfs.h	2006/11/10 22:26:09
@@ -360,6 +360,9 @@
 	    struct thread *td, struct mbuf **mrq);
 int	nfsrv_fhtovp(fhandle_t *, int, struct vnode **, struct ucred *,
 	    struct nfssvc_sock *, struct sockaddr *, int *, int);
+int	nfsrv_fhtovp_locked(fhandle_t *, int, struct vnode **,
+	    struct ucred *, struct nfssvc_sock *, struct sockaddr *, int *,
+	    int);
 int	nfsrv_setpublicfs(struct mount *, struct netexport *,
 	    struct export_args *);
 int	nfs_ispublicfh(fhandle_t *);
--- //depot/vendor/freebsd/src/sys/nfsserver/nfs_serv.c	2006/10/26 12:42:15
+++ //depot/user/rwatson/nfs/src/sys/nfsserver/nfs_serv.c	2006/11/10 22:51:12
@@ -137,11 +137,8 @@
 SYSCTL_STRUCT(_vfs_nfsrv, NFS_NFSRVSTATS, nfsrvstats, CTLFLAG_RD,
 	&nfsrvstats, nfsrvstats, "S,nfsrvstats");
 
-static int	nfsrv_access_withgiant(struct vnode *vp, int flags,
-		    struct ucred *cred, int rdonly, struct thread *td,
-		    int override);
-static int	nfsrv_access(struct vnode *, int, struct ucred *, int,
-		    struct thread *, int);
+static int	nfsrv_access(struct vnode *vp, int flags, struct ucred *cred,
+		    int rdonly, struct thread *td, int override);
 static void	nfsrvw_coalesce(struct nfsrv_descript *,
 		    struct nfsrv_descript *);
 
@@ -181,6 +178,7 @@
 	struct vattr vattr, *vap = &vattr;
 	u_long testmode, nfsmode;
 	int v3 = (nfsd->nd_flag & ND_NFSV3);
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -190,18 +188,20 @@
 	fhp = &nfh.fh_generic;
 	nfsm_srvmtofh(fhp);
 	tl = nfsm_dissect_nonblock(u_int32_t *, NFSX_UNSIGNED);
-	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE);
+	NFSD_UNLOCK();
+	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
+	    TRUE);
 	if (error) {
+		NFSD_LOCK();
 		nfsm_reply(NFSX_UNSIGNED);
 		nfsm_srvpostop_attr(1, NULL);
 		error = 0;
 		goto nfsmout;
 	}
 	nfsmode = fxdr_unsigned(u_int32_t, *tl);
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	if ((nfsmode & NFSV3ACCESS_READ) &&
-		nfsrv_access_withgiant(vp, VREAD, cred, rdonly, td, 0))
+		nfsrv_access(vp, VREAD, cred, rdonly, td, 0))
 		nfsmode &= ~NFSV3ACCESS_READ;
 	if (vp->v_type == VDIR)
 		testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
@@ -209,18 +209,18 @@
 	else
 		testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
 	if ((nfsmode & testmode) &&
-		nfsrv_access_withgiant(vp, VWRITE, cred, rdonly, td, 0))
+		nfsrv_access(vp, VWRITE, cred, rdonly, td, 0))
 		nfsmode &= ~testmode;
 	if (vp->v_type == VDIR)
 		testmode = NFSV3ACCESS_LOOKUP;
 	else
 		testmode = NFSV3ACCESS_EXECUTE;
 	if ((nfsmode & testmode) &&
-		nfsrv_access_withgiant(vp, VEXEC, cred, rdonly, td, 0))
+		nfsrv_access(vp, VEXEC, cred, rdonly, td, 0))
 		nfsmode &= ~testmode;
 	getret = VOP_GETATTR(vp, vap, cred, td);
 	vput(vp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	vp = NULL;
 	NFSD_LOCK();
 	nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
@@ -231,9 +231,9 @@
 	NFSD_LOCK_ASSERT();
 	if (vp) {
 		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 	}
 	return(error);
@@ -259,23 +259,26 @@
 	caddr_t bpos;
 	int error = 0, rdonly;
 	struct mbuf *mb, *mreq;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 	fhp = &nfh.fh_generic;
 	nfsm_srvmtofh(fhp);
-	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE);
+	NFSD_UNLOCK();
+	error = nfsrv_fhtovp_locked(fhp, 1, &vp, cred, slp, nam, &rdonly,
+	    TRUE);
 	if (error) {
+		NFSD_LOCK();
 		nfsm_reply(0);
 		error = 0;
 		goto nfsmout;
 	}
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	error = VOP_GETATTR(vp, vap, cred, td);
 	vput(vp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	vp = NULL;
 	NFSD_LOCK();
 	nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
@@ -292,9 +295,9 @@
 	NFSD_LOCK_ASSERT();
 	if (vp) {
 		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 	}
 	return(error);
@@ -325,23 +328,24 @@
 	struct mbuf *mb, *mreq;
 	struct timespec guard;
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 	fhp = &nfh.fh_generic;
 	nfsm_srvmtofh(fhp);
+	NFSD_UNLOCK();
 	if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 		error = ESTALE;
 		goto out;
 	}
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mp);
 	(void) vn_start_write(NULL, &mp, V_WAIT);
 	vfs_rel(mp);		/* The write holds a ref. */
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
+	VATTR_NULL(vap);
 	NFSD_LOCK();
-	VATTR_NULL(vap);
 	if (v3) {
 		nfsm_srvsattr(vap);
 		tl = nfsm_dissect_nonblock(u_int32_t *, NFSX_UNSIGNED);
@@ -380,12 +384,14 @@
 			fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime);
 
 	}
+	NFSD_UNLOCK();
 
 	/*
 	 * Now that we have all the fields, lets do it.
 	 */
 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE);
 	if (error) {
+		NFSD_LOCK();
 		nfsm_reply(2 * NFSX_UNSIGNED);
 		if (v3)
 			nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
@@ -397,8 +403,7 @@
 	 * vp now an active resource, pay careful attention to cleanup
 	 */
 	if (v3) {
-		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		error = preat_ret = VOP_GETATTR(vp, &preat, cred, td);
 		if (!error && gcheck &&
 			(preat.va_ctime.tv_sec != guard.tv_sec ||
@@ -406,7 +411,7 @@
 			error = NFSERR_NOT_SYNC;
 		if (error) {
 			vput(vp);
-			mtx_unlock(&Giant);	/* VFS */
+			VFS_UNLOCK_GIANT(vfslocked);
 			vp = NULL;
 			NFSD_LOCK();
 			nfsm_reply(NFSX_WCCDATA(v3));
@@ -415,10 +420,8 @@
 			error = 0;
 			goto nfsmout;
 		}
-		mtx_unlock(&Giant);	/* VFS */
-		NFSD_LOCK();
+		VFS_UNLOCK_GIANT(vfslocked);
 	}
-	NFSD_LOCK_ASSERT();
 
 	/*
 	 * If the size is being changed write acces is required, otherwise
@@ -434,28 +437,25 @@
 			error = EISDIR;
 			goto out;
 		} else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly,
-			td, 0)) != 0)
+		    td, 0)) != 0)
 			goto out;
 	}
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	error = VOP_SETATTR(vp, vap, cred, td);
 	postat_ret = VOP_GETATTR(vp, vap, cred, td);
-	mtx_unlock(&Giant);	/* VFS */
-	NFSD_LOCK();
+	VFS_UNLOCK_GIANT(vfslocked);
 	if (!error)
 		error = postat_ret;
 out:
-	NFSD_LOCK_ASSERT();
+	NFSD_UNLOCK_ASSERT();
 	if (vp != NULL) {
-		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
-		NFSD_LOCK();
+		VFS_UNLOCK_GIANT(vfslocked);
 	}
 
 	vp = NULL;
+	NFSD_LOCK();
 	nfsm_reply(NFSX_WCCORFATTR(v3));
 	if (v3) {
 		nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
@@ -470,11 +470,11 @@
 nfsmout:
 	NFSD_LOCK_ASSERT();
 	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mp);
 	if (vp)
 		vput(vp);
 	vn_finished_write(mp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	return(error);
 }
@@ -517,13 +517,16 @@
 	nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
 		&dirp, v3, &dirattr, &dirattr_ret, td, pubflag);
+	NFSD_UNLOCK();
 
 	/*
 	 * namei failure, only dirp to cleanup.  Clear out garbarge from
 	 * structure in case macros jump to nfsmout.
+	 *
+	 * XXXRW: For now, use Giant unconditionally during name lookup,
+	 * rather than deal with complexity of conditional Giant acqusition
+	 * as moving across the name space.
 	 */
-
-	NFSD_UNLOCK();
 	mtx_lock(&Giant);	/* VFS */
 	if (error) {
 		if (dirp) {
@@ -696,6 +699,7 @@
 	nfsfh_t nfh;
 	fhandle_t *fhp;
 	struct uio io, *uiop = &io;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -706,9 +710,9 @@
 	mp3 = NULL;
 	fhp = &nfh.fh_generic;
 	nfsm_srvmtofh(fhp);
+	NFSD_UNLOCK();
 	len = 0;
 	i = 0;
-	NFSD_UNLOCK();
 	while (len < NFS_MAXPATHLEN) {
 		MGET(nmp, M_TRYWAIT, MT_DATA);
 		MCLGET(nmp, M_TRYWAIT);
@@ -736,17 +740,16 @@
 	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) {
+		NFSD_LOCK();
 		nfsm_reply(2 * NFSX_UNSIGNED);
 		if (v3)
 			nfsm_srvpostop_attr(1, NULL);
 		error = 0;
 		goto nfsmout;
 	}
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	if (vp->v_type != VLNK) {
 		if (v3)
 			error = EINVAL;
@@ -756,7 +759,7 @@
 		error = VOP_READLINK(vp, uiop, cred);
 	getret = VOP_GETATTR(vp, &attr, cred, td);
 	vput(vp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	vp = NULL;
 	NFSD_LOCK();
 	nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
@@ -781,9 +784,9 @@
 		m_freem(mp3);
 	if (vp) {
 		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 	}
 	return(error);
@@ -819,6 +822,7 @@
 	struct nfsheur *nh;
 	off_t off;
 	int ioflag = 0;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -833,16 +837,18 @@
 		off = (off_t)fxdr_unsigned(u_int32_t, *tl);
 	}
 	nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd));
+	NFSD_UNLOCK();
 
 	/*
 	 * Reference vp.  If an error occurs, vp will be invalid, but we
 	 * have to NULL it just in case.  The macros might goto nfsmout
 	 * as well.
 	 */
-
-	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE);
+	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
+	    TRUE);
 	if (error) {
 		vp = NULL;
+		NFSD_LOCK();
 		nfsm_reply(2 * NFSX_UNSIGNED);
 		if (v3)
 			nfsm_srvpostop_attr(1, NULL);
@@ -856,20 +862,18 @@
 		else
 			error = (vp->v_type == VDIR) ? EISDIR : EACCES;
 	}
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	if (!error) {
-		if ((error = nfsrv_access_withgiant(vp, VREAD, cred, rdonly,
-		    td, 1)) != 0)
-			error = nfsrv_access_withgiant(vp, VEXEC, cred,
-			    rdonly, td, 1);
+		if ((error = nfsrv_access(vp, VREAD, cred, rdonly, td, 1))
+		    != 0)
+			error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 1);
 	}
 	getret = VOP_GETATTR(vp, vap, cred, td);
 	if (!error)
 		error = getret;
 	if (error) {
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		vp = NULL;
 		NFSD_LOCK();
 		nfsm_reply(NFSX_POSTOPATTR(v3));
@@ -878,8 +882,7 @@
 		error = 0;
 		goto nfsmout;
 	}
-	mtx_unlock(&Giant);	/* VFS */
-	NFSD_LOCK();
+	VFS_UNLOCK_GIANT(vfslocked);
 
 	/*
 	 * Calculate byte count to read
@@ -892,6 +895,7 @@
 	else
 		cnt = reqlen;
 
+	NFSD_LOCK();
 	/*
 	 * Calculate seqcount for heuristic
 	 */
@@ -958,8 +962,8 @@
 		fp = (struct nfs_fattr *)tl;
 		tl += (NFSX_V2FATTR / sizeof (u_int32_t));
 	}
+	NFSD_UNLOCK();
 	len = left = nfsm_rndup(cnt);
-	NFSD_UNLOCK();
 	if (cnt > 0) {
 		/*
 		 * Generate the mbuf list with the uio_iov ref. to it.
@@ -1005,7 +1009,7 @@
 		uiop->uio_resid = len;
 		uiop->uio_rw = UIO_READ;
 		uiop->uio_segflg = UIO_SYSSPACE;
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred);
 		off = uiop->uio_offset;
 		nh->nh_nextr = off;
@@ -1015,7 +1019,7 @@
 				error = getret;
 			m_freem(mreq);
 			vput(vp);
-			mtx_unlock(&Giant);	/* VFS */
+			VFS_UNLOCK_GIANT(vfslocked);
 			NFSD_LOCK();
 			vp = NULL;
 			nfsm_reply(NFSX_POSTOPATTR(v3));
@@ -1026,11 +1030,11 @@
 		}
 	} else {
 		uiop->uio_resid = 0;
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	}
-	mtx_assert(&Giant, MA_OWNED);	/* VFS */
+	VFS_ASSERT_GIANT(vp->v_mount);
 	vput(vp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	vp = NULL;
 	NFSD_LOCK();
 	nfsm_srvfillattr(vap, fp);
@@ -1051,9 +1055,9 @@
 	NFSD_LOCK_ASSERT();
 	if (vp) {
 		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 	}
 	return(error);
@@ -1090,6 +1094,7 @@
 	struct uio io, *uiop = &io;
 	off_t off;
 	struct mount *mntp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -1101,23 +1106,27 @@
 	}
 	fhp = &nfh.fh_generic;
 	nfsm_srvmtofh(fhp);
+	NFSD_UNLOCK();
 	if ((mntp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 		error = ESTALE;
+		NFSD_LOCK();
 		goto ereply;
 	}
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mntp);
 	(void) vn_start_write(NULL, &mntp, V_WAIT);
 	vfs_rel(mntp);		/* The write holds a ref. */
-	mtx_unlock(&Giant);	/* VFS */
-	NFSD_LOCK();
+	VFS_UNLOCK_GIANT(vfslocked);
 	if (v3) {
+		NFSD_LOCK();
 		tl = nfsm_dissect_nonblock(u_int32_t *, 5 * NFSX_UNSIGNED);
+		NFSD_UNLOCK();
 		off = fxdr_hyper(tl);
 		tl += 3;
 		stable = fxdr_unsigned(int, *tl++);
 	} else {
+		NFSD_LOCK();
 		tl = nfsm_dissect_nonblock(u_int32_t *, 4 * NFSX_UNSIGNED);
+		NFSD_UNLOCK();
 		off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
 		tl += 2;
 		if (nfs_async)
@@ -1158,15 +1167,18 @@
 	}
 	if (len > NFS_MAXDATA || len < 0 || i < len) {
 		error = EIO;
+		NFSD_LOCK();
 		nfsm_reply(2 * NFSX_UNSIGNED);
 		if (v3)
 			nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
 		error = 0;
 		goto nfsmout;
 	}
-	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE);
+	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
+	    TRUE);
 	if (error) {
 		vp = NULL;
+		NFSD_LOCK();
 		nfsm_reply(2 * NFSX_UNSIGNED);
 		if (v3)
 			nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
@@ -1174,11 +1186,9 @@
 		goto nfsmout;
 	}
 	if (v3) {
-		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		forat_ret = VOP_GETATTR(vp, &forat, cred, td);
-		mtx_unlock(&Giant);	/* VFS */
-		NFSD_LOCK();
+		VFS_UNLOCK_GIANT(vfslocked);
 	}
 	if (vp->v_type != VREG) {
 		if (v3)
@@ -1189,12 +1199,11 @@
 	if (!error)
 		error = nfsrv_access(vp, VWRITE, cred, rdonly, td, 1);
 	if (error) {
-		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
+		vp = NULL;
 		NFSD_LOCK();
-		vp = NULL;
 		nfsm_reply(NFSX_WCCDATA(v3));
 		if (v3)
 			nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
@@ -1202,7 +1211,6 @@
 		goto nfsmout;
 	}
 
-	NFSD_UNLOCK();
 	if (len > 0) {
 	    MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
 		M_WAITOK);
@@ -1236,21 +1244,21 @@
 	    uiop->uio_segflg = UIO_SYSSPACE;
 	    uiop->uio_td = NULL;
 	    uiop->uio_offset = off;
-	    mtx_lock(&Giant);	/* VFS */
+	    vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	    error = VOP_WRITE(vp, uiop, ioflags, cred);
 	    /* XXXRW: unlocked write. */
 	    nfsrvstats.srvvop_writes++;
 	    FREE((caddr_t)iv, M_TEMP);
 	} else
-	    mtx_lock(&Giant);	/* VFS */
-	mtx_assert(&Giant, MA_OWNED);	/* VFS */
+	    vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+	VFS_ASSERT_GIANT(vp->v_mount);
 	aftat_ret = VOP_GETATTR(vp, vap, cred, td);
 	vput(vp);
-	mtx_unlock(&Giant);	/* VFS */
-	NFSD_LOCK();
+	VFS_UNLOCK_GIANT(vfslocked);
 	vp = NULL;
 	if (!error)
 		error = aftat_ret;
+	NFSD_LOCK();
 ereply:
 	NFSD_LOCK_ASSERT();
 	nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
@@ -1288,11 +1296,11 @@
 nfsmout:
 	NFSD_LOCK_ASSERT();
 	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mntp);
 	if (vp)
 		vput(vp);
 	vn_finished_write(mntp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	return(error);
 }
@@ -1308,6 +1316,8 @@
 {
 	int i;
 
+	NFSD_LOCK_DONTCARE();
+
 	if (cr1->cr_uid != cr2->cr_uid)
 		return (0);
 	if (cr1->cr_ngroups != cr2->cr_ngroups)
@@ -1348,6 +1358,7 @@
 	struct uio io, *uiop = &io;
 	u_quad_t cur_usec;
 	struct mount *mntp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -1501,16 +1512,15 @@
 		nfsd->nd_mrep = NULL;
 		cred = nfsd->nd_cr;
 		v3 = (nfsd->nd_flag & ND_NFSV3);
+		NFSD_UNLOCK();
 		forat_ret = aftat_ret = 1;
 		error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
 		    nfsd->nd_nam, &rdonly, TRUE);
 		if (!error) {
 		    if (v3) {
-			NFSD_UNLOCK();
-			mtx_lock(&Giant);	/* VFS */
+			vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 			forat_ret = VOP_GETATTR(vp, &forat, cred, td);
-			mtx_unlock(&Giant);	/* VFS */
-			NFSD_LOCK();
+			VFS_UNLOCK_GIANT(vfslocked);
 		    }
 		    if (vp->v_type != VREG) {
 			if (v3)
@@ -1521,11 +1531,9 @@
 		} else {
 		    vp = NULL;
 		}
-		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		if (!error)
-		    error = nfsrv_access_withgiant(vp, VWRITE, cred, rdonly,
-			td, 1);
+		    error = nfsrv_access(vp, VWRITE, cred, rdonly, td, 1);
 		if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
 		    ioflags = IO_NODELOCKED;
 		else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
@@ -1579,13 +1587,13 @@
 		    vput(vp);
 		    vp = NULL;
 		}
-		mtx_unlock(&Giant);	/* VFS */
-		NFSD_LOCK();
+		VFS_UNLOCK_GIANT(vfslocked);
 
 		/*
 		 * Loop around generating replies for all write rpcs that have
 		 * now been completed.
 		 */
+		NFSD_LOCK();
 		swp = nfsd;
 		do {
 		    NFS_DPF(WG, ("R%03x", nfsd->nd_retxid & 0xfff));
@@ -1648,6 +1656,7 @@
 	 * Search for a reply to return.
 	 */
 	s = splsoftclock();
+	NFSD_LOCK_ASSERT();
 	LIST_FOREACH(nfsd, &slp->ns_tq, nd_tq)
 		if (nfsd->nd_mreq) {
 		    NFS_DPF(WG, ("X%03x", nfsd->nd_retxid & 0xfff));
@@ -1742,6 +1751,7 @@
 	u_quad_t tempsize;
 	u_char cverf[NFSX_V3CREATEVERF];
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -1753,15 +1763,16 @@
 
 	fhp = &nfh.fh_generic;
 	nfsm_srvmtofh(fhp);
+	NFSD_UNLOCK();
 	if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 		error = ESTALE;
+		NFSD_LOCK();
 		goto ereply_locked;
 	}
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mp);
 	(void) vn_start_write(NULL, &mp, V_WAIT);
 	vfs_rel(mp);		/* The write holds a ref. */
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	nfsm_srvnamesiz(len);
 
@@ -1782,9 +1793,9 @@
 		&dirp, v3, &dirfor, &dirfor_ret, td, FALSE);
 	if (dirp && !v3) {
 		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(dirp->v_mount);
 		vrele(dirp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 		dirp = NULL;
 	}
@@ -1829,10 +1840,12 @@
 			exclusive_flag = 1;
 			break;
 		};
+		NFSD_UNLOCK();
 		vap->va_type = VREG;
 	} else {
 		sp = nfsm_dissect_nonblock(struct nfsv2_sattr *, NFSX_V2SATTR);
 		vap->va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
+		NFSD_UNLOCK();
 		if (vap->va_type == VNON)
 			vap->va_type = VREG;
 		vap->va_mode = nfstov_mode(sp->sa_mode);
@@ -1859,8 +1872,11 @@
 	 *
 	 * The only possible error we can have at this point is EEXIST.
 	 * nd.ni_vp will also be non-NULL in that case.
+	 *
+	 * XXXRW: For now acquire Giant unconditionally during create to
+	 * avoid interactions between Giant for ndvp and Giant for vp if it
+	 * already exists.
 	 */
-	NFSD_UNLOCK();
 	mtx_lock(&Giant);	/* VFS */
 	if (nd.ni_vp == NULL) {
 		if (vap->va_mode == (mode_t)VNOVAL)
@@ -1938,8 +1954,8 @@
 		}
 	} else {
 		if (vap->va_size != -1) {
-			error = nfsrv_access_withgiant(nd.ni_vp, VWRITE,
-			    cred, (nd.ni_cnd.cn_flags & RDONLY), td, 0);
+			error = nfsrv_access(nd.ni_vp, VWRITE, cred,
+			    (nd.ni_cnd.cn_flags & RDONLY), td, 0);
 			if (!error) {
 				tempsize = vap->va_size;
 				VATTR_NULL(vap);
@@ -2052,6 +2068,7 @@
 	fhandle_t *fhp;
 	struct mount *mp = NULL;
 	int v3 = (nfsd->nd_flag & ND_NFSV3);
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -2062,15 +2079,16 @@
 
 	fhp = &nfh.fh_generic;
 	nfsm_srvmtofh(fhp);
+	NFSD_UNLOCK();
 	if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 		error = ESTALE;
+		NFSD_LOCK();
 		goto ereply;
 	}
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mp);
 	(void) vn_start_write(NULL, &mp, V_WAIT);
 	vfs_rel(mp);		/* The write holds a ref. */
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	nfsm_srvnamesiz(len);
 
@@ -2092,12 +2110,17 @@
 		error = 0;
 		goto nfsmout;
 	}
+
+	/*
+	 * XXXRW: For now, acquire Giant unconditionally to avoid complexity
+	 * of dealing with Giant separately for dvp and vp.
+	 */
 	tl = nfsm_dissect_nonblock(u_int32_t *, NFSX_UNSIGNED);
 	vtyp = nfsv3tov_type(*tl);
 	if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
 		NFSD_UNLOCK();
+		error = NFSERR_BADTYPE;
 		mtx_lock(&Giant);	/* VFS */
-		error = NFSERR_BADTYPE;
 		goto out;
 	}
 	VATTR_NULL(vap);
@@ -2114,8 +2137,8 @@
 	 */
 	if (nd.ni_vp) {
 		NFSD_UNLOCK();
+		error = EEXIST;
 		mtx_lock(&Giant);	/* VFS */
-		error = EEXIST;
 		goto out;
 	}
 	vap->va_type = vtyp;
@@ -2168,6 +2191,7 @@
 	 * send response, cleanup, return.
 	 */
 out:
+	GIANT_REQUIRED;
 	NFSD_UNLOCK_ASSERT();
 	vp = nd.ni_vp;
 	if (!error) {
@@ -2212,9 +2236,9 @@
 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 	}
 	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mp);
 	vn_finished_write(mp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	return (0);
 nfsmout:
@@ -2261,6 +2285,7 @@
 	nfsfh_t nfh;
 	fhandle_t *fhp;
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -2269,15 +2294,16 @@
 
 	fhp = &nfh.fh_generic;
 	nfsm_srvmtofh(fhp);
+	NFSD_UNLOCK();
 	if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 		error = ESTALE;
+		NFSD_LOCK();
 		goto ereply;
 	}
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mp);
 	(void) vn_start_write(NULL, &mp, V_WAIT);
 	vfs_rel(mp);		/* The write holds a ref. */
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	nfsm_srvnamesiz(len);
 
@@ -2386,6 +2412,7 @@
 	fhandle_t *ffhp, *tfhp;
 	uid_t saved_uid;
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -2404,15 +2431,16 @@
 	ndclear(&tond);
 
 	nfsm_srvmtofh(ffhp);
+	NFSD_UNLOCK();
 	if ((mp = vfs_getvfs(&ffhp->fh_fsid)) == NULL) {
 		error = ESTALE;
+		NFSD_LOCK();
 		goto out1;
 	}
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);
+	vfslocked = VFS_LOCK_GIANT(mp);
 	(void) vn_start_write(NULL, &mp, V_WAIT);
 	vfs_rel(mp);		/* The write holds a ref. */
-	mtx_unlock(&Giant);
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	nfsm_srvnamesiz(len);
 	/*
@@ -2427,9 +2455,9 @@
 		&dpos, &fdirp, v3, &fdirfor, &fdirfor_ret, td, FALSE);
 	if (fdirp && !v3) {
 		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(fdirp->v_mount);
 		vrele(fdirp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 		fdirp = NULL;
 	}
@@ -2518,6 +2546,7 @@
 	      fromnd.ni_cnd.cn_namelen))
 		error = -1;
 out:
+	GIANT_REQUIRED;
 	NFSD_UNLOCK_ASSERT();
 	if (!error) {
 		/*
@@ -2639,6 +2668,7 @@
 	nfsfh_t nfh, dnfh;
 	fhandle_t *fhp, *dfhp;
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -2653,15 +2683,16 @@
 		goto ereply;
 	}
 	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mp);
 	(void) vn_start_write(NULL, &mp, V_WAIT);
 	vfs_rel(mp);		/* The write holds a ref. */
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	nfsm_srvmtofh(dfhp);
 	nfsm_srvnamesiz(len);
 
-	error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, slp, nam, &rdonly, TRUE);
+	error = nfsrv_fhtovp_locked(fhp, TRUE, &vp, cred, slp, nam, &rdonly,
+	    TRUE);
 	if (error) {
 		nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
 		if (v3) {
@@ -2803,12 +2834,18 @@
 	nfsfh_t nfh;
 	fhandle_t *fhp;
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 	ndclear(&nd);
 
+	/*
+	 * XXXRW: For now, unconditionally acquire Giant in several places to
+	 * avoid complexity of unwinding separately when several vnodes are
+	 * in flight.
+	 */
 	fhp = &nfh.fh_generic;
 	nfsm_srvmtofh(fhp);
 	if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
@@ -2818,10 +2855,10 @@
 		goto out;
 	}
 	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mp);
 	(void) vn_start_write(NULL, &mp, V_WAIT);
 	vfs_rel(mp);		/* The write holds a ref. */
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	nfsm_srvnamesiz(len);
 	nd.ni_cnd.cn_cred = cred;
@@ -2998,12 +3035,17 @@
 	nfsfh_t nfh;
 	fhandle_t *fhp;
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 	ndclear(&nd);
 
+	/*
+	 * XXXRW: For now, unconditionally acquire Giant so as to avoid the
+	 * complexity of tracking it for several in-flight vnodes.
+	 */
 	fhp = &nfh.fh_generic;
 	nfsm_srvmtofh(fhp);
 	if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
@@ -3013,10 +3055,10 @@
 		goto out;
 	}
 	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mp);
 	(void) vn_start_write(NULL, &mp, V_WAIT);
 	vfs_rel(mp);		/* The write holds a ref. */
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	nfsm_srvnamesiz(len);
 	nd.ni_cnd.cn_cred = cred;
@@ -3027,9 +3069,9 @@
 		&dirp, v3, &dirfor, &dirfor_ret, td, FALSE);
 	if (dirp && !v3) {
 		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(dirp->v_mount);
 		vrele(dirp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 		dirp = NULL;
 	}
@@ -3174,6 +3216,7 @@
 	fhandle_t *fhp;
 	struct nameidata nd;
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -3187,10 +3230,10 @@
 		goto out;
 	}
 	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mp);
 	(void) vn_start_write(NULL, &mp, V_WAIT);
 	vfs_rel(mp);		/* The write holds a ref. */
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	nfsm_srvnamesiz(len);
 	nd.ni_cnd.cn_cred = cred;
@@ -3200,9 +3243,9 @@
 		&dirp, v3, &dirfor, &dirfor_ret, td, FALSE);
 	if (dirp && !v3) {
 		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(dirp->v_mount);
 		vrele(dirp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 		dirp = NULL;
 	}
@@ -3234,6 +3277,9 @@
 	/*
 	 * Issue or abort op.  Since SAVESTART is not set, path name
 	 * component is freed by the VOP after either.
+	 *
+	 * XXXRW: For now, acquire Giant unconditionally to avoid the
+	 * complexity of unwinding Giant for several vnodes in flight.
 	 */
 	NFSD_LOCK_ASSERT();
 	NFSD_UNLOCK();
@@ -3357,6 +3403,7 @@
 	int v3 = (nfsd->nd_flag & ND_NFSV3);
 	u_quad_t off, toff, verf;
 	u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -3374,6 +3421,7 @@
 		toff = fxdr_unsigned(u_quad_t, *tl++);
 		verf = 0;	/* shut up gcc */
 	}
+	NFSD_UNLOCK();
 	off = toff;
 	cnt = fxdr_unsigned(int, *tl);
 	siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
@@ -3386,14 +3434,13 @@
 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE);
 	if (!error && vp->v_type != VDIR) {
 		error = ENOTDIR;
-		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
-		NFSD_LOCK();
+		VFS_UNLOCK_GIANT(vfslocked);
 		vp = NULL;
 	}
 	if (error) {
+		NFSD_LOCK();
 		nfsm_reply(NFSX_UNSIGNED);
 		if (v3)
 			nfsm_srvpostop_attr(getret, &at);
@@ -3404,8 +3451,7 @@
 	/*
 	 * Obtain lock on vnode for this section of the code
 	 */
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	if (v3) {
 		error = getret = VOP_GETATTR(vp, &at, cred, td);
 #if 0
@@ -3417,10 +3463,10 @@
 #endif
 	}
 	if (!error)
-		error = nfsrv_access_withgiant(vp, VEXEC, cred, rdonly, td, 0);
+		error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0);
 	if (error) {
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 		vp = NULL;
 		nfsm_reply(NFSX_POSTOPATTR(v3));
@@ -3464,7 +3510,7 @@
 	VOP_UNLOCK(vp, 0, td);
 	if (error) {
 		vrele(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		vp = NULL;
 		free((caddr_t)rbuf, M_TEMP);
 		if (cookies)
@@ -3485,7 +3531,7 @@
 		 */
 		if (siz == 0) {
 			vrele(vp);
-			mtx_unlock(&Giant);	/* VFS */
+			VFS_UNLOCK_GIANT(vfslocked);
 			vp = NULL;
 			NFSD_LOCK();
 			nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
@@ -3535,7 +3581,7 @@
 		goto again;
 	}
 
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	len = 3 * NFSX_UNSIGNED;	/* paranoia, probably can be 0 */
 	nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
@@ -3614,9 +3660,9 @@
 		ncookies--;
 	}
 	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	vrele(vp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	vp = NULL;
 	nfsm_clget;
@@ -3640,9 +3686,9 @@
 	NFSD_LOCK_ASSERT();
 	if (vp) {
 		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vrele(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 	}
 	return(error);
@@ -3677,6 +3723,7 @@
 	u_quad_t off, toff, verf;
 	u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */
 	int v3 = (nfsd->nd_flag & ND_NFSV3);
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -3695,6 +3742,7 @@
 	off = toff;
 	siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
 	xfer = NFS_SRVMAXDATA(nfsd);
+	NFSD_UNLOCK();
 	if (cnt > xfer)
 		cnt = xfer;
 	if (siz > xfer)
@@ -3703,21 +3751,19 @@
 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE);
 	if (!error && vp->v_type != VDIR) {
 		error = ENOTDIR;
-		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		vp = NULL;
-		NFSD_LOCK();
 	}
 	if (error) {
+		NFSD_LOCK();
 		nfsm_reply(NFSX_UNSIGNED);
 		nfsm_srvpostop_attr(getret, &at);
 		error = 0;
 		goto nfsmout;
 	}
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	error = getret = VOP_GETATTR(vp, &at, cred, td);
 #if 0
 	/*
@@ -3727,10 +3773,10 @@
 		error = NFSERR_BAD_COOKIE;
 #endif
 	if (!error)
-		error = nfsrv_access_withgiant(vp, VEXEC, cred, rdonly, td, 0);
+		error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0);
 	if (error) {
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 		vp = NULL;
 		nfsm_reply(NFSX_V3POSTOPATTR);
@@ -3767,7 +3813,7 @@
 		error = getret;
 	if (error) {
 		vrele(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		vp = NULL;
 		if (cookies)
 			free((caddr_t)cookies, M_TEMP);
@@ -3787,7 +3833,7 @@
 		 */
 		if (siz == 0) {
 			vrele(vp);
-			mtx_unlock(&Giant);	/* VFS */
+			VFS_UNLOCK_GIANT(vfslocked);
 			NFSD_LOCK();
 			vp = NULL;
 			nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
@@ -3842,7 +3888,7 @@
 	    EOPNOTSUPP) {
 		error = NFSERR_NOTSUPP;
 		vrele(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		vp = NULL;
 		free((caddr_t)cookies, M_TEMP);
 		free((caddr_t)rbuf, M_TEMP);
@@ -3853,7 +3899,7 @@
 		goto nfsmout;
 	}
 	vput(nvp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	nvp = NULL;
 
 	dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
@@ -3868,7 +3914,7 @@
 	be = bp + M_TRAILINGSPACE(mp);
 
 	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	VFS_LOCK_GIANT(vp->v_mount);
 	/* Loop through the records and build reply */
 	while (cpos < cend && ncookies > 0) {
 		if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
@@ -3885,6 +3931,13 @@
 			bzero((caddr_t)nfhp, NFSX_V3FH);
 			nfhp->fh_fsid =
 				nvp->v_mount->mnt_stat.f_fsid;
+			/*
+			 * XXXRW: Assert the mountpoints are the same so that
+			 * we know that acquiring Giant based on the
+			 * directory is the right thing for the child.
+			 */
+			KASSERT(nvp->v_mount == vp->v_mount,
+			    ("nfsrv_readdirplus: nvp mount != vp mount"));
 			if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
 				vput(nvp);
 				nvp = NULL;
@@ -3982,7 +4035,7 @@
 		ncookies--;
 	}
 	vrele(vp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	vp = NULL;
 	nfsm_clget_nolock;
 	*tl = nfsrv_nfs_false;
@@ -4005,9 +4058,9 @@
 	NFSD_LOCK_ASSERT();
 	if (vp) {
 		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vrele(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 	}
 	return(error);
@@ -4035,6 +4088,7 @@
 	u_quad_t off;
 	struct mount *mp = NULL;
 	int v3 = (nfsd->nd_flag & ND_NFSV3);
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -4048,11 +4102,10 @@
 		goto ereply;
 	}
 	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mp);
 	(void) vn_start_write(NULL, &mp, V_WAIT);
 	vfs_rel(mp);		/* The write holds a ref. */
-	mtx_unlock(&Giant);	/* VFS */
-	NFSD_LOCK();
+	VFS_UNLOCK_GIANT(vfslocked);
 	tl = nfsm_dissect_nonblock(u_int32_t *, 3 * NFSX_UNSIGNED);
 
 	/*
@@ -4064,13 +4117,13 @@
 	cnt = fxdr_unsigned(int, *tl);
 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE);
 	if (error) {
+		NFSD_LOCK();
 		nfsm_reply(2 * NFSX_UNSIGNED);
 		nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
 		error = 0;
 		goto nfsmout;
 	}
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	for_ret = VOP_GETATTR(vp, &bfor, cred, td);
 
 	if (cnt > MAX_COMMIT_COUNT) {
@@ -4158,7 +4211,7 @@
 
 	aft_ret = VOP_GETATTR(vp, &aft, cred, td);
 	vput(vp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	vp = NULL;
 	NFSD_LOCK();
 ereply:
@@ -4177,11 +4230,11 @@
 nfsmout:
 	NFSD_LOCK_ASSERT();
 	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(mp);
 	if (vp)
 		vput(vp);
 	vn_finished_write(mp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	return(error);
 }
@@ -4209,14 +4262,17 @@
 	fhandle_t *fhp;
 	struct statfs statfs;
 	u_quad_t tval;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
+	NFSD_UNLOCK();
 
 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 	fhp = &nfh.fh_generic;
 	nfsm_srvmtofh(fhp);
 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE);
 	if (error) {
+		NFSD_LOCK();
 		nfsm_reply(NFSX_UNSIGNED);
 		if (v3)
 			nfsm_srvpostop_attr(getret, &at);
@@ -4224,12 +4280,11 @@
 		goto nfsmout;
 	}
 	sf = &statfs;
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	error = VFS_STATFS(vp->v_mount, sf, td);
 	getret = VOP_GETATTR(vp, &at, cred, td);
 	vput(vp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	vp = NULL;
 	NFSD_LOCK();
 	nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
@@ -4280,9 +4335,9 @@
 	NFSD_LOCK_ASSERT();
 	if (vp) {
 		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 	}
 	return(error);
@@ -4310,8 +4365,10 @@
 	u_quad_t maxfsize;
 	struct statfs sb;
 	int v3 = (nfsd->nd_flag & ND_NFSV3);
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
+	NFSD_UNLOCK();
 
 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 	if (!v3)
@@ -4320,21 +4377,21 @@
 	nfsm_srvmtofh(fhp);
 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE);
 	if (error) {
+		NFSD_LOCK();
 		nfsm_reply(NFSX_UNSIGNED);
 		nfsm_srvpostop_attr(getret, &at);
 		error = 0;
 		goto nfsmout;
 	}
 
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	/* 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);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	vp = NULL;
 	NFSD_LOCK();
 	nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
@@ -4367,9 +4424,9 @@
 	NFSD_LOCK_ASSERT();
 	if (vp) {
 		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 	}
 	return(error);
@@ -4396,8 +4453,10 @@
 	nfsfh_t nfh;
 	fhandle_t *fhp;
 	int v3 = (nfsd->nd_flag & ND_NFSV3);
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
+	NFSD_UNLOCK();
 
 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 	if (!v3)
@@ -4406,13 +4465,13 @@
 	nfsm_srvmtofh(fhp);
 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE);
 	if (error) {
+		NFSD_LOCK();
 		nfsm_reply(NFSX_UNSIGNED);
 		nfsm_srvpostop_attr(getret, &at);
 		error = 0;
 		goto nfsmout;
 	}
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
 	if (!error)
 		error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
@@ -4422,7 +4481,7 @@
 		error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc);
 	getret = VOP_GETATTR(vp, &at, cred, td);
 	vput(vp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	vp = NULL;
 	NFSD_LOCK();
 	nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
@@ -4449,9 +4508,9 @@
 	NFSD_LOCK_ASSERT();
 	if (vp) {
 		NFSD_UNLOCK();
-		mtx_lock(&Giant);	/* VFS */
+		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vput(vp);
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 	}
 	return(error);
@@ -4521,19 +4580,24 @@
  * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
  * will return EPERM instead of EACCESS. EPERM is always an error.
  *
- * There are two versions: one to be called while holding Giant (which is
- * needed due to use of VFS), and the other called with the NFS server lock
- * (which will be dropped and reacquired).  This is necessary because
- * nfsrv_access checks are required from both classes of contexts.
+ * There are two versions: one called while holding the NFS server lock,
+ * which will be dropped and re-acquired, and one called without it.
+ *
+ * nfsrv_access() assumes that the NFS server lock is not held, but that if
+ * Giant is required for the vnode it will already be acquired.
+ *
+ * nfsrv_access_locked() assumes that the NFS server lock is held, but that
+ * it will need to acquire Giant for the vnode.
  */
 static int
-nfsrv_access_withgiant(struct vnode *vp, int flags, struct ucred *cred,
+nfsrv_access(struct vnode *vp, int flags, struct ucred *cred,
     int rdonly, struct thread *td, int override)
 {
 	struct vattr vattr;
 	int error;
 
-	GIANT_REQUIRED;
+	NFSD_UNLOCK_ASSERT();
+	VFS_ASSERT_GIANT(vp->v_mount);
 
 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 
@@ -4574,19 +4638,3 @@
 		error = 0;
 	return (error);
 }
-
-static int
-nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly,
-    struct thread *td, int override)
-{
-	int error;
-
-	NFSD_LOCK_ASSERT();
-
-	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
-	error = nfsrv_access_withgiant(vp, flags, cred, rdonly, td, override);
-	mtx_unlock(&Giant);	/* VFS */
-	NFSD_LOCK();
-	return (error);
-}
--- //depot/vendor/freebsd/src/sys/nfsserver/nfs_srvsubs.c	2006/08/01 16:27:53
+++ //depot/user/rwatson/nfs/src/sys/nfsserver/nfs_srvsubs.c	2006/11/10 22:26:09
@@ -624,7 +624,6 @@
 
 	NFSD_LOCK_ASSERT();
 	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
 
 	*retdirp = NULL;
 	cnp->cn_flags |= NOMACCHECK;
@@ -643,14 +642,14 @@
 			md = md->m_next;
 			if (md == NULL) {
 				error = EBADRPC;
-				goto out;
+				goto out_nogiant;
 			}
 			fromcp = mtod(md, caddr_t);
 			rem = md->m_len;
 		}
 		if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
 			error = EACCES;
-			goto out;
+			goto out_nogiant;
 		}
 		*tocp++ = *fromcp++;
 		rem--;
@@ -663,17 +662,17 @@
 		if (rem >= len)
 			*dposp += len;
 		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
-			goto out;
+			goto out_nogiant;
 	}
 
 	/*
 	 * Extract and set starting directory.
+	 *
+	 * XXXRW: For now, acquire Giant unconditionally to avoid tracking it
+	 * on multiple vnodes.
 	 */
-	mtx_unlock(&Giant);	/* VFS */
-	NFSD_LOCK();
 	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
 	    nam, &rdonly, pubflag);
-	NFSD_UNLOCK();
 	mtx_lock(&Giant);	/* VFS */
 	if (error)
 		goto out;
@@ -889,6 +888,8 @@
 	 * cleanup state trivially.
 	 */
 out:
+	mtx_unlock(&Giant);	/* VFS */
+out_nogiant:
 	if (error) {
 		uma_zfree(namei_zone, cnp->cn_pnbuf);
 		ndp->ni_vp = NULL;
@@ -898,7 +899,6 @@
 	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
 		ndp->ni_dvp = NULL;
 	}
-	mtx_unlock(&Giant);	/* VFS */
 	NFSD_LOCK();
 	return (error);
 }
@@ -1064,6 +1064,10 @@
  *	- get vp and export rights by calling VFS_FHTOVP()
  *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
  *	- if not lockflag unlock it with VOP_UNLOCK()
+ *
+ * As this routine may acquire Giant and may sleep, it can't be called with
+ * nfsd_mtx.  Caller should invoke nfsrv_fhtovp_locked() if the lock is held
+ * so that it can be automatically dropped and re-acquired.
  */
 int
 nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
@@ -1080,7 +1084,7 @@
 	struct sockaddr_int *saddr;
 #endif
 
-	NFSD_LOCK_ASSERT();
+	NFSD_UNLOCK_ASSERT();
 
 	*vpp = NULL;
 
@@ -1093,7 +1097,6 @@
 	mp = vfs_getvfs(&fhp->fh_fsid);
 	if (!mp)
 		return (ESTALE);
-	NFSD_UNLOCK();
 	vfslocked = VFS_LOCK_GIANT(mp);
 	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
 	if (error)
@@ -1133,11 +1136,28 @@
 out:
 	vfs_rel(mp);
 	VFS_UNLOCK_GIANT(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
  * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
