From ac2e2ac9c0f50bdd161daeb3faed2f7a1fd9ceae Mon Sep 17 00:00:00 2001
From: Vitaliy Gusev <gusev.vitaliy@nexenta.com>
Date: Mon, 22 Oct 2012 14:29:07 +0400
Subject: [PATCH 03/30] re #3541 rb11254 - nfs nohide - "nfssrv: need ability
 to go to submounts for v3 and v2 protocols"

---
 usr/src/cmd/fs.d/nfs/lib/sharetab.h     |  3 ++
 usr/src/lib/libshare/nfs/libshare_nfs.c | 12 +++++-
 usr/src/lib/libshare/nfs/libshare_nfs.h |  1 +
 usr/src/uts/common/fs/nfs/nfs3_srv.c    | 23 ++++++++---
 usr/src/uts/common/fs/nfs/nfs_srv.c     | 51 +++++++++++++++++++++++++
 usr/src/uts/common/nfs/export.h         |  3 +-
 usr/src/uts/common/nfs/nfs.h            |  2 +
 7 files changed, 87 insertions(+), 8 deletions(-)

diff --git a/usr/src/cmd/fs.d/nfs/lib/sharetab.h b/usr/src/cmd/fs.d/nfs/lib/sharetab.h
index b51c5e7d85..2a70b10d2d 100644
--- a/usr/src/cmd/fs.d/nfs/lib/sharetab.h
+++ b/usr/src/cmd/fs.d/nfs/lib/sharetab.h
@@ -22,6 +22,8 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ *
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
 /*
  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
@@ -65,6 +67,7 @@ extern "C" {
 #define	SHOPT_NOACLFAB	"noaclfab"
 #define	SHOPT_UIDMAP	"uidmap"
 #define	SHOPT_GIDMAP	"gidmap"
+#define	SHOPT_NOHIDE	"nohide"
 
 /* XXX The following are added for testing volatile fh's purposes only */
 #ifdef VOLATILE_FH_TEST
diff --git a/usr/src/lib/libshare/nfs/libshare_nfs.c b/usr/src/lib/libshare/nfs/libshare_nfs.c
index f4ddbddda7..484244e6ba 100644
--- a/usr/src/lib/libshare/nfs/libshare_nfs.c
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.c
@@ -174,8 +174,10 @@ struct option_defs optdefs[] = {
 	{SHOPT_UIDMAP, OPT_UIDMAP, OPT_TYPE_MAPPING},
 #define	OPT_GIDMAP	19
 	{SHOPT_GIDMAP, OPT_GIDMAP, OPT_TYPE_MAPPING},
+#define	OPT_NOHIDE	20
+	{SHOPT_NOHIDE, OPT_NOHIDE, OPT_TYPE_BOOLEAN},
 #ifdef VOLATILE_FH_TEST	/* XXX added for testing volatile fh's only */
-#define	OPT_VOLFH	20
+#define	OPT_VOLFH	21
 	{SHOPT_VOLFH, OPT_VOLFH},
 #endif /* VOLATILE_FH_TEST */
 	NULL
@@ -1027,6 +1029,14 @@ fill_export_from_optionset(struct exportdata *export, sa_optionset_t optionset)
 			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,
diff --git a/usr/src/lib/libshare/nfs/libshare_nfs.h b/usr/src/lib/libshare/nfs/libshare_nfs.h
index ac608f2b52..4a0660407e 100644
--- a/usr/src/lib/libshare/nfs/libshare_nfs.h
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.h
@@ -56,6 +56,7 @@ extern "C" {
 #define	SHOPT_NOACLFAB	"noaclfab"
 #define	SHOPT_UIDMAP	"uidmap"
 #define	SHOPT_GIDMAP	"gidmap"
+#define	SHOPT_NOHIDE	"nohide"
 
 /*
  * defined options types. These should be in a file rather than
diff --git a/usr/src/uts/common/fs/nfs/nfs3_srv.c b/usr/src/uts/common/fs/nfs/nfs3_srv.c
index b10ae94693..dc9164aafb 100644
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c
@@ -480,6 +480,12 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 	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;
 
@@ -3609,13 +3615,18 @@ good:
 		if (vn_is_nfs_reparse(nvp, cr))
 			nvap->va_type = VLNK;
 
-		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
+		if (vn_ismntpt(nvp)) {
+			infop[i].attr.attributes = FALSE;
 			infop[i].fh.handle_follows = FALSE;
+		} 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;
+		}
 
 		VN_RELE(nvp);
 		dp = nextdp(dp);
diff --git a/usr/src/uts/common/fs/nfs/nfs_srv.c b/usr/src/uts/common/fs/nfs/nfs_srv.c
index 0588c5643e..beb925441b 100644
--- a/usr/src/uts/common/fs/nfs/nfs_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs_srv.c
@@ -329,6 +329,52 @@ rfs_setattr_getfh(struct nfssaargs *args)
 	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.
@@ -426,6 +472,11 @@ rfs_lookup(struct nfsdiropargs *da, struct nfsdiropres *dr,
 	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 */
diff --git a/usr/src/uts/common/nfs/export.h b/usr/src/uts/common/nfs/export.h
index 0252e18b34..74b18f6b84 100644
--- a/usr/src/uts/common/nfs/export.h
+++ b/usr/src/uts/common/nfs/export.h
@@ -20,8 +20,8 @@
  */
 
 /*
- * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  * Copyright 2016 Jason King.
  */
 
@@ -189,6 +189,7 @@ struct exportdata32 {
 #define	EX_NOACLFAB	0x2000	/* If set, NFSv2 and v3 servers won't */
 				/* fabricate an aclent_t ACL on file systems */
 				/* that don't support aclent_t ACLs */
+#define	EX_NOHIDE	0x4000	/* traversable from exported parent */
 
 #ifdef	_KERNEL
 
diff --git a/usr/src/uts/common/nfs/nfs.h b/usr/src/uts/common/nfs/nfs.h
index fe69ae4e87..ff1f67cfe6 100644
--- a/usr/src/uts/common/nfs/nfs.h
+++ b/usr/src/uts/common/nfs/nfs.h
@@ -2278,6 +2278,8 @@ extern int	rfs_publicfh_mclookup(char *, vnode_t *, cred_t *, 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 int	rfs_climb_crossmnt(vnode_t **, struct exportinfo **, cred_t *);
 
 extern vtype_t		nf3_to_vt[];
 extern kstat_named_t	*rfsproccnt_v3_ptr;
-- 
2.21.0

