--- //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/07 17:21:59
@@ -137,11 +137,10 @@
 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 int	nfsrv_access_locked(struct vnode *, int, struct ucred *,
+		    int, struct thread *, int);
 static void	nfsrvw_coalesce(struct nfsrv_descript *,
 		    struct nfsrv_descript *);
 
@@ -181,6 +180,7 @@
 	struct vattr vattr, *vap = &vattr;
 	u_long testmode, nfsmode;
 	int v3 = (nfsd->nd_flag & ND_NFSV3);
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -199,9 +199,9 @@
 	}
 	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,6 +259,7 @@
 	caddr_t bpos;
 	int error = 0, rdonly;
 	struct mbuf *mb, *mreq;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -272,10 +273,10 @@
 		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 +293,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,6 +326,7 @@
 	struct mbuf *mb, *mreq;
 	struct timespec guard;
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -336,10 +338,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();
 	VATTR_NULL(vap);
 	if (v3) {
@@ -398,7 +400,7 @@
 	 */
 	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 +408,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,7 +417,7 @@
 			error = 0;
 			goto nfsmout;
 		}
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 	}
 	NFSD_LOCK_ASSERT();
@@ -433,15 +435,15 @@
 		if (vp->v_type == VDIR) {
 			error = EISDIR;
 			goto out;
-		} else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly,
-			td, 0)) != 0)
+		} else if ((error = nfsrv_access_locked(vp, VWRITE, cred,
+		    rdonly, 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 */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	if (!error)
 		error = postat_ret;
@@ -449,9 +451,9 @@
 	NFSD_LOCK_ASSERT();
 	if (vp != NULL) {
 		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();
 	}
 
@@ -470,11 +472,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);
 }
@@ -521,8 +523,11 @@
 	/*
 	 * 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) {
@@ -696,6 +701,7 @@
 	nfsfh_t nfh;
 	fhandle_t *fhp;
 	struct uio io, *uiop = &io;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -746,7 +752,7 @@
 		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 +762,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 +787,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 +825,7 @@
 	struct nfsheur *nh;
 	off_t off;
 	int ioflag = 0;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -857,19 +864,18 @@
 			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,7 +884,7 @@
 		error = 0;
 		goto nfsmout;
 	}
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 
 	/*
@@ -1005,7 +1011,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 +1021,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 +1032,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 +1057,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 +1096,7 @@
 	struct uio io, *uiop = &io;
 	off_t off;
 	struct mount *mntp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -1106,10 +1113,10 @@
 		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 */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	if (v3) {
 		tl = nfsm_dissect_nonblock(u_int32_t *, 5 * NFSX_UNSIGNED);
@@ -1175,9 +1182,9 @@
 	}
 	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 */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 	}
 	if (vp->v_type != VREG) {
@@ -1187,12 +1194,13 @@
 			error = (vp->v_type == VDIR) ? EISDIR : EACCES;
 	}
 	if (!error)
-		error = nfsrv_access(vp, VWRITE, cred, rdonly, td, 1);
+		error = nfsrv_access_locked(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);
 		NFSD_LOCK();
 		vp = NULL;
 		nfsm_reply(NFSX_WCCDATA(v3));
@@ -1236,17 +1244,17 @@
 	    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 */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	vp = NULL;
 	if (!error)
@@ -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);
 }
@@ -1348,6 +1356,7 @@
 	struct uio io, *uiop = &io;
 	u_quad_t cur_usec;
 	struct mount *mntp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -1507,9 +1516,9 @@
 		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 */
+			VFS_UNLOCK_GIANT(vfslocked);
 			NFSD_LOCK();
 		    }
 		    if (vp->v_type != VREG) {
@@ -1522,10 +1531,9 @@
 		    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,7 +1587,7 @@
 		    vput(vp);
 		    vp = NULL;
 		}
-		mtx_unlock(&Giant);	/* VFS */
+		VFS_UNLOCK_GIANT(vfslocked);
 		NFSD_LOCK();
 
 		/*
@@ -1742,6 +1750,7 @@
 	u_quad_t tempsize;
 	u_char cverf[NFSX_V3CREATEVERF];
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -1758,10 +1767,10 @@
 		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 +1791,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;
 	}
@@ -1859,6 +1868,10 @@
 	 *
 	 * 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 */
@@ -1938,8 +1951,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 +2065,7 @@
 	fhandle_t *fhp;
 	struct mount *mp = NULL;
 	int v3 = (nfsd->nd_flag & ND_NFSV3);
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -2067,10 +2081,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 */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	nfsm_srvnamesiz(len);
 
@@ -2092,6 +2106,11 @@
 		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) {
@@ -2212,9 +2231,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 +2280,7 @@
 	nfsfh_t nfh;
 	fhandle_t *fhp;
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -2274,10 +2294,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 */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	nfsm_srvnamesiz(len);
 
@@ -2386,6 +2406,7 @@
 	fhandle_t *ffhp, *tfhp;
 	uid_t saved_uid;
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -2409,10 +2430,10 @@
 		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 +2448,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;
 	}
@@ -2639,6 +2660,7 @@
 	nfsfh_t nfh, dnfh;
 	fhandle_t *fhp, *dfhp;
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -2653,10 +2675,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 */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	nfsm_srvmtofh(dfhp);
 	nfsm_srvnamesiz(len);
@@ -2803,12 +2825,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 +2846,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 +3026,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 +3046,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 +3060,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 +3207,7 @@
 	fhandle_t *fhp;
 	struct nameidata nd;
 	struct mount *mp = NULL;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -3187,10 +3221,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 +3234,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 +3268,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 +3394,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();
 
@@ -3387,9 +3425,9 @@
 	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);
 		NFSD_LOCK();
 		vp = NULL;
 	}
@@ -3405,7 +3443,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 +3455,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 +3502,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 +3523,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 +3573,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 +3652,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 +3678,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 +3715,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();
 
@@ -3704,9 +3743,9 @@
 	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();
 	}
@@ -3717,7 +3756,7 @@
 		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 +3766,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 +3806,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 +3826,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 +3881,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 +3892,7 @@
 		goto nfsmout;
 	}
 	vput(nvp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	nvp = NULL;
 
 	dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
@@ -3868,7 +3907,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 +3924,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 +4028,7 @@
 		ncookies--;
 	}
 	vrele(vp);
-	mtx_unlock(&Giant);	/* VFS */
+	VFS_UNLOCK_GIANT(vfslocked);
 	vp = NULL;
 	nfsm_clget_nolock;
 	*tl = nfsrv_nfs_false;
@@ -4005,9 +4051,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 +4081,7 @@
 	u_quad_t off;
 	struct mount *mp = NULL;
 	int v3 = (nfsd->nd_flag & ND_NFSV3);
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -4048,10 +4095,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 */
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	tl = nfsm_dissect_nonblock(u_int32_t *, 3 * NFSX_UNSIGNED);
 
@@ -4070,7 +4117,7 @@
 		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 +4205,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 +4224,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,6 +4256,7 @@
 	fhandle_t *fhp;
 	struct statfs statfs;
 	u_quad_t tval;
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -4225,11 +4273,11 @@
 	}
 	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 +4328,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,6 +4358,7 @@
 	u_quad_t maxfsize;
 	struct statfs sb;
 	int v3 = (nfsd->nd_flag & ND_NFSV3);
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -4327,14 +4376,14 @@
 	}
 
 	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 +4416,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,6 +4445,7 @@
 	nfsfh_t nfh;
 	fhandle_t *fhp;
 	int v3 = (nfsd->nd_flag & ND_NFSV3);
+	int vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
@@ -4412,7 +4462,7 @@
 		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 +4472,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 +4499,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 +4571,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__));
 
@@ -4576,17 +4631,17 @@
 }
 
 static int
-nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly,
-    struct thread *td, int override)
+nfsrv_access_locked(struct vnode *vp, int flags, struct ucred *cred,
+    int rdonly, struct thread *td, int override)
 {
-	int error;
+	int error, vfslocked;
 
 	NFSD_LOCK_ASSERT();
 
 	NFSD_UNLOCK();
-	mtx_lock(&Giant);	/* VFS */
-	error = nfsrv_access_withgiant(vp, flags, cred, rdonly, td, override);
-	mtx_unlock(&Giant);	/* VFS */
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+	error = nfsrv_access(vp, flags, cred, rdonly, td, override);
+	VFS_UNLOCK_GIANT(vfslocked);
 	NFSD_LOCK();
 	return (error);
 }
