--- old/usr/src/uts/common/fs/nfs/nfs4_srv.c	2016-09-14 16:21:02.654588948 +0200
+++ new/usr/src/uts/common/fs/nfs/nfs4_srv.c	2016-09-14 16:21:02.658789914 +0200
@@ -872,6 +872,7 @@
 	int error, different_export = 0;
 	vnode_t *dvp, *vp;
 	struct exportinfo *exi = NULL;
+	struct exportinfo *oexi = NULL;
 	fid_t fid;
 	uint_t count, i;
 	secinfo4 *resok_val;
@@ -963,7 +964,7 @@
 		 * If vp isn't a mountpoint and the vfs ptrs aren't the same,
 		 * then vp is probably an LOFS object.  We don't need the
 		 * realvp, we just need to know that we might have crossed
-		 * a server fs boundary and need to call checkexport4.
+		 * a server fs boundary and need to call checkexport.
 		 * (LOFS lookup hides server fs mountpoints, and actually calls
 		 * traverse)
 		 */
@@ -984,11 +985,11 @@
 		}
 
 		if (dotdot)
-			exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
+			oexi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
 		else
-			exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
+			oexi = checkexport(&vp->v_vfsp->vfs_fsid, &fid, vp);
 
-		if (exi == NULL) {
+		if (oexi == NULL) {
 			if (did_traverse == TRUE) {
 				/*
 				 * If this vnode is a mounted-on vnode,
@@ -1002,6 +1003,8 @@
 				VN_RELE(vp);
 				return (puterrno4(EACCES));
 			}
+		} else {
+			exi = oexi;
 		}
 	} else {
 		exi = cs->exi;
@@ -1017,7 +1020,7 @@
 	 * For a real export node, return the flavor that the client
 	 * has access with.
 	 */
-	ASSERT(RW_LOCK_HELD(&exported_lock));
+	rw_enter(&exported_lock, RW_READER);
 	if (PSEUDO(exi)) {
 		count = exi->exi_export.ex_seccnt; /* total sec count */
 		resok_val = kmem_alloc(count * sizeof (secinfo4), KM_SLEEP);
@@ -1110,7 +1113,9 @@
 		resp->SECINFO4resok_val = resok_val;
 		kmem_free(flavor_list, count * sizeof (int));
 	}
-
+	rw_exit(&exported_lock);
+	if (oexi)
+		exi_rele(oexi);
 	VN_RELE(vp);
 	return (NFS4_OK);
 }
@@ -2611,7 +2616,7 @@
 	int error;
 	int different_export = 0;
 	vnode_t *vp, *pre_tvp = NULL, *oldvp = NULL;
-	struct exportinfo *exi = NULL, *pre_exi = NULL;
+	struct exportinfo *exi = NULL, *pre_exi = NULL, *oexi = NULL;
 	nfsstat4 stat;
 	fid_t fid;
 	int attrdir, dotdot, walk;
@@ -2705,7 +2710,7 @@
 
 		/*
 		 * hold pre_tvp to counteract rele by traverse.  We will
-		 * need pre_tvp below if checkexport4 fails
+		 * need pre_tvp below if checkexport fails
 		 */
 		VN_HOLD(pre_tvp);
 		if ((error = traverse(&vp)) != 0) {
@@ -2741,7 +2746,7 @@
 		if (dotdot)
 			exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
 		else
-			exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
+			exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid, vp);
 
 		if (exi == NULL) {
 			if (pre_tvp) {
@@ -2755,6 +2760,8 @@
 				VN_RELE(vp);
 				vp = pre_tvp;
 				exi = pre_exi;
+				if (exi)
+					exi_hold(exi);
 			} else {
 				VN_RELE(vp);
 				return (puterrno4(EACCES));
@@ -2764,6 +2771,8 @@
 			VN_RELE(pre_tvp);
 		}
 
+		if (cs->exi)
+			exi_rele(cs->exi);
 		cs->exi = exi;
 
 		/*
@@ -3444,16 +3453,22 @@
 
 		/*
 		 * if root filesystem is exported, the exportinfo struct that we
-		 * should use is what checkexport4 returns, because root_exi is
+		 * should use is what checkexport returns, because root_exi is
 		 * actually a mostly empty struct.
 		 */
-		exi = checkexport4(&fh_fmtp->fh4_fsid,
+		exi = checkexport(&fh_fmtp->fh4_fsid,
 		    (fid_t *)&fh_fmtp->fh4_xlen, NULL);
-		cs->exi = ((exi != NULL) ? exi : exi_public);
+		if (exi) {
+			cs->exi = exi;
+		} else {
+			exi_hold(exi_public);
+			cs->exi = exi_public;
+		}
 	} else {
 		/*
 		 * it's a properly shared filesystem
 		 */
+		exi_hold(exi_public);
 		cs->exi = exi_public;
 	}
 
@@ -3470,6 +3485,8 @@
 			    cs->exi)) {
 				*cs->statusp = resp->status =
 				    NFS4ERR_SERVERFAULT;
+				if (sav_exi)
+					exi_rele(sav_exi);
 				goto out;
 			}
 		}
@@ -3481,9 +3498,12 @@
 	if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
 		VN_RELE(cs->vp);
 		cs->vp = NULL;
+		exi_rele(cs->exi);
 		cs->exi = sav_exi;
 		goto out;
 	}
+	if (sav_exi)
+		exi_rele(sav_exi);
 
 	*cs->statusp = resp->status = NFS4_OK;
 out:
@@ -3536,7 +3556,9 @@
 	}
 
 	fh_fmtp = (nfs_fh4_fmt_t *)args->object.nfs_fh4_val;
-	cs->exi = checkexport4(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen,
+	if (cs->exi)
+		exi_rele(cs->exi);
+	cs->exi = checkexport(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen,
 	    NULL);
 
 	if (cs->exi == NULL) {
@@ -3610,11 +3632,13 @@
 	 * one or more exports further down in the server's
 	 * file tree.
 	 */
-	exi = checkexport4(&rootdir->v_vfsp->vfs_fsid, &fid, NULL);
+	exi = checkexport(&rootdir->v_vfsp->vfs_fsid, &fid, NULL);
 	if (exi == NULL || exi->exi_export.ex_flags & EX_PUBLIC) {
 		NFS4_DEBUG(rfs4_debug,
 		    (CE_WARN, "rfs4_op_putrootfh: export check failure"));
 		*cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
+		if (exi)
+			exi_rele(exi);
 		goto out;
 	}
 
@@ -3625,6 +3649,7 @@
 	error = makefh4(&cs->fh, rootdir, exi);
 	if (error != 0) {
 		*cs->statusp = resp->status = puterrno4(error);
+		exi_rele(exi);
 		goto out;
 	}
 
@@ -3637,9 +3662,12 @@
 	if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
 		VN_RELE(rootdir);
 		cs->vp = NULL;
+		exi_rele(exi);
 		cs->exi = sav_exi;
 		goto out;
 	}
+	if (sav_exi)
+		exi_rele(sav_exi);
 
 	*cs->statusp = resp->status = NFS4_OK;
 	cs->deleg = FALSE;
@@ -4817,7 +4845,11 @@
 	}
 	cs->vp = cs->saved_vp;
 	cs->saved_vp = NULL;
+	if (cs->exi)
+		exi_rele(cs->exi);
 	cs->exi = cs->saved_exi;
+	if (cs->exi)
+		exi_hold(cs->exi);
 	nfs_fh4_copy(&cs->saved_fh, &cs->fh);
 	*cs->statusp = resp->status = NFS4_OK;
 	cs->deleg = FALSE;
@@ -4846,7 +4878,11 @@
 	}
 	cs->saved_vp = cs->vp;
 	VN_HOLD(cs->saved_vp);
+	if (cs->saved_exi)
+		exi_rele(cs->saved_exi);
 	cs->saved_exi = cs->exi;
+	if (cs->saved_exi)
+		exi_hold(cs->saved_exi);
 	/*
 	 * since SAVEFH is fairly rare, don't alloc space for its fh
 	 * unless necessary.
@@ -5811,18 +5847,6 @@
 	    COMPOUND4args *, args);
 
 	/*
-	 * For now, NFS4 compound processing must be protected by
-	 * exported_lock because it can access more than one exportinfo
-	 * per compound and share/unshare can now change multiple
-	 * exinfo structs.  The NFS2/3 code only refs 1 exportinfo
-	 * per proc (excluding public exinfo), and exi_count design
-	 * is sufficient to protect concurrent execution of NFS2/3
-	 * ops along with unexport.  This lock will be removed as
-	 * part of the NFSv4 phase 2 namespace redesign work.
-	 */
-	rw_enter(&exported_lock, RW_READER);
-
-	/*
 	 * If this is the first compound we've seen, we need to start all
 	 * new instances' grace periods.
 	 */
@@ -5891,11 +5915,14 @@
 		}
 	}
 
-	rw_exit(&exported_lock);
 
 	DTRACE_NFSV4_2(compound__done, struct compound_state *, &cs,
 	    COMPOUND4res *, resp);
 
+	if (cs.exi)
+		exi_rele(cs.exi);
+	if (cs.saved_exi)
+		exi_rele(cs.saved_exi);
 	if (cs.vp)
 		VN_RELE(cs.vp);
 	if (cs.saved_vp)
@@ -7496,7 +7523,9 @@
 			nfs_fh4_fmt_t *fh_fmtp =
 			    (nfs_fh4_fmt_t *)oo->ro_reply_fh.nfs_fh4_val;
 
-			cs->exi = checkexport4(&fh_fmtp->fh4_fsid,
+			if (cs->exi)
+				exi_rele(cs->exi);
+			cs->exi = checkexport(&fh_fmtp->fh4_fsid,
 			    (fid_t *)&fh_fmtp->fh4_xlen, NULL);
 
 			if (cs->exi == NULL) {
