changeset 13814:829c00a55a37

2986 nfs: exi refcounter leak at rfs3_lookup Reviewed by: Albert Lee <trisk@nexenta.com> Reviewed by: Gordon Ross <gwr@nexenta.com> Approved by: Albert Lee <trisk@nexenta.com>
author Vitaliy Gusev <gusev.vitaliy@nexenta.com>
date Wed, 22 Aug 2012 13:03:31 +0000
parents 57f9d55c2a31
children 61cf2631639d
files usr/src/uts/common/fs/nfs/nfs3_srv.c usr/src/uts/common/fs/nfs/nfs_server.c usr/src/uts/common/fs/nfs/nfs_srv.c
diffstat 3 files changed, 50 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c	Wed Sep 12 04:54:49 2012 +0000
+++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c	Wed Aug 22 13:03:31 2012 +0000
@@ -433,16 +433,25 @@
 		goto out1;
 	}
 
+	exi_hold(exi);
+
 	/*
 	 * If the public filehandle is used then allow
 	 * a multi-component lookup
 	 */
 	if (PUBLIC_FH3(&args->what.dir)) {
+		struct exportinfo *new;
+
 		publicfh_flag = TRUE;
+
 		error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
-		    &exi, &sec);
-		if (error && exi != NULL)
-			exi_rele(exi); /* See comment below Re: publicfh_flag */
+		    &new, &sec);
+
+		if (error == 0) {
+			exi_rele(exi);
+			exi = new;
+		}
+
 		/*
 		 * Since WebNFS may bypass MOUNT, we need to ensure this
 		 * request didn't come from an unlabeled admin_low client.
@@ -464,8 +473,6 @@
 			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);
 				resp->status = NFS3ERR_ACCES;
 				error = 1;
@@ -491,8 +498,6 @@
 		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);
 				resp->status = NFS3ERR_ACCES;
 				error = 1;
@@ -519,18 +524,10 @@
 		goto out;
 	}
 
-	/*
-	 * 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, common_dispatch.
-	 */
-	if (publicfh_flag)
-		exi_rele(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;
@@ -552,6 +549,12 @@
 	return;
 
 out:
+	/*
+	 * The passed argument exportinfo is released by the
+	 * caller, common_dispatch
+	 */
+	exi_rele(exi);
+
 	if (curthread->t_flag & T_WOULDBLOCK) {
 		curthread->t_flag &= ~T_WOULDBLOCK;
 		resp->status = NFS3ERR_JUKEBOX;
--- a/usr/src/uts/common/fs/nfs/nfs_server.c	Wed Sep 12 04:54:49 2012 +0000
+++ b/usr/src/uts/common/fs/nfs/nfs_server.c	Wed Aug 22 13:03:31 2012 +0000
@@ -21,6 +21,7 @@
 /*
  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
@@ -2800,8 +2801,8 @@
 			 */
 
 			/* Release the reference on the old exi value */
-			ASSERT(*exi != NULL);
 			exi_rele(*exi);
+			*exi = NULL;
 
 			if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) {
 				VN_RELE(*vpp);
@@ -2814,6 +2815,9 @@
 	if (mc_dvp)
 		VN_RELE(mc_dvp);
 
+	if (error && *exi != NULL)
+		exi_rele(*exi);
+
 	return (error);
 }
 
@@ -2959,16 +2963,19 @@
 /*
  * Get the export information for the lookup vnode, and verify its
  * useable.
+ *
+ * Set @exip only in success
  */
 int
 nfs_check_vpexi(vnode_t *mc_dvp, vnode_t *vp, cred_t *cr,
-    struct exportinfo **exi)
+    struct exportinfo **exip)
 {
 	int walk;
 	int error = 0;
-
-	*exi = nfs_vptoexi(mc_dvp, vp, cr, &walk, NULL, FALSE);
-	if (*exi == NULL)
+	struct exportinfo *exi;
+
+	exi = nfs_vptoexi(mc_dvp, vp, cr, &walk, NULL, FALSE);
+	if (exi == NULL)
 		error = EACCES;
 	else {
 		/*
@@ -2977,10 +2984,13 @@
 		 * must not terminate below the
 		 * exported directory.
 		 */
-		if ((*exi)->exi_export.ex_flags & EX_NOSUB && walk > 0)
+		if (exi->exi_export.ex_flags & EX_NOSUB && walk > 0) {
 			error = EACCES;
+			exi_rele(exi);
+		}
 	}
-
+	if (error == 0)
+		*exip = exi;
 	return (error);
 }
 
--- a/usr/src/uts/common/fs/nfs/nfs_srv.c	Wed Sep 12 04:54:49 2012 +0000
+++ b/usr/src/uts/common/fs/nfs/nfs_srv.c	Wed Aug 22 13:03:31 2012 +0000
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
@@ -399,6 +400,8 @@
 		return;
 	}
 
+	exi_hold(exi);
+
 	/*
 	 * If the public filehandle is used then allow
 	 * a multi-component lookup, i.e. evaluate
@@ -409,9 +412,16 @@
 	 * which is OK as long as the filesystem is exported.
 	 */
 	if (PUBLIC_FH2(fhp)) {
+		struct exportinfo *new;
+
 		publicfh_flag = TRUE;
-		error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &exi,
+		error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &new,
 		    &sec);
+
+		if (error == 0) {
+			exi_rele(exi);
+			exi = new;
+		}
 	} else {
 		/*
 		 * Do a normal single component lookup.
@@ -452,13 +462,10 @@
 	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.
+	 * The passed argument exportinfo is released by the
+	 * caller, comon_dispatch
 	 */
-	if (publicfh_flag && exi != NULL)
-		exi_rele(exi);
+	exi_rele(exi);
 
 	/*
 	 * If it's public fh, no 0x81, and client's flavor is