--- old/usr/src/cmd/fs.d/nfs/lib/sharetab.h	2012-08-04 02:30:31.622492609 +0400
+++ new/usr/src/cmd/fs.d/nfs/lib/sharetab.h	2012-08-04 02:30:31.030492593 +0400
@@ -60,6 +60,7 @@
 #define	SHOPT_INDEX	"index"
 #define	SHOPT_LOG	"log"
 #define	SHOPT_NOACLFAB	"noaclfab"
+#define	SHOPT_NOHIDE	"nohide"
 
 /* XXX The following are added for testing volatile fh's purposes only */
 #ifdef VOLATILE_FH_TEST
--- old/usr/src/lib/libshare/nfs/libshare_nfs.c	2012-08-04 02:30:32.678492636 +0400
+++ new/usr/src/lib/libshare/nfs/libshare_nfs.c	2012-08-04 02:30:32.030492619 +0400
@@ -166,8 +166,11 @@
 	{"", OPT_CHARSET_MAP, OPT_TYPE_ACCLIST},
 #define	OPT_NOACLFAB	17
 	{SHOPT_NOACLFAB, OPT_NOACLFAB, OPT_TYPE_BOOLEAN},
+#define	OPT_NOHIDE	18
+	{SHOPT_NOHIDE, OPT_NOHIDE, OPT_TYPE_BOOLEAN},
+
 #ifdef VOLATILE_FH_TEST	/* XXX added for testing volatile fh's only */
-#define	OPT_VOLFH	18
+#define	OPT_VOLFH	19
 	{SHOPT_VOLFH, OPT_VOLFH},
 #endif /* VOLATILE_FH_TEST */
 	NULL
@@ -1013,6 +1016,14 @@
 			else
 				export->ex_flags &= ~EX_NOACLFAB;
 			break;
+		case OPT_NOHIDE:
+			if (value != NULL && (strcasecmp(value, "true") == 0 ||
+			    strcmp(value, "1") == 0))
+				export->ex_flags |= EX_NOHIDE;
+			else
+				export->ex_flags &= ~EX_NOHIDE;
+
+			break;
 		default:
 			/* have a syntactic error */
 			(void) printf(dgettext(TEXT_DOMAIN,
--- old/usr/src/lib/libshare/nfs/libshare_nfs.h	2012-08-04 02:30:33.750492663 +0400
+++ new/usr/src/lib/libshare/nfs/libshare_nfs.h	2012-08-04 02:30:33.154492648 +0400
@@ -53,6 +53,7 @@
 #define	SHOPT_LOG	"log"
 #define	SHOPT_CKSUM	"cksum"
 #define	SHOPT_NOACLFAB	"noaclfab"
+#define	SHOPT_NOHIDE	"nohide"
 
 /*
  * defined options types. These should be in a file rather than
--- old/usr/src/man/man1m/share_nfs.1m	2012-08-04 02:30:34.702492687 +0400
+++ new/usr/src/man/man1m/share_nfs.1m	2012-08-04 02:30:34.094492672 +0400
@@ -132,6 +132,31 @@
 .sp
 .ne 2
 .na
+\fB\fBnohide\fR\fR
+.ad
+.sp .6
+.RS 4n
+
+By default, if a server exports two filesystems, one of which is mounted as a
+child of the other, NFS Version 2 and Version 3 clients must mount both
+filesystems explicitly in order to access them. If a client only mounts
+the parent, it will see an empty directory at the location where the other
+filesystem is mounted.
+
+Setting the \fBnohide\fR option on a filesystem causes it to no longer be
+hidden in this manner, and a client will be able to move from the parent
+filesystem to this one without noticing the change. However, some NFS clients
+or applications may not function correctly when this option is used. In
+particular, files on different underlying filesystems may appear to have the
+same inode numbers.
+
+This option is equivalent to the option of the same name provided in \fBLinux
+NFS\fR, and only applies to NFS Version 2 and Version 3 requests.
+.RE
+
+.sp
+.ne 2
+.na
 \fB\fBnone=\fR\fIaccess_list\fR\fR
 .ad
 .sp .6
--- old/usr/src/uts/common/fs/nfs/nfs3_srv.c	2012-08-04 02:30:35.694492713 +0400
+++ new/usr/src/uts/common/fs/nfs/nfs3_srv.c	2012-08-04 02:30:35.074492697 +0400
@@ -71,12 +71,6 @@
  * for a description of this interface.
  */
 
-#ifdef DEBUG
-int rfs3_do_pre_op_attr = 1;
-int rfs3_do_post_op_attr = 1;
-int rfs3_do_post_op_fh3 = 1;
-#endif
-
 static writeverf3 write3verf;
 
 static int	sattr3_to_vattr(sattr3 *, struct vattr *);
@@ -227,12 +221,7 @@
 	if (error)
 		goto out;
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr)
-		bvap = &bva;
-#else
 	bvap = &bva;
-#endif
 
 	if (rdonly(exi, req) || vn_is_readonly(vp)) {
 		resp->status = NFS3ERR_ROFS;
@@ -322,16 +311,8 @@
 		goto out1;
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		ava.va_mask = AT_ALL;
-		avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
-	} else
-		avap = NULL;
-#else
 	ava.va_mask = AT_ALL;
 	avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
-#endif
 
 	/*
 	 * Force modified metadata out to stable storage.
@@ -421,15 +402,8 @@
 		}
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr) {
-		dva.va_mask = AT_ALL;
-		dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
-	}
-#else
 	dva.va_mask = AT_ALL;
 	dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
-#endif
 
 	if (args->what.name == nfs3nametoolong) {
 		resp->status = NFS3ERR_NAMETOOLONG;
@@ -457,16 +431,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.
@@ -488,8 +471,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;
@@ -505,6 +486,12 @@
 	if (name != args->what.name)
 		kmem_free(name, MAXPATHLEN + 1);
 
+	if (error == 0 && vn_ismntpt(vp)) {
+		error = rfs_cross_mnt(&vp, &exi);
+		if (error)
+			VN_RELE(vp);
+	}
+
 	if (is_system_labeled() && error == 0) {
 		bslabel_t *clabel = req->rq_label;
 
@@ -515,8 +502,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;
@@ -524,16 +509,8 @@
 		}
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		dva.va_mask = AT_ALL;
-		dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
-	} else
-		dvap = NULL;
-#else
 	dva.va_mask = AT_ALL;
 	dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
-#endif
 
 	if (error)
 		goto out;
@@ -551,26 +528,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);
-
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
-#endif
 
+	exi_rele(exi);
 	VN_RELE(vp);
 
 	resp->status = NFS3_OK;
@@ -592,6 +553,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;
@@ -662,12 +629,7 @@
 	if (error)
 		goto out;
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr)
-		vap = &va;
-#else
 	vap = &va;
-#endif
 
 	resp->resok.access = 0;
 
@@ -742,16 +704,8 @@
 			resp->resok.access |= ACCESS3_EXECUTE;
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
-#endif
 
 	resp->status = NFS3_OK;
 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
@@ -816,12 +770,7 @@
 	if (error)
 		goto out;
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr)
-		vap = &va;
-#else
 	vap = &va;
-#endif
 
 	/* We lied about the object type for a referral */
 	if (vn_is_nfs_reparse(vp, cr))
@@ -889,16 +838,9 @@
 			*(data + MAXPATHLEN - uio.uio_resid) = '\0';
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-#endif
+
 	/* Lie about object type again just to be consistent */
 	if (is_referral && vap != NULL)
 		vap->va_type = VLNK;
@@ -1077,12 +1019,7 @@
 	if (error)
 		goto out;
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr)
-		vap = &va;
-#else
 	vap = &va;
-#endif
 
 	if (vp->v_type != VREG) {
 		resp->status = NFS3ERR_INVAL;
@@ -1232,20 +1169,10 @@
 	va.va_mask = AT_ALL;
 	error = VOP_GETATTR(vp, &va, 0, cr, &ct);
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		if (error)
-			vap = NULL;
-		else
-			vap = &va;
-	} else
-		vap = NULL;
-#else
 	if (error)
 		vap = NULL;
 	else
 		vap = &va;
-#endif
 
 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
 
@@ -1419,10 +1346,6 @@
 		goto err;
 
 	bvap = &bva;
-#ifdef DEBUG
-	if (!rfs3_do_pre_op_attr)
-		bvap = NULL;
-#endif
 	avap = bvap;
 
 	if (args->count != args->data.data_len) {
@@ -1534,11 +1457,6 @@
 	ava.va_mask = AT_ALL;
 	avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava;
 
-#ifdef DEBUG
-	if (!rfs3_do_post_op_attr)
-		avap = NULL;
-#endif
-
 	if (error)
 		goto err;
 
@@ -1627,16 +1545,8 @@
 		goto out;
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr) {
-		dbva.va_mask = AT_ALL;
-		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
-	} else
-		dbvap = NULL;
-#else
 	dbva.va_mask = AT_ALL;
 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
-#endif
 	davap = dbvap;
 
 	if (args->where.name == nfs3nametoolong) {
@@ -1799,16 +1709,8 @@
 	error = VOP_CREATE(dvp, name, &va, excl, VWRITE,
 	    &vp, cr, 0, NULL, NULL);
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		dava.va_mask = AT_ALL;
-		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
-	} else
-		davap = NULL;
-#else
 	dava.va_mask = AT_ALL;
 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
-#endif
 
 	if (error) {
 		/*
@@ -1912,24 +1814,11 @@
 	if (name != args->where.name)
 		kmem_free(name, MAXPATHLEN + 1);
 
-#ifdef DEBUG
-	if (!rfs3_do_post_op_attr)
-		vap = NULL;
-#endif
-
-#ifdef DEBUG
-	if (!rfs3_do_post_op_fh3)
-		resp->resok.obj.handle_follows = FALSE;
-	else {
-#endif
 	error = makefh3(&resp->resok.obj.handle, vp, exi);
 	if (error)
 		resp->resok.obj.handle_follows = FALSE;
 	else
 		resp->resok.obj.handle_follows = TRUE;
-#ifdef DEBUG
-	}
-#endif
 
 	/*
 	 * Force modified data and metadata out to stable storage.
@@ -2013,16 +1902,8 @@
 		goto out;
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr) {
-		dbva.va_mask = AT_ALL;
-		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
-	} else
-		dbvap = NULL;
-#else
 	dbva.va_mask = AT_ALL;
 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
-#endif
 	davap = dbvap;
 
 	if (args->where.name == nfs3nametoolong) {
@@ -2082,16 +1963,8 @@
 	if (name != args->where.name)
 		kmem_free(name, MAXPATHLEN + 1);
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		dava.va_mask = AT_ALL;
-		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
-	} else
-		davap = NULL;
-#else
 	dava.va_mask = AT_ALL;
 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
-#endif
 
 	/*
 	 * Force modified data and metadata out to stable storage.
@@ -2101,30 +1974,14 @@
 	if (error)
 		goto out;
 
-#ifdef DEBUG
-	if (!rfs3_do_post_op_fh3)
-		resp->resok.obj.handle_follows = FALSE;
-	else {
-#endif
 	error = makefh3(&resp->resok.obj.handle, vp, exi);
 	if (error)
 		resp->resok.obj.handle_follows = FALSE;
 	else
 		resp->resok.obj.handle_follows = TRUE;
-#ifdef DEBUG
-	}
-#endif
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-#endif
 
 	/*
 	 * Force modified data and metadata out to stable storage.
@@ -2194,16 +2051,8 @@
 		goto err;
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr) {
-		dbva.va_mask = AT_ALL;
-		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
-	} else
-		dbvap = NULL;
-#else
 	dbva.va_mask = AT_ALL;
 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
-#endif
 	davap = dbvap;
 
 	if (args->where.name == nfs3nametoolong) {
@@ -2275,16 +2124,8 @@
 
 	error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0);
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		dava.va_mask = AT_ALL;
-		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
-	} else
-		davap = NULL;
-#else
 	dava.va_mask = AT_ALL;
 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
-#endif
 
 	if (error)
 		goto err;
@@ -2306,30 +2147,14 @@
 		goto out;
 	}
 
-#ifdef DEBUG
-	if (!rfs3_do_post_op_fh3)
-		resp->resok.obj.handle_follows = FALSE;
-	else {
-#endif
 	error = makefh3(&resp->resok.obj.handle, vp, exi);
 	if (error)
 		resp->resok.obj.handle_follows = FALSE;
 	else
 		resp->resok.obj.handle_follows = TRUE;
-#ifdef DEBUG
-	}
-#endif
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-#endif
 
 	/*
 	 * Force modified data and metadata out to stable storage.
@@ -2402,16 +2227,8 @@
 		goto out;
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr) {
-		dbva.va_mask = AT_ALL;
-		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
-	} else
-		dbvap = NULL;
-#else
 	dbva.va_mask = AT_ALL;
 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
-#endif
 	davap = dbvap;
 
 	if (args->where.name == nfs3nametoolong) {
@@ -2513,16 +2330,8 @@
 	if (name != args->where.name)
 		kmem_free(name, MAXPATHLEN + 1);
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		dava.va_mask = AT_ALL;
-		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
-	} else
-		davap = NULL;
-#else
 	dava.va_mask = AT_ALL;
 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
-#endif
 
 	/*
 	 * Force modified data and metadata out to stable storage.
@@ -2534,30 +2343,14 @@
 
 	resp->status = NFS3_OK;
 
-#ifdef DEBUG
-	if (!rfs3_do_post_op_fh3)
-		resp->resok.obj.handle_follows = FALSE;
-	else {
-#endif
 	error = makefh3(&resp->resok.obj.handle, vp, exi);
 	if (error)
 		resp->resok.obj.handle_follows = FALSE;
 	else
 		resp->resok.obj.handle_follows = TRUE;
-#ifdef DEBUG
-	}
-#endif
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-#endif
 
 	/*
 	 * Force modified metadata out to stable storage.
@@ -2626,16 +2419,8 @@
 		goto err;
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr) {
-		bva.va_mask = AT_ALL;
-		bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
-	} else
-		bvap = NULL;
-#else
 	bva.va_mask = AT_ALL;
 	bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
-#endif
 	avap = bvap;
 
 	if (vp->v_type != VDIR) {
@@ -2711,16 +2496,8 @@
 	VN_RELE(targvp);
 	targvp = NULL;
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		ava.va_mask = AT_ALL;
-		avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
-	} else
-		avap = NULL;
-#else
 	ava.va_mask = AT_ALL;
 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
-#endif
 
 	/*
 	 * Force modified data and metadata out to stable storage.
@@ -2786,16 +2563,8 @@
 		goto err;
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr) {
-		bva.va_mask = AT_ALL;
-		bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
-	} else
-		bvap = NULL;
-#else
 	bva.va_mask = AT_ALL;
 	bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
-#endif
 	avap = bvap;
 
 	if (vp->v_type != VDIR) {
@@ -2848,16 +2617,8 @@
 	if (name != args->object.name)
 		kmem_free(name, MAXPATHLEN + 1);
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		ava.va_mask = AT_ALL;
-		avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
-	} else
-		avap = NULL;
-#else
 	ava.va_mask = AT_ALL;
 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
-#endif
 
 	/*
 	 * Force modified data and metadata out to stable storage.
@@ -2958,16 +2719,8 @@
 		}
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr) {
-		fbva.va_mask = AT_ALL;
-		fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
-	} else
-		fbvap = NULL;
-#else
 	fbva.va_mask = AT_ALL;
 	fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
-#endif
 	favap = fbvap;
 
 	fh3 = &args->to.dir;
@@ -2989,16 +2742,8 @@
 		goto err;
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr) {
-		tbva.va_mask = AT_ALL;
-		tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
-	} else
-		tbvap = NULL;
-#else
 	tbva.va_mask = AT_ALL;
 	tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
-#endif
 	tavap = tbvap;
 
 	if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
@@ -3100,22 +2845,10 @@
 	VN_RELE(srcvp);
 	srcvp = NULL;
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		fava.va_mask = AT_ALL;
-		favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
-		tava.va_mask = AT_ALL;
-		tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
-	} else {
-		favap = NULL;
-		tavap = NULL;
-	}
-#else
 	fava.va_mask = AT_ALL;
 	favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
 	tava.va_mask = AT_ALL;
 	tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
-#endif
 
 	/*
 	 * Force modified data and metadata out to stable storage.
@@ -3197,16 +2930,8 @@
 		goto out;
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-#endif
 
 	fh3 = &args->link.dir;
 	to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
@@ -3243,16 +2968,8 @@
 		goto out;
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr) {
-		bva.va_mask = AT_ALL;
-		bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
-	} else
-		bvap = NULL;
-#else
 	bva.va_mask = AT_ALL;
 	bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
-#endif
 
 	if (dvp->v_type != VDIR) {
 		resp->status = NFS3ERR_NOTDIR;
@@ -3298,22 +3015,10 @@
 
 	error = VOP_LINK(dvp, vp, name, cr, NULL, 0);
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-		ava.va_mask = AT_ALL;
-		avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
-	} else {
-		vap = NULL;
-		avap = NULL;
-	}
-#else
 	va.va_mask = AT_ALL;
 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
 	ava.va_mask = AT_ALL;
 	avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
-#endif
 
 	/*
 	 * Force modified data and metadata out to stable storage.
@@ -3442,16 +3147,8 @@
 
 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-#endif
 
 	if (vp->v_type != VDIR) {
 		resp->status = NFS3ERR_NOTDIR;
@@ -3491,16 +3188,8 @@
 
 	error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-#endif
 
 	if (error) {
 		kmem_free(data, count);
@@ -3730,16 +3419,8 @@
 
 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-#endif
 
 	if (vp->v_type != VDIR) {
 		error = ENOTDIR;
@@ -3898,19 +3579,9 @@
 
 		/* else, fall through */
 	}
-
 good:
-
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-#endif
 
 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
 
@@ -3938,36 +3609,25 @@
 			continue;
 		}
 
-#ifdef DEBUG
-		if (rfs3_do_post_op_attr) {
-			nva.va_mask = AT_ALL;
-			nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ?
-			    NULL : &nva;
-		} else
-			nvap = NULL;
-#else
 		nva.va_mask = AT_ALL;
 		nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
-#endif
+
 		/* Lie about the object type for a referral */
 		if (vn_is_nfs_reparse(nvp, cr))
 			nvap->va_type = VLNK;
 
-		vattr_to_post_op_attr(nvap, &infop[i].attr);
-
-#ifdef DEBUG
-		if (!rfs3_do_post_op_fh3)
-			infop[i].fh.handle_follows = FALSE;
-		else {
-#endif
-		error = makefh3(&infop[i].fh.handle, nvp, exi);
-		if (!error)
-			infop[i].fh.handle_follows = TRUE;
-		else
+		if (vn_ismntpt(nvp)) {
+			infop[i].attr.attributes = FALSE;
 			infop[i].fh.handle_follows = FALSE;
-#ifdef DEBUG
+		} else {
+			vattr_to_post_op_attr(nvap, &infop[i].attr);
+
+			error = makefh3(&infop[i].fh.handle, nvp, exi);
+			if (!error)
+				infop[i].fh.handle_follows = TRUE;
+			else
+				infop[i].fh.handle_follows = FALSE;
 		}
-#endif
 
 		VN_RELE(nvp);
 		dp = nextdp(dp);
@@ -4106,16 +3766,8 @@
 
 	error = VFS_STATVFS(vp->v_vfsp, &sb);
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-#endif
 
 	if (error)
 		goto out;
@@ -4211,16 +3863,8 @@
 		}
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-#endif
 
 	resp->status = NFS3_OK;
 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
@@ -4323,16 +3967,8 @@
 		}
 	}
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		va.va_mask = AT_ALL;
-		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-	} else
-		vap = NULL;
-#else
 	va.va_mask = AT_ALL;
 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
-#endif
 
 	error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
 	if (error)
@@ -4424,14 +4060,7 @@
 	if (error)
 		goto out;
 
-#ifdef DEBUG
-	if (rfs3_do_pre_op_attr)
-		bvap = &bva;
-	else
-		bvap = NULL;
-#else
 	bvap = &bva;
-#endif
 
 	if (rdonly(exi, req)) {
 		resp->status = NFS3ERR_ROFS;
@@ -4465,16 +4094,8 @@
 
 	error = VOP_FSYNC(vp, FSYNC, cr, NULL);
 
-#ifdef DEBUG
-	if (rfs3_do_post_op_attr) {
-		ava.va_mask = AT_ALL;
-		avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
-	} else
-		avap = NULL;
-#else
 	ava.va_mask = AT_ALL;
 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
-#endif
 
 	if (error)
 		goto out;
--- old/usr/src/uts/common/fs/nfs/nfs_server.c	2012-08-04 02:30:36.966492745 +0400
+++ new/usr/src/uts/common/fs/nfs/nfs_server.c	2012-08-04 02:30:36.346492728 +0400
@@ -2599,8 +2599,6 @@
 	vnode_t *realvp;
 	int error;
 
-	*exi = NULL;
-
 	/*
 	 * check if the given path is a url or native path. Since p is
 	 * modified by MCLpath(), it may be empty after returning from
@@ -2800,8 +2798,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 +2812,9 @@
 	if (mc_dvp)
 		VN_RELE(mc_dvp);
 
+	if (error && *exi != NULL)
+		exi_rele(*exi);
+
 	return (error);
 }
 
@@ -2959,16 +2960,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;
+	struct exportinfo *exi;
 
-	*exi = nfs_vptoexi(mc_dvp, vp, cr, &walk, NULL, FALSE);
-	if (*exi == NULL)
+	exi = nfs_vptoexi(mc_dvp, vp, cr, &walk, NULL, FALSE);
+	if (exi == NULL)
 		error = EACCES;
 	else {
 		/*
@@ -2977,10 +2981,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);
 }
 
--- old/usr/src/uts/common/fs/nfs/nfs_srv.c	2012-08-04 02:30:38.070492774 +0400
+++ new/usr/src/uts/common/fs/nfs/nfs_srv.c	2012-08-04 02:30:37.458492758 +0400
@@ -326,6 +326,51 @@
 	return (&args->saa_fh);
 }
 
+/* Change and release @exip and @vpp only in success */
+int
+rfs_cross_mnt(vnode_t **vpp, struct exportinfo **exip)
+{
+	struct exportinfo *exi;
+	vnode_t *vp;
+	fid_t fid;
+	int error;
+
+	vp = *vpp;
+
+	/* traverse() releases argument in success */
+	VN_HOLD(*vpp);
+
+	if ((error = traverse(&vp)) != 0) {
+		VN_RELE(*vpp);
+		return (error);
+	}
+
+	bzero(&fid, sizeof (fid));
+	fid.fid_len = MAXFIDSZ;
+	error = VOP_FID(vp, &fid, NULL);
+	if (error) {
+		VN_RELE(vp);
+		return (error);
+	}
+
+	exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
+	if (exi == NULL ||
+	    (exi->exi_export.ex_flags & EX_NOHIDE) == 0) {
+		/* It is not error, just subdir is not exported
+		 * or "nohide" is not set
+		 */
+		VN_RELE(vp);
+	} else {
+		/* go to submount */
+		exi_rele(*exip);
+		*exip = exi;
+
+		VN_RELE(*vpp);
+		*vpp = vp;
+	}
+	return (0);
+}
+
 /*
  * Directory lookup.
  * Returns an fhandle and file attributes for file name in a directory.
@@ -399,6 +444,8 @@
 		return;
 	}
 
+	exi_hold(exi);
+
 	/*
 	 * If the public filehandle is used then allow
 	 * a multi-component lookup, i.e. evaluate
@@ -409,9 +456,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.
@@ -423,6 +477,11 @@
 	if (name != da->da_name)
 		kmem_free(name, MAXPATHLEN);
 
+	if (error == 0 && vn_ismntpt(vp)) {
+		error = rfs_cross_mnt(&vp, &exi);
+		if (error)
+			VN_RELE(vp);
+	}
 
 	if (!error) {
 		va.va_mask = AT_ALL;	/* we want everything */
@@ -451,14 +510,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
--- old/usr/src/uts/common/nfs/export.h	2012-08-04 02:30:39.174492802 +0400
+++ new/usr/src/uts/common/nfs/export.h	2012-08-04 02:30:38.546492786 +0400
@@ -183,6 +183,7 @@
 #define	EX_CHARMAP	0x1000	/* NFS may need a character set conversion */
 #define	EX_NOACLFAB	0x2000	/* If set, NFSv2 and v3 servers doesn't */
 				/* fabricate ACL for VOP_GETSECATTR OTW call */
+#define	EX_NOHIDE	0x4000	/* traversable from exported parent */
 
 #ifdef	_KERNEL
 
--- old/usr/src/uts/common/nfs/nfs.h	2012-08-04 02:30:40.182492828 +0400
+++ new/usr/src/uts/common/nfs/nfs.h	2012-08-04 02:30:39.570492812 +0400
@@ -2275,16 +2275,13 @@
 			vnode_t **, struct exportinfo **, struct sec_ol *);
 extern int	rfs_pathname(char *, vnode_t **, vnode_t **,
 			vnode_t *, cred_t *, int);
+extern int rfs_cross_mnt(vnode_t **, struct exportinfo **);
 extern vtype_t		nf3_to_vt[];
 extern kstat_named_t	*rfsproccnt_v3_ptr;
 extern vfsops_t		*nfs3_vfsops;
 extern struct vnodeops	*nfs3_vnodeops;
 extern const struct fs_operation_def nfs3_vnodeops_template[];
-#ifdef DEBUG
-extern int		rfs3_do_pre_op_attr;
-extern int		rfs3_do_post_op_attr;
-extern int		rfs3_do_post_op_fh3;
-#endif
+
 /*
  * Some servers do not properly update the attributes of the
  * directory when changes are made.  To allow interoperability
