From fc11ea7aae1607e14e5fc362add75c3f068f814d Mon Sep 17 00:00:00 2001
From: Marcel Telka <marcel.telka@nexenta.com>
Date: Sat, 24 Jan 2015 00:58:09 +0100
Subject: [PATCH 05/30] NEX-3095 Issues related to NFS nohide Reviewed by: Dan
 Fields <dan.fields@nexenta.com>

---
 usr/src/uts/common/fs/nfs/nfs3_srv.c | 24 +++++-------------------
 usr/src/uts/common/fs/nfs/nfs_srv.c  | 26 ++++++++++++--------------
 2 files changed, 17 insertions(+), 33 deletions(-)

diff --git a/usr/src/uts/common/fs/nfs/nfs3_srv.c b/usr/src/uts/common/fs/nfs/nfs3_srv.c
index e3cf57b3a7..7f5f4611b3 100644
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c
@@ -382,10 +382,6 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 
 	dvap = NULL;
 
-	/*
-	 * The passed argument exportinfo is released by the
-	 * caller, common_dispatch
-	 */
 	if (exi != NULL)
 		exi_hold(exi);
 
@@ -457,10 +453,12 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 	 */
 	if (PUBLIC_FH3(&args->what.dir)) {
 		publicfh_flag = TRUE;
+
+		exi_rele(exi);
+
 		error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
 		    &exi, &sec);
-		if (error && exi != NULL)
-			exi_rele(exi); /* See comment below Re: publicfh_flag */
+
 		/*
 		 * Since WebNFS may bypass MOUNT, we need to ensure this
 		 * request didn't come from an unlabeled admin_low client.
@@ -482,8 +480,6 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 			if (tp == NULL || tp->tpc_tp.tp_doi !=
 			    l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
 			    SUN_CIPSO) {
-				if (exi != NULL)
-					exi_rele(exi);
 				VN_RELE(vp);
 				error = EACCES;
 			}
@@ -514,8 +510,6 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
 			if (!do_rfs_label_check(clabel, dvp,
 			    DOMINANCE_CHECK, exi)) {
-				if (publicfh_flag && exi != NULL)
-					exi_rele(exi);
 				VN_RELE(vp);
 				error = EACCES;
 			}
@@ -536,15 +530,6 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 			auth_weak = TRUE;
 	}
 
-	/*
-	 * If publicfh_flag is true then we have called rfs_publicfh_mclookup
-	 * and have obtained a new exportinfo in exi which needs to be
-	 * released. Note that the original exportinfo pointed to by exi
-	 * will be released by the caller, common_dispatch.
-	 */
-	if (publicfh_flag)
-		exi_rele(exi);
-
 	if (error) {
 		VN_RELE(vp);
 		goto out;
@@ -553,6 +538,7 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 	va.va_mask = AT_ALL;
 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 
+	exi_rele(exi);
 	VN_RELE(vp);
 
 	resp->status = NFS3_OK;
diff --git a/usr/src/uts/common/fs/nfs/nfs_srv.c b/usr/src/uts/common/fs/nfs/nfs_srv.c
index d90a2d9d40..2535ab3219 100644
--- a/usr/src/uts/common/fs/nfs/nfs_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs_srv.c
@@ -18,9 +18,10 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2016 by Delphix. All rights reserved.
  */
 
@@ -334,17 +335,14 @@ int
 rfs_cross_mnt(vnode_t **vpp, struct exportinfo **exip)
 {
 	struct exportinfo *exi;
-	vnode_t *vp;
+	vnode_t *vp = *vpp;
 	fid_t fid;
 	int error;
 
-	vp = *vpp;
-
-	/* traverse() releases argument in success */
-	VN_HOLD(*vpp);
+	VN_HOLD(vp);
 
 	if ((error = traverse(&vp)) != 0) {
-		VN_RELE(*vpp);
+		VN_RELE(vp);
 		return (error);
 	}
 
@@ -363,6 +361,8 @@ rfs_cross_mnt(vnode_t **vpp, struct exportinfo **exip)
 		 * It is not error, just subdir is not exported
 		 * or "nohide" is not set
 		 */
+		if (exi != NULL)
+			exi_rele(exi);
 		VN_RELE(vp);
 	} else {
 		/* go to submount */
@@ -372,6 +372,7 @@ rfs_cross_mnt(vnode_t **vpp, struct exportinfo **exip)
 		VN_RELE(*vpp);
 		*vpp = vp;
 	}
+
 	return (0);
 }
 
@@ -499,6 +500,9 @@ rfs_lookup(struct nfsdiropargs *da, struct nfsdiropres *dr,
 	 */
 	if (PUBLIC_FH2(fhp)) {
 		publicfh_flag = TRUE;
+
+		exi_rele(exi);
+
 		error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &exi,
 		    &sec);
 	} else {
@@ -546,13 +550,7 @@ rfs_lookup(struct nfsdiropargs *da, struct nfsdiropres *dr,
 out:
 	VN_RELE(dvp);
 
-	/*
-	 * If publicfh_flag is true then we have called rfs_publicfh_mclookup
-	 * and have obtained a new exportinfo in exi which needs to be
-	 * released. Note the the original exportinfo pointed to by exi
-	 * will be released by the caller, comon_dispatch.
-	 */
-	if (publicfh_flag && exi != NULL)
+	if (exi != NULL)
 		exi_rele(exi);
 
 	/*
-- 
2.21.0

