From dce6443de2e4e6179ae8ac79fedf0131c6af71e6 Mon Sep 17 00:00:00 2001
From: Vitaliy Gusev <gusev.vitaliy@gmail.com>
Date: Thu, 9 Jan 2020 10:15:59 +0300
Subject: [PATCH] nfssrv: nfsstat reports zeroed data in zone

---
 usr/src/uts/common/fs/nfs/nfs3_srv.c      |   3 +-
 usr/src/uts/common/fs/nfs/nfs4_srv.c      |   9 +-
 usr/src/uts/common/fs/nfs/nfs4_srv_attr.c |   8 +-
 usr/src/uts/common/fs/nfs/nfs_server.c    |  31 +--
 usr/src/uts/common/fs/nfs/nfs_srv.c       |   4 +-
 usr/src/uts/common/fs/nfs/nfs_stats.c     | 250 +++++-----------------
 usr/src/uts/common/nfs/nfs.h              |  15 +-
 usr/src/uts/common/nfs/nfs4.h             |   1 -
 usr/src/uts/common/nfs/nfs_acl.h          |   2 -
 usr/src/uts/common/nfs/nfs_dispatch.h     |   1 -
 10 files changed, 103 insertions(+), 221 deletions(-)

diff --git a/usr/src/uts/common/fs/nfs/nfs3_srv.c b/usr/src/uts/common/fs/nfs/nfs3_srv.c
index 400d4b80d3..d976300b58 100644
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c
@@ -843,10 +843,11 @@ rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
 	if (is_referral) {
 		char *s;
 		size_t strsz;
+		kstat_named_t *stat = exi->exi_ne->ne_globals->svstat[NFS_V3];
 
 		/* Get an artificial symlink based on a referral */
 		s = build_symlink(vp, cr, &strsz);
-		global_svstat_ptr[3][NFS_REFERLINKS].value.ui64++;
+		stat[NFS_REFERLINKS].value.ui64++;
 		DTRACE_PROBE2(nfs3serv__func__referral__reflink,
 		    vnode_t *, vp, char *, s);
 		if (s == NULL)
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv.c b/usr/src/uts/common/fs/nfs/nfs4_srv.c
index 7a8aa00943..689e167a49 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c
@@ -3813,10 +3813,12 @@ rfs4_op_readlink(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
 	if (is_referral) {
 		char *s;
 		size_t strsz;
+		kstat_named_t *stat =
+		    cs->exi->exi_ne->ne_globals->svstat[NFS_V4];
 
 		/* Get an artificial symlink based on a referral */
 		s = build_symlink(vp, cs->cr, &strsz);
-		global_svstat_ptr[4][NFS_REFERLINKS].value.ui64++;
+		stat[NFS_REFERLINKS].value.ui64++;
 		DTRACE_PROBE2(nfs4serv__func__referral__reflink,
 		    vnode_t *, vp, char *, s);
 		if (s == NULL)
@@ -5892,6 +5894,7 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi,
 		nfs_argop4 *argop;
 		nfs_resop4 *resop;
 		uint_t op;
+		kstat_named_t *stat = ne->ne_globals->rfsproccnt[NFS_V4];
 
 		argop = &args->array[i];
 		resop = &resp->array[i];
@@ -5903,7 +5906,7 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi,
 			 * Count the individual ops here; NULL and COMPOUND
 			 * are counted in common_dispatch()
 			 */
-			rfsproccnt_v4_ptr[op].value.ui64++;
+			stat[op].value.ui64++;
 
 			NFS4_DEBUG(rfs4_debug > 1,
 			    (CE_NOTE, "Executing %s", rfs4_op_string[op]));
@@ -5920,7 +5923,7 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi,
 			 * day when XDR code doesn't verify v4 opcodes.
 			 */
 			op = OP_ILLEGAL;
-			rfsproccnt_v4_ptr[OP_ILLEGAL_IDX].value.ui64++;
+			stat[OP_ILLEGAL_IDX].value.ui64++;
 
 			rfs4_op_illegal(argop, resop, req, &cs);
 			cs.cont = FALSE;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
index 242e2ab102..a9ee217a8b 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
@@ -1609,6 +1609,10 @@ rfs4_fattr4_fs_locations(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
 		break;  /* this attr is supported */
 
 	case NFS4ATTR_GETIT:
+	{
+		kstat_named_t *stat =
+		    sarg->cs->exi->exi_ne->ne_globals->svstat[NFS_V4];
+
 		fsl = fetch_referral(sarg->cs->vp, sarg->cs->cr);
 		if (fsl == NULL)
 			(void) memset(&(na->fs_locations), 0,
@@ -1617,9 +1621,9 @@ rfs4_fattr4_fs_locations(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
 			na->fs_locations = *fsl;
 			kmem_free(fsl, sizeof (fs_locations4));
 		}
-		global_svstat_ptr[4][NFS_REFERRALS].value.ui64++;
+		stat[NFS_REFERRALS].value.ui64++;
 		break;
-
+	}
 	case NFS4ATTR_FREEIT:
 		if (sarg->op == NFS4ATTR_SETIT || sarg->op == NFS4ATTR_VERIT)
 			error = EINVAL;
diff --git a/usr/src/uts/common/fs/nfs/nfs_server.c b/usr/src/uts/common/fs/nfs/nfs_server.c
index 5d3e8b3ed8..9f5c118163 100644
--- a/usr/src/uts/common/fs/nfs/nfs_server.c
+++ b/usr/src/uts/common/fs/nfs/nfs_server.c
@@ -195,9 +195,6 @@ static void	rfs4_server_start(nfs_globals_t *, int);
 static void	nullfree(void);
 static void	rfs_dispatch(struct svc_req *, SVCXPRT *);
 static void	acl_dispatch(struct svc_req *, SVCXPRT *);
-static void	common_dispatch(struct svc_req *, SVCXPRT *,
-		rpcvers_t, rpcvers_t, char *,
-		struct rpc_disptable *);
 static	int	checkauth(struct exportinfo *, struct svc_req *, cred_t *, int,
 		bool_t, bool_t *);
 static char	*client_name(struct svc_req *req);
@@ -1334,13 +1331,13 @@ union rfs_res {
 static struct rpc_disptable rfs_disptable[] = {
 	{sizeof (rfsdisptab_v2) / sizeof (rfsdisptab_v2[0]),
 	    rfscallnames_v2,
-	    &rfsproccnt_v2_ptr, rfsdisptab_v2},
+	    rfsdisptab_v2},
 	{sizeof (rfsdisptab_v3) / sizeof (rfsdisptab_v3[0]),
 	    rfscallnames_v3,
-	    &rfsproccnt_v3_ptr, rfsdisptab_v3},
+	    rfsdisptab_v3},
 	{sizeof (rfsdisptab_v4) / sizeof (rfsdisptab_v4[0]),
 	    rfscallnames_v4,
-	    &rfsproccnt_v4_ptr, rfsdisptab_v4},
+	    rfsdisptab_v4},
 };
 
 /*
@@ -1462,7 +1459,6 @@ auth_tooweak(struct svc_req *req, char *res)
 	return (FALSE);
 }
 
-
 static void
 common_dispatch(struct svc_req *req, SVCXPRT *xprt, rpcvers_t min_vers,
     rpcvers_t max_vers, char *pgmname, struct rpc_disptable *disptable)
@@ -1499,9 +1495,17 @@ common_dispatch(struct svc_req *req, SVCXPRT *xprt, rpcvers_t min_vers,
 	char cbuf[INET6_ADDRSTRLEN];	/* to hold both IPv4 and IPv6 addr */
 	bool_t ro = FALSE;
 	nfs_export_t *ne = nfs_get_export();
+	nfs_globals_t *ng = ne->ne_globals;
+	kstat_named_t *svstat, *procstat;
+
+	ASSERT(req->rq_prog == NFS_PROGRAM || req->rq_prog == NFS_ACL_PROGRAM);
 
 	vers = req->rq_vers;
 
+	svstat = ng->svstat[req->rq_vers];
+	procstat = (req->rq_prog == NFS_PROGRAM) ?
+	    ng->rfsproccnt[vers] : ng->aclproccnt[vers];
+
 	if (vers < min_vers || vers > max_vers) {
 		svcerr_progvers(req->rq_xprt, min_vers, max_vers);
 		error++;
@@ -1517,7 +1521,7 @@ common_dispatch(struct svc_req *req, SVCXPRT *xprt, rpcvers_t min_vers,
 		goto done;
 	}
 
-	(*(disptable[(int)vers].dis_proccntp))[which].value.ui64++;
+	procstat[which].value.ui64++;
 
 	disp = &disptable[(int)vers].dis_table[which];
 	procnames = disptable[(int)vers].dis_procnames;
@@ -1839,9 +1843,8 @@ done:
 	if (exi != NULL)
 		exi_rele(exi);
 
-	global_svstat_ptr[req->rq_vers][NFS_BADCALLS].value.ui64 += error;
-
-	global_svstat_ptr[req->rq_vers][NFS_CALLS].value.ui64++;
+	svstat[NFS_BADCALLS].value.ui64 += error;
+	svstat[NFS_CALLS].value.ui64++;
 }
 
 static void
@@ -1964,10 +1967,10 @@ static struct rpcdisp acldisptab_v3[] = {
 static struct rpc_disptable acl_disptable[] = {
 	{sizeof (acldisptab_v2) / sizeof (acldisptab_v2[0]),
 		aclcallnames_v2,
-		&aclproccnt_v2_ptr, acldisptab_v2},
+		acldisptab_v2},
 	{sizeof (acldisptab_v3) / sizeof (acldisptab_v3[0]),
 		aclcallnames_v3,
-		&aclproccnt_v3_ptr, acldisptab_v3},
+		acldisptab_v3},
 };
 
 static void
@@ -2649,6 +2652,7 @@ nfs_server_zone_init(zoneid_t zoneid)
 	 * export init must precede srv init calls.
 	 */
 	nfs_export_zone_init(ng);
+	rfs_stat_zone_init(ng);
 	rfs_srv_zone_init(ng);
 	rfs3_srv_zone_init(ng);
 	rfs4_srv_zone_init(ng);
@@ -2697,6 +2701,7 @@ nfs_server_zone_fini(zoneid_t zoneid, void *data)
 	rfs4_srv_zone_fini(ng);
 	rfs3_srv_zone_fini(ng);
 	rfs_srv_zone_fini(ng);
+	rfs_stat_zone_fini(ng);
 	nfs_export_zone_fini(ng);
 
 	mutex_destroy(&ng->nfs_server_upordown_lock);
diff --git a/usr/src/uts/common/fs/nfs/nfs_srv.c b/usr/src/uts/common/fs/nfs/nfs_srv.c
index 0c996612a3..ae51f4ab53 100644
--- a/usr/src/uts/common/fs/nfs/nfs_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs_srv.c
@@ -670,10 +670,12 @@ rfs_readlink(fhandle_t *fhp, struct nfsrdlnres *rl, struct exportinfo *exi,
 	if (is_referral) {
 		char *s;
 		size_t strsz;
+		kstat_named_t *stat =
+		    exi->exi_ne->ne_globals->svstat[NFS_VERSION];
 
 		/* Get an artificial symlink based on a referral */
 		s = build_symlink(vp, cr, &strsz);
-		global_svstat_ptr[2][NFS_REFERLINKS].value.ui64++;
+		stat[NFS_REFERLINKS].value.ui64++;
 		DTRACE_PROBE2(nfs2serv__func__referral__reflink,
 		    vnode_t *, vp, char *, s);
 		if (s == NULL)
diff --git a/usr/src/uts/common/fs/nfs/nfs_stats.c b/usr/src/uts/common/fs/nfs/nfs_stats.c
index baaf47a82a..97f820d756 100644
--- a/usr/src/uts/common/fs/nfs/nfs_stats.c
+++ b/usr/src/uts/common/fs/nfs/nfs_stats.c
@@ -45,8 +45,8 @@ zone_key_t nfsstat_zone_key;
  */
 static kstat_named_t *
 nfsstat_zone_init_common(zoneid_t zoneid, const char *module, int vers,
-			    const char *name, const kstat_named_t *template,
-			    size_t template_size)
+    const char *name, const kstat_named_t *template,
+    size_t template_size)
 {
 	kstat_t *ksp;
 	kstat_named_t *ks_data;
@@ -68,7 +68,7 @@ nfsstat_zone_init_common(zoneid_t zoneid, const char *module, int vers,
  */
 static void
 nfsstat_zone_fini_common(zoneid_t zoneid, const char *module, int vers,
-			    const char *name)
+    const char *name)
 {
 	kstat_delete_byname_zone(module, vers, name, zoneid);
 }
@@ -89,38 +89,22 @@ static const kstat_named_t svstat_tmpl[] = {
 	{ "referlinks",	KSTAT_DATA_UINT64 },
 };
 
-/* Points to the global zone server kstat data for all nfs versions */
-kstat_named_t *global_svstat_ptr[NFS_VERSMAX + 1];
-
 static void
 nfsstat_zone_init_server(zoneid_t zoneid, kstat_named_t *svstatp[])
 {
 	int vers;
 
-	/*
-	 * first two indexes of these arrays are not used, so initialize
-	 * to NULL
-	 */
-	svstatp[0] = NULL;
-	svstatp[1] = NULL;
-	global_svstat_ptr[0] = NULL;
-	global_svstat_ptr[0] = NULL;
-
 	for (vers = NFS_VERSION; vers <= NFS_V4; vers++) {
 		svstatp[vers] = nfsstat_zone_init_common(zoneid, "nfs", vers,
 		    "nfs_server", svstat_tmpl, sizeof (svstat_tmpl));
-		if (zoneid == GLOBAL_ZONEID)
-			global_svstat_ptr[vers] = svstatp[vers];
 	}
 }
 
 static void
-nfsstat_zone_fini_server(zoneid_t zoneid, kstat_named_t **svstatp)
+nfsstat_zone_fini_server(zoneid_t zoneid, kstat_named_t *svstatp[])
 {
 	int vers;
 	for (vers = NFS_VERSION; vers <= NFS_V4; vers++) {
-		if (zoneid == GLOBAL_ZONEID)
-			global_svstat_ptr[vers] = NULL;
 		nfsstat_zone_fini_common(zoneid, "nfs", vers, "nfs_server");
 		kmem_free(svstatp[vers], sizeof (svstat_tmpl));
 	}
@@ -188,29 +172,6 @@ static const kstat_named_t rfsproccnt_v2_tmpl[] = {
 	{ "statfs",	KSTAT_DATA_UINT64 }
 };
 
-kstat_named_t *rfsproccnt_v2_ptr;
-
-static void
-nfsstat_zone_init_rfsproc_v2(zoneid_t zoneid, struct nfs_version_stats *statsp)
-{
-	kstat_named_t *ks_data;
-
-	ks_data = nfsstat_zone_init_common(zoneid, "nfs", 0, "rfsproccnt_v2",
-	    rfsproccnt_v2_tmpl, sizeof (rfsproccnt_v2_tmpl));
-	statsp->rfsproccnt_ptr = ks_data;
-	if (zoneid == GLOBAL_ZONEID)
-		rfsproccnt_v2_ptr = ks_data;
-}
-
-static void
-nfsstat_zone_fini_rfsproc_v2(zoneid_t zoneid, struct nfs_version_stats *statsp)
-{
-	if (zoneid == GLOBAL_ZONEID)
-		rfsproccnt_v2_ptr = NULL;
-	nfsstat_zone_fini_common(zoneid, "nfs", 0, "rfsproccnt_v2");
-	kmem_free(statsp->rfsproccnt_ptr, sizeof (rfsproccnt_v2_tmpl));
-}
-
 /*
  * NFSv2 client ACL stats
  */
@@ -249,30 +210,6 @@ static const kstat_named_t aclproccnt_v2_tmpl[] = {
 	{ "getxattrdir",	KSTAT_DATA_UINT64 }
 };
 
-kstat_named_t *aclproccnt_v2_ptr;
-
-static void
-nfsstat_zone_init_aclproc_v2(zoneid_t zoneid, struct nfs_version_stats *statsp)
-{
-	kstat_named_t *ks_data;
-
-	ks_data = nfsstat_zone_init_common(zoneid, "nfs_acl", 0,
-	    "aclproccnt_v2", aclproccnt_v2_tmpl,
-	    sizeof (aclproccnt_v2_tmpl));
-	statsp->aclproccnt_ptr = ks_data;
-	if (zoneid == GLOBAL_ZONEID)
-		aclproccnt_v2_ptr = ks_data;
-}
-
-static void
-nfsstat_zone_fini_aclproc_v2(zoneid_t zoneid, struct nfs_version_stats *statsp)
-{
-	if (zoneid == GLOBAL_ZONEID)
-		aclproccnt_v2_ptr = NULL;
-	nfsstat_zone_fini_common(zoneid, "nfs_acl", 0, "aclproccnt_v2");
-	kmem_free(statsp->aclproccnt_ptr, sizeof (aclproccnt_v2_tmpl));
-}
-
 /*
  * NFSv3 client stats
  */
@@ -343,29 +280,6 @@ static const kstat_named_t rfsproccnt_v3_tmpl[] = {
 	{ "commit",	KSTAT_DATA_UINT64 }
 };
 
-kstat_named_t *rfsproccnt_v3_ptr;
-
-static void
-nfsstat_zone_init_rfsproc_v3(zoneid_t zoneid, struct nfs_version_stats *statsp)
-{
-	kstat_named_t *ks_data;
-
-	ks_data = nfsstat_zone_init_common(zoneid, "nfs", 0, "rfsproccnt_v3",
-	    rfsproccnt_v3_tmpl, sizeof (rfsproccnt_v3_tmpl));
-	statsp->rfsproccnt_ptr = ks_data;
-	if (zoneid == GLOBAL_ZONEID)
-		rfsproccnt_v3_ptr = ks_data;
-}
-
-static void
-nfsstat_zone_fini_rfsproc_v3(zoneid_t zoneid, struct nfs_version_stats *statsp)
-{
-	if (zoneid == GLOBAL_ZONEID)
-		rfsproccnt_v3_ptr = NULL;
-	nfsstat_zone_fini_common(zoneid, "nfs", 0, "rfsproccnt_v3");
-	kmem_free(statsp->rfsproccnt_ptr, sizeof (rfsproccnt_v3_tmpl));
-}
-
 /*
  * NFSv3 client ACL stats
  */
@@ -400,30 +314,6 @@ static const kstat_named_t aclproccnt_v3_tmpl[] = {
 	{ "getxattrdir",	KSTAT_DATA_UINT64 }
 };
 
-kstat_named_t *aclproccnt_v3_ptr;
-
-static void
-nfsstat_zone_init_aclproc_v3(zoneid_t zoneid, struct nfs_version_stats *statsp)
-{
-	kstat_named_t *ks_data;
-
-	ks_data = nfsstat_zone_init_common(zoneid, "nfs_acl", 0,
-	    "aclproccnt_v3", aclproccnt_v3_tmpl,
-	    sizeof (aclproccnt_v3_tmpl));
-	statsp->aclproccnt_ptr = ks_data;
-	if (zoneid == GLOBAL_ZONEID)
-		aclproccnt_v3_ptr = ks_data;
-}
-
-static void
-nfsstat_zone_fini_aclproc_v3(zoneid_t zoneid, struct nfs_version_stats *statsp)
-{
-	if (zoneid == GLOBAL_ZONEID)
-		aclproccnt_v3_ptr = NULL;
-	nfsstat_zone_fini_common(zoneid, "nfs_acl", 0, "aclproccnt_v3");
-	kmem_free(statsp->aclproccnt_ptr, sizeof (aclproccnt_v3_tmpl));
-}
-
 /*
  * NFSv4 client stats
  */
@@ -530,29 +420,6 @@ static const kstat_named_t rfsproccnt_v4_tmpl[] = {
 	{ "illegal",	KSTAT_DATA_UINT64 },
 };
 
-kstat_named_t *rfsproccnt_v4_ptr;
-
-static void
-nfsstat_zone_init_rfsproc_v4(zoneid_t zoneid, struct nfs_version_stats *statsp)
-{
-	kstat_named_t *ks_data;
-
-	ks_data = nfsstat_zone_init_common(zoneid, "nfs", 0, "rfsproccnt_v4",
-	    rfsproccnt_v4_tmpl, sizeof (rfsproccnt_v4_tmpl));
-	statsp->rfsproccnt_ptr = ks_data;
-	if (zoneid == GLOBAL_ZONEID)
-		rfsproccnt_v4_ptr = ks_data;
-}
-
-static void
-nfsstat_zone_fini_rfsproc_v4(zoneid_t zoneid, struct nfs_version_stats *statsp)
-{
-	if (zoneid == GLOBAL_ZONEID)
-		rfsproccnt_v4_ptr = NULL;
-	nfsstat_zone_fini_common(zoneid, "nfs", 0, "rfsproccnt_v4");
-	kmem_free(statsp->rfsproccnt_ptr, sizeof (rfsproccnt_v4_tmpl));
-}
-
 /*
  * NFSv4 client ACL stats
  */
@@ -576,39 +443,6 @@ nfsstat_zone_fini_aclreq_v4(zoneid_t zoneid, struct nfs_version_stats *statsp)
 	kmem_free(statsp->aclreqcnt_ptr, sizeof (aclreqcnt_v4_tmpl));
 }
 
-/*
- * NFSv4 server ACL stats
- */
-static const kstat_named_t aclproccnt_v4_tmpl[] = {
-	{ "null",	KSTAT_DATA_UINT64 },
-	{ "getacl",	KSTAT_DATA_UINT64 },
-	{ "setacl",	KSTAT_DATA_UINT64 }
-};
-
-kstat_named_t *aclproccnt_v4_ptr;
-
-static void
-nfsstat_zone_init_aclproc_v4(zoneid_t zoneid, struct nfs_version_stats *statsp)
-{
-	kstat_named_t *ks_data;
-
-	ks_data = nfsstat_zone_init_common(zoneid, "nfs_acl", 0,
-	    "aclproccnt_v4", aclproccnt_v4_tmpl,
-	    sizeof (aclproccnt_v4_tmpl));
-	statsp->aclproccnt_ptr = ks_data;
-	if (zoneid == GLOBAL_ZONEID)
-		aclproccnt_v4_ptr = ks_data;
-}
-
-static void
-nfsstat_zone_fini_aclproc_v4(zoneid_t zoneid, struct nfs_version_stats *statsp)
-{
-	if (zoneid == GLOBAL_ZONEID)
-		aclproccnt_v4_ptr = NULL;
-	nfsstat_zone_fini_common(zoneid, "nfs_acl", 0, "aclproccnt_v4");
-	kmem_free(statsp->aclproccnt_ptr, sizeof (aclproccnt_v4_tmpl));
-}
-
 /*
  * Zone initializer callback to setup the kstats.
  */
@@ -619,32 +453,21 @@ nfsstat_zone_init(zoneid_t zoneid)
 
 	nfs_stats_ptr = kmem_zalloc(sizeof (*nfs_stats_ptr), KM_SLEEP);
 
-	/*
-	 * Initialize all versions of the nfs_server
-	 */
-	nfsstat_zone_init_server(zoneid, nfs_stats_ptr->nfs_stats_svstat_ptr);
-
 	/*
 	 * Initialize v2 stats
 	 */
 	nfsstat_zone_init_rfsreq_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
-	nfsstat_zone_init_rfsproc_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
 	nfsstat_zone_init_aclreq_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
-	nfsstat_zone_init_aclproc_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
 	/*
 	 * Initialize v3 stats
 	 */
 	nfsstat_zone_init_rfsreq_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
-	nfsstat_zone_init_rfsproc_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
 	nfsstat_zone_init_aclreq_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
-	nfsstat_zone_init_aclproc_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
 	/*
 	 * Initialize v4 stats
 	 */
 	nfsstat_zone_init_rfsreq_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
-	nfsstat_zone_init_rfsproc_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
 	nfsstat_zone_init_aclreq_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
-	nfsstat_zone_init_aclproc_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
 
 	return (nfs_stats_ptr);
 }
@@ -657,32 +480,75 @@ nfsstat_zone_fini(zoneid_t zoneid, void *data)
 {
 	struct nfs_stats *nfs_stats_ptr = data;
 
-	/*
-	 * Free nfs:0:nfs_server stats
-	 */
-	nfsstat_zone_fini_server(zoneid, nfs_stats_ptr->nfs_stats_svstat_ptr);
-
 	/*
 	 * Free v2 stats
 	 */
 	nfsstat_zone_fini_rfsreq_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
-	nfsstat_zone_fini_rfsproc_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
 	nfsstat_zone_fini_aclreq_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
-	nfsstat_zone_fini_aclproc_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
 	/*
 	 * Free v3 stats
 	 */
 	nfsstat_zone_fini_rfsreq_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
-	nfsstat_zone_fini_rfsproc_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
 	nfsstat_zone_fini_aclreq_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
-	nfsstat_zone_fini_aclproc_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
 	/*
 	 * Free v4 stats
 	 */
 	nfsstat_zone_fini_rfsreq_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
-	nfsstat_zone_fini_rfsproc_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
 	nfsstat_zone_fini_aclreq_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
-	nfsstat_zone_fini_aclproc_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
 
 	kmem_free(nfs_stats_ptr, sizeof (*nfs_stats_ptr));
 }
+
+void
+rfs_stat_zone_init(nfs_globals_t *ng)
+{
+	zoneid_t zoneid = ng->nfs_zoneid;
+
+	/* Initialize all versions of the nfs_server */
+	nfsstat_zone_init_server(zoneid, ng->svstat);
+
+	/* NFS proc */
+	ng->rfsproccnt[NFS_V2] = nfsstat_zone_init_common(zoneid, "nfs", 0,
+	    "rfsproccnt_v2", rfsproccnt_v2_tmpl, sizeof (rfsproccnt_v2_tmpl));
+
+	ng->rfsproccnt[NFS_V3] = nfsstat_zone_init_common(zoneid, "nfs", 0,
+	    "rfsproccnt_v3", rfsproccnt_v3_tmpl, sizeof (rfsproccnt_v3_tmpl));
+
+	ng->rfsproccnt[NFS_V4] = nfsstat_zone_init_common(zoneid, "nfs", 0,
+	    "rfsproccnt_v4", rfsproccnt_v4_tmpl, sizeof (rfsproccnt_v4_tmpl));
+
+	/* ACL proc */
+	ng->aclproccnt[NFS_V2] = nfsstat_zone_init_common(zoneid, "nfs_acl", 0,
+	    "aclproccnt_v2", aclproccnt_v2_tmpl, sizeof (aclproccnt_v2_tmpl));
+
+	ng->aclproccnt[NFS_V3] = nfsstat_zone_init_common(zoneid, "nfs_acl", 0,
+	    "aclproccnt_v3", aclproccnt_v3_tmpl, sizeof (aclproccnt_v3_tmpl));
+
+}
+
+void
+rfs_stat_zone_fini(nfs_globals_t *ng)
+{
+	zoneid_t zoneid = ng->nfs_zoneid;
+
+	/* Free nfs:x:nfs_server stats */
+	nfsstat_zone_fini_server(zoneid, ng->svstat);
+
+	/* NFS */
+	nfsstat_zone_fini_common(zoneid, "nfs", 0, "rfsproccnt_v2");
+	kmem_free(ng->rfsproccnt[NFS_V2], sizeof (rfsproccnt_v2_tmpl));
+
+	nfsstat_zone_fini_common(zoneid, "nfs", 0, "rfsproccnt_v3");
+	kmem_free(ng->rfsproccnt[NFS_V3], sizeof (rfsproccnt_v3_tmpl));
+
+	nfsstat_zone_fini_common(zoneid, "nfs", 0, "rfsproccnt_v4");
+	kmem_free(ng->rfsproccnt[NFS_V4], sizeof (rfsproccnt_v4_tmpl));
+
+	/* ACL */
+	nfsstat_zone_fini_common(zoneid, "nfs_acl", 0, "aclproccnt_v2");
+	kmem_free(ng->aclproccnt[NFS_V2], sizeof (aclproccnt_v2_tmpl));
+
+	nfsstat_zone_fini_common(zoneid, "nfs_acl", 0, "aclproccnt_v3");
+	kmem_free(ng->aclproccnt[NFS_V3], sizeof (aclproccnt_v3_tmpl));
+
+}
diff --git a/usr/src/uts/common/nfs/nfs.h b/usr/src/uts/common/nfs/nfs.h
index c705aee47c..6f76fc93ea 100644
--- a/usr/src/uts/common/nfs/nfs.h
+++ b/usr/src/uts/common/nfs/nfs.h
@@ -117,6 +117,11 @@ typedef struct nfs_globals {
 	struct nfs3_srv		*nfs3_srv;	/* nfs3_srv.c */
 	struct nfs4_srv		*nfs4_srv;	/* nfs4_srv.c */
 	struct nfsauth_globals	*nfs_auth;	/* nfs_auth.c */
+
+	/* statistic: nfs_stat.c, etc. */
+	kstat_named_t		*svstat[NFS_VERSMAX + 1];
+	kstat_named_t		*rfsproccnt[NFS_VERSMAX + 1];
+	kstat_named_t		*aclproccnt[NFS_VERSMAX + 1];
 } nfs_globals_t;
 
 /*
@@ -930,6 +935,8 @@ extern void	rfs_srv_zone_fini(nfs_globals_t *);
 /* index for svstat_ptr */
 enum nfs_svccounts {NFS_CALLS, NFS_BADCALLS, NFS_REFERRALS, NFS_REFERLINKS};
 
+#define	NFS_V2	NFS_VERSION
+
 /*	function defs for NFS kernel */
 extern int	nfs_waitfor_purge_complete(vnode_t *);
 extern int	nfs_validate_caches(vnode_t *, cred_t *);
@@ -1013,7 +1020,6 @@ extern krwlock_t	nfssrv_globals_rwl;
 
 extern krwlock_t	rroklock;
 extern vtype_t		nf_to_vt[];
-extern kstat_named_t	*rfsproccnt_v2_ptr;
 extern kmutex_t		nfs_minor_lock;
 extern int		nfs_major;
 extern int		nfs_minor;
@@ -1029,16 +1035,13 @@ extern int		(*nfs_srv_dss_func)(char *, size_t);
  */
 struct nfs_version_stats {
 	kstat_named_t	*aclreqcnt_ptr;		/* nfs_acl:0:aclreqcnt_v? */
-	kstat_named_t	*aclproccnt_ptr;	/* nfs_acl:0:aclproccnt_v? */
 	kstat_named_t	*rfsreqcnt_ptr;		/* nfs:0:rfsreqcnt_v? */
-	kstat_named_t	*rfsproccnt_ptr;	/* nfs:0:rfsproccnt_v? */
 };
 
 /*
  * A bit of asymmetry: nfs:0:nfs_client isn't part of this structure.
  */
 struct nfs_stats {
-	kstat_named_t		*nfs_stats_svstat_ptr[NFS_VERSMAX + 1];
 	struct nfs_version_stats	nfs_stats_v2;
 	struct nfs_version_stats	nfs_stats_v3;
 	struct nfs_version_stats	nfs_stats_v4;
@@ -1055,6 +1058,9 @@ extern zone_key_t nfsstat_zone_key;
 extern void	*nfsstat_zone_init(zoneid_t);
 extern void	nfsstat_zone_fini(zoneid_t, void *);
 
+extern void rfs_stat_zone_init(nfs_globals_t *);
+extern void rfs_stat_zone_fini(nfs_globals_t *);
+
 #endif	/* _KERNEL */
 
 /*
@@ -2338,7 +2344,6 @@ 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;
 extern vfsops_t		*nfs3_vfsops;
 extern struct vnodeops	*nfs3_vnodeops;
 extern const struct fs_operation_def nfs3_vnodeops_template[];
diff --git a/usr/src/uts/common/nfs/nfs4.h b/usr/src/uts/common/nfs/nfs4.h
index ce21ce999b..39178138e8 100644
--- a/usr/src/uts/common/nfs/nfs4.h
+++ b/usr/src/uts/common/nfs/nfs4.h
@@ -1456,7 +1456,6 @@ extern vtype_t	nf4_to_vt[];
 extern struct nfs4_ntov_map nfs4_ntov_map[];
 extern uint_t nfs4_ntov_map_size;
 
-extern kstat_named_t	*rfsproccnt_v4_ptr;
 extern struct vfsops	*nfs4_vfsops;
 extern struct vnodeops	*nfs4_vnodeops;
 extern const struct	fs_operation_def nfs4_vnodeops_template[];
diff --git a/usr/src/uts/common/nfs/nfs_acl.h b/usr/src/uts/common/nfs/nfs_acl.h
index a9dd2e3635..f3ab476467 100644
--- a/usr/src/uts/common/nfs/nfs_acl.h
+++ b/usr/src/uts/common/nfs/nfs_acl.h
@@ -379,8 +379,6 @@ extern void nfs_acl_free(vsecattr_t *);
 
 #ifdef _KERNEL
 /* server and client data structures */
-extern kstat_named_t	*aclproccnt_v2_ptr;
-extern kstat_named_t	*aclproccnt_v3_ptr;
 
 extern char		*aclnames_v2[];
 extern uchar_t		acl_call_type_v2[];
diff --git a/usr/src/uts/common/nfs/nfs_dispatch.h b/usr/src/uts/common/nfs/nfs_dispatch.h
index 16475fea47..d1757fdb28 100644
--- a/usr/src/uts/common/nfs/nfs_dispatch.h
+++ b/usr/src/uts/common/nfs/nfs_dispatch.h
@@ -73,7 +73,6 @@ typedef struct rpcdisp {
 typedef struct rpc_disptable {
 	int dis_nprocs;
 	char **dis_procnames;
-	kstat_named_t **dis_proccntp;
 	struct rpcdisp *dis_table;
 } rpc_disptable_t;
 
-- 
2.23.0

