From 78c4613c6c4790bdbd76fa5c82a4f14ef70dba80 Mon Sep 17 00:00:00 2001
From: Dan McDonald <danmcd@joyent.com>
Date: Wed, 16 Oct 2019 11:28:58 -0400
Subject: [PATCH 1/2] Revert exi_zone to exi_zoneid, and install exi_ne
 backpointer

---
 usr/src/uts/common/fs/nfs/nfs3_srv.c    |  6 ++---
 usr/src/uts/common/fs/nfs/nfs4_srv_ns.c | 19 ++++++++--------
 usr/src/uts/common/fs/nfs/nfs_auth.c    |  2 +-
 usr/src/uts/common/fs/nfs/nfs_export.c  | 27 ++++++++++------------
 usr/src/uts/common/fs/nfs/nfs_srv.c     |  6 ++---
 usr/src/uts/common/nfs/export.h         | 30 ++++++++++++-------------
 6 files changed, 43 insertions(+), 47 deletions(-)

diff --git a/usr/src/uts/common/fs/nfs/nfs3_srv.c b/usr/src/uts/common/fs/nfs/nfs3_srv.c
index 0756d98930..400d4b80d3 100644
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c
@@ -445,7 +445,7 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 	}
 
 	fhp = &args->what.dir;
-	ASSERT3P(curzone, ==, exi->exi_zone); /* exi is guaranteed non-NULL. */
+	ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL */
 	if (strcmp(args->what.name, "..") == 0 &&
 	    EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
 		if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
@@ -1336,7 +1336,7 @@ rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
 		goto err;
 	}
 
-	ASSERT3P(curzone, ==, exi->exi_zone); /* exi is guaranteed non-NULL. */
+	ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL. */
 	ns = nfs3_get_srv();
 
 	if (is_system_labeled()) {
@@ -4139,7 +4139,7 @@ rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
 		goto out;
 	}
 
-	ASSERT3P(curzone, ==, exi->exi_zone); /* exi is guaranteed non-NULL. */
+	ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL. */
 	ns = nfs3_get_srv();
 	bva.va_mask = AT_ALL;
 	error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
index 89435c1cbd..3501d0f0bb 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
@@ -165,9 +165,7 @@ pseudo_exportfs(nfs_export_t *ne, vnode_t *vp, fid_t *fid,
 	VN_HOLD(exi->exi_vp);
 	exi->exi_visible = vis_head;
 	exi->exi_count = 1;
-	/* Caller will set exi_zone... */
-	/* XXX KEBE SAYS Uncomment me or fix in the caller */
-	/* exi->exi_zoneid = ne->ne_globals->nfs_zoneid; */
+	exi->exi_zoneid = ne->ne_globals->nfs_zoneid;
 	exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
 	    VSW_VOLATILEDEV) ? 1 : 0;
 	mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
@@ -642,10 +640,11 @@ treeclimb_export(struct exportinfo *exip)
 	struct vattr va;
 	treenode_t *tree_head = NULL;
 	timespec_t now;
-	nfs_export_t *ne = nfs_get_export();
+	nfs_export_t *ne;
 
+	ne = exip->exi_ne;
+	ASSERT3P(ne, ==, nfs_get_export());	/* curzone reality check */
 	ASSERT(RW_WRITE_HELD(&ne->exported_lock));
-	ASSERT3P(curzone, ==, exip->exi_zone);
 
 	gethrestime(&now);
 
@@ -661,12 +660,13 @@ treeclimb_export(struct exportinfo *exip)
 		if (error)
 			break;
 
+		/* XXX KEBE ASKS DO WE NEED THIS?!? */
 		ASSERT3U(exip->exi_zoneid, ==, curzone->zone_id);
 		/*
 		 * The root of the file system, or the zone's root for
 		 * in-zone NFS service needs special handling
 		 */
-		if (vp->v_flag & VROOT || VN_IS_CURZONEROOT(vp)) {
+		if (vp->v_flag & VROOT || vp == EXI_TO_ZONEROOTVP(exip)) {
 			if (!exportdir) {
 				struct exportinfo *exi;
 
@@ -698,8 +698,6 @@ treeclimb_export(struct exportinfo *exip)
 				 */
 				new_exi = pseudo_exportfs(ne, vp, &fid,
 				    vis_head, NULL);
-				/* XXX KEBE SAYS NUKE ME */
-				new_exi->exi_zone = exip->exi_zone;
 				vis_head = NULL;
 			}
 
@@ -842,7 +840,8 @@ treeclimb_unexport(nfs_export_t *ne, struct exportinfo *exip)
 	treenode_t *connect_point = NULL;
 
 	ASSERT(RW_WRITE_HELD(&ne->exported_lock));
-	ASSERT(curzone == exip->exi_zone || curzone == global_zone);
+	ASSERT(curzone->zone_id == exip->exi_zoneid ||
+	    curzone->zone_id == global_zone->zone_id);
 
 	/*
 	 * exi_tree can be null for the zone root
@@ -1005,7 +1004,7 @@ has_visible(struct exportinfo *exi, vnode_t *vp)
 	 * list.  i.e. if it does not have a visible list, then there is no
 	 * node in this filesystem leads to any other shared node.
 	 */
-	ASSERT3P(curzone, ==, exi->exi_zone);
+	ASSERT3P(curzone->zone_id, ==, exi->exi_zoneid);
 	if (vp_is_exported &&
 	    ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp))) {
 		return (exi->exi_visible ? 1 : 0);
diff --git a/usr/src/uts/common/fs/nfs/nfs_auth.c b/usr/src/uts/common/fs/nfs/nfs_auth.c
index c8b07dbaea..f1c8ae372c 100644
--- a/usr/src/uts/common/fs/nfs/nfs_auth.c
+++ b/usr/src/uts/common/fs/nfs/nfs_auth.c
@@ -884,7 +884,7 @@ nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor,
 
 	ASSERT(cr != NULL);
 
-	ASSERT3P(curzone, ==, exi->exi_zone);
+	ASSERT3P(curzone->zone_id, ==, exi->exi_zoneid);
 	nag = nfsauth_get_zg();
 
 	/*
diff --git a/usr/src/uts/common/fs/nfs/nfs_export.c b/usr/src/uts/common/fs/nfs/nfs_export.c
index 6b061e00eb..66237b3edc 100644
--- a/usr/src/uts/common/fs/nfs/nfs_export.c
+++ b/usr/src/uts/common/fs/nfs/nfs_export.c
@@ -693,24 +693,17 @@ exportinfo_t *
 vis2exi(treenode_t *tnode)
 {
 	exportinfo_t *exi_ret = NULL;
-#ifdef DEBUG
-	zone_t *zone = NULL;
-#endif
 
 	for (;;) {
 		tnode = tnode->tree_parent;
-#ifdef DEBUG
-		if (zone == NULL && tnode->tree_exi != NULL)
-			zone = tnode->tree_exi->exi_zone;
-#endif
 		if (TREE_ROOT(tnode)) {
-			ASSERT3P(zone, ==, tnode->tree_exi->exi_zone);
 			exi_ret = tnode->tree_exi;
 			break;
 		}
 	}
 
-	ASSERT(exi_ret); /* Every visible should have its home exportinfo */
+	/* Every visible should have its home exportinfo */
+	ASSERT(exi_ret != NULL);
 	return (exi_ret);
 }
 
@@ -824,6 +817,7 @@ export_link(nfs_export_t *ne, exportinfo_t *exi)
 	bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
 	    strlen(exi->exi_export.ex_path))];
 	exp_hash_link(exi, path_hash, bckt);
+	exi->exi_ne = ne;
 }
 
 /*
@@ -930,11 +924,14 @@ nfs_export_zone_init(nfs_globals_t *ng)
 	 *	ASSERT(curzone->zone_id == ng->nfs_zoneid);
 	 * We grab the zone pointer explicitly (like netstacks do) and
 	 * set the rootvp here.
+	 *
+	 * Subsequent exportinfo_t's that get export_link()ed to "ne" also
+	 * will backpoint to "ne" such that exi->exi_ne->exi_root->exi_vp
+	 * will get the zone's rootvp for a given exportinfo_t.
 	 */
 	zone = zone_find_by_id_nolock(ng->nfs_zoneid);
 	ne->exi_root->exi_vp = zone->zone_rootvp;
-	ne->exi_root->exi_zone = zone;	/* XXX KEBE SAYS lose me, and... */
-	/* ne->exi_root->exi_zoneid = ng->nfs_zoneid; */ /* use me instead! */
+	ne->exi_root->exi_zoneid = ng->nfs_zoneid;
 
 	/*
 	 * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
@@ -1412,9 +1409,8 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
 	exi->exi_fid = fid;
 	exi->exi_vp = vp;
 	exi->exi_count = 1;
-	exi->exi_zone = crgetzone(cr);
-	ASSERT(exi->exi_zone != NULL);		/* XXX KEBE ASKS... */
-	ASSERT3P(exi->exi_zone, ==, curzone);	/* ... are these legit? */
+	exi->exi_zoneid = crgetzoneid(cr);
+	ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
 	exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
 	    VSW_VOLATILEDEV) ? 1 : 0;
 	mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
@@ -1884,6 +1880,8 @@ export_unlink(nfs_export_t *ne, struct exportinfo *exi)
 
 	exp_hash_unlink(exi, fid_hash);
 	exp_hash_unlink(exi, path_hash);
+	ASSERT3P(exi->exi_ne, ==, ne);
+	exi->exi_ne = NULL;
 }
 
 /*
@@ -1928,7 +1926,6 @@ unexport(nfs_export_t *ne, struct exportinfo *exi)
 		exi->exi_visible = NULL;
 
 		/* interconnect the existing treenode with the new exportinfo */
-		newexi->exi_zone = exi->exi_zone; /* XXX KEBE SAYS LOSE ME */
 		newexi->exi_tree = exi->exi_tree;
 		newexi->exi_tree->tree_exi = newexi;
 
diff --git a/usr/src/uts/common/fs/nfs/nfs_srv.c b/usr/src/uts/common/fs/nfs/nfs_srv.c
index 637a0bb73d..ac4acbd32d 100644
--- a/usr/src/uts/common/fs/nfs/nfs_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs_srv.c
@@ -417,7 +417,7 @@ rfs_climb_crossmnt(vnode_t **dvpp, struct exportinfo **exip, cred_t *cr)
 	struct exportinfo *exi;
 	vnode_t *dvp = *dvpp;
 
-	ASSERT3P((*exip)->exi_zone, ==, curzone);
+	ASSERT3U((*exip)->exi_zoneid, ==, curzone->zone_id);
 	ASSERT((dvp->v_flag & VROOT) || VN_IS_CURZONEROOT(dvp));
 
 	VN_HOLD(dvp);
@@ -428,7 +428,7 @@ rfs_climb_crossmnt(vnode_t **dvpp, struct exportinfo **exip, cred_t *cr)
 		return (-1);
 	}
 
-	ASSERT3P(exi->exi_zone, ==, curzone);
+	ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
 	exi_rele(*exip);
 	*exip = exi;
 	VN_RELE(*dvpp);
@@ -489,7 +489,7 @@ rfs_lookup(struct nfsdiropargs *da, struct nfsdiropres *dr,
 	}
 
 	exi_hold(exi);
-	ASSERT3P(exi->exi_zone, ==, curzone);
+	ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
 
 	/*
 	 * Not allow lookup beyond root.
diff --git a/usr/src/uts/common/nfs/export.h b/usr/src/uts/common/nfs/export.h
index c68e5524ea..dd8df1a67c 100644
--- a/usr/src/uts/common/nfs/export.h
+++ b/usr/src/uts/common/nfs/export.h
@@ -472,6 +472,12 @@ typedef struct treenode {
 	struct exp_visible *tree_vis;
 } treenode_t;
 
+/*
+ * Now that we have links to chase, we can get the zone rootvp just from
+ * an export.  No current-zone-context needed.
+ */
+#define	EXI_TO_ZONEROOTVP(exi) ((exi)->exi_ne->exi_root->exi_vp)
+
 /*
  * TREE_ROOT checks if the node corresponds to a filesystem root or
  * the zone's root directory.
@@ -481,7 +487,7 @@ typedef struct treenode {
 #define	TREE_ROOT(t) \
 	((t)->tree_exi != NULL && \
 	(((t)->tree_exi->exi_vp->v_flag & VROOT) || \
-	VN_CMP((t)->tree_exi->exi_zone->zone_rootvp, (t)->tree_exi->exi_vp)))
+	VN_CMP(EXI_TO_ZONEROOTVP((t)->tree_exi), (t)->tree_exi->exi_vp)))
 
 #define	TREE_EXPORTED(t) \
 	((t)->tree_exi && !PSEUDO((t)->tree_exi))
@@ -523,6 +529,7 @@ struct exportinfo {
 	krwlock_t		exi_cache_lock;
 	kmutex_t		exi_lock;
 	uint_t			exi_count;
+	zoneid_t		exi_zoneid;
 	vnode_t			*exi_vp;
 	vnode_t			*exi_dvp;
 	avl_tree_t		*exi_cache[AUTH_TABLESIZE];
@@ -534,26 +541,18 @@ struct exportinfo {
 	int			exi_id;
 	avl_node_t		exi_id_link;
 	/*
-	 * Soft-reference/backpointer to the zone.  The ZSD callbacks we have
-	 * invoke cleanup code that crosses into OTHER cleanup functions that
-	 * may assume same-zone context and attempt to find their own ZSD,
-	 * using "curzone" when in fact "curzone" is global when called from
-	 * NFS's ZSD cleanup (see lm_unexport->nlm_unexport for an example).
-	 *
-	 * During ZSD shutdown or destroy callbacks, the zone structure
-	 * does not have its mutex held, and it has just-enough references
-	 * to not free from underneath us.  This field is not a proper
-	 * referenced-held zone pointer, and only ZSD callbacks should use
-	 * it.
+	 * Soft-reference/backpointer to zone's nfs_export_t.
+	 * This allows us access to the zone's rootvp (stored in
+	 * exi_ne->exi_root->exi_vp) even if the current thread isn't in
+	 * same-zone context.
 	 */
-	struct zone		*exi_zone;
+	struct nfs_export	*exi_ne;
 #ifdef VOLATILE_FH_TEST
 	uint32_t		exi_volatile_id;
 	struct ex_vol_rename	*exi_vol_rename;
 	kmutex_t		exi_vol_rename_lock;
 #endif /* VOLATILE_FH_TEST -- keep last! */
 };
-#define	exi_zoneid exi_zone->zone_id
 
 typedef struct exportinfo exportinfo_t;
 typedef struct exportdata exportdata_t;
@@ -675,7 +674,8 @@ typedef struct nfs_export {
 	krwlock_t exported_lock;
 
 	/* "public" and default (root) location for public filehandle */
-	struct exportinfo *exi_public, *exi_root;
+	struct exportinfo *exi_public;
+	struct exportinfo *exi_root;
 	/* For checking default public file handle */
 	fid_t exi_rootfid;
 	/* For comparing V2 filehandles */
-- 
2.21.0 (Apple Git-122)

