From 9cd6258dd9174e5dcae3e4e5b3f784497c366e02 Mon Sep 17 00:00:00 2001
From: Dan McDonald <danmcd@joyent.com>
Date: Tue, 1 Oct 2019 16:03:14 -0400
Subject: [PATCH 27/30] Plug memory leaks:

Plug sharefs zone-shutdown leaks
Go ahead and destroy the NFSv4 database tables
Do rfs4_ss_fini() BEFORE rfs4_servinst_destroy_all().
dss_paths[] entries need cleanup too
NFS Auth per-zone needs better cleanup
---
 usr/src/uts/common/fs/nfs/nfs4_srv.c     | 22 +++++++++++++++++++---
 usr/src/uts/common/fs/nfs/nfs4_state.c   | 21 ++++++++++++++-------
 usr/src/uts/common/fs/nfs/nfs_auth.c     |  3 +++
 usr/src/uts/common/fs/sharefs/sharetab.c | 22 ++++++++++++++++++++++
 4 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv.c b/usr/src/uts/common/fs/nfs/nfs4_srv.c
index 9d8554566a..446f9fc070 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c
@@ -818,8 +818,8 @@ rfs4_servinst_create(nfs4_srv_t *nsrv4, int start_grace,
 	    sizeof (rfs4_dss_path_t *), KM_SLEEP);
 
 	for (i = 0; i < dss_npaths; i++) {
-		/* CSTYLED */
-		sip->dss_paths[i] = rfs4_dss_newpath(nsrv4, sip, dss_paths[i], i);
+		sip->dss_paths[i] =
+		    rfs4_dss_newpath(nsrv4, sip, dss_paths[i], i);
 	}
 
 	mutex_enter(&nsrv4->servinst_lock);
@@ -857,9 +857,25 @@ rfs4_servinst_destroy_all(nfs4_srv_t *nsrv4)
 		rw_destroy(&sip->rwlock);
 		if (sip->oldstate)
 			kmem_free(sip->oldstate, sizeof (rfs4_oldstate_t));
-		if (sip->dss_paths)
+		if (sip->dss_paths) {
+			int i = sip->dss_npaths;
+
+			while (i > 0) {
+				i--;
+				if (sip->dss_paths[i] != NULL) {
+					char *path = sip->dss_paths[i]->path;
+
+					if (path != NULL) {
+						kmem_free(path,
+						    strlen(path) + 1);
+					}
+					kmem_free(sip->dss_paths[i],
+					    sizeof (rfs4_dss_path_t));
+				}
+			}
 			kmem_free(sip->dss_paths,
 			    sip->dss_npaths * sizeof (rfs4_dss_path_t *));
+		}
 		kmem_free(sip, sizeof (rfs4_servinst_t));
 #ifdef DEBUG
 		n++;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_state.c b/usr/src/uts/common/fs/nfs/nfs4_state.c
index 70241c48d8..727c043c63 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_state.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_state.c
@@ -1496,6 +1496,14 @@ rfs4_state_zone_fini()
 
 	rfs4_set_deleg_policy(nsrv4, SRV_NEVER_DELEGATE);
 
+	/*
+	 * Clean up any dangling stable storage structures BEFORE calling
+	 * rfs4_servinst_destroy_all() so there are no dangling structures
+	 * (i.e. the srvinsts are all cleared of danglers BEFORE they get
+	 * freed).
+	 */
+	rfs4_ss_fini(nsrv4);
+
 	mutex_enter(&nsrv4->state_lock);
 
 	if (nsrv4->nfs4_server_state == NULL) {
@@ -1517,12 +1525,14 @@ rfs4_state_zone_fini()
 	/* First stop all of the reaper threads in the database */
 	rfs4_database_shutdown(dbp);
 	/*
-	 * XXX workaround
-	 * Skip destrying the state database yet just in case there
-	 * are unfinished operations depending on it.
+	 * WARNING: There may be consumers of the rfs4 database still
+	 * active as we destroy these.  IF that's the case, consider putting
+	 * some of their _zone_fini()-like functions into the zsd key as
+	 * ~~SHUTDOWN~~ functions instead of ~~DESTROY~~ functions.  We can
+	 * maintain some ordering guarantees better that way.
 	 */
 	/* Now destroy/release the database tables */
-	/* rfs4_database_destroy(dbp); */
+	rfs4_database_destroy(dbp);
 
 	/* Reset the cache timers for next time */
 	nsrv4->rfs4_client_cache_time = 0;
@@ -1534,9 +1544,6 @@ rfs4_state_zone_fini()
 	nsrv4->rfs4_deleg_state_cache_time = 0;
 
 	mutex_exit(&nsrv4->state_lock);
-
-	/* clean up any dangling stable storage structures */
-	rfs4_ss_fini(nsrv4);
 }
 
 typedef union {
diff --git a/usr/src/uts/common/fs/nfs/nfs_auth.c b/usr/src/uts/common/fs/nfs/nfs_auth.c
index ad18836cf7..e62b9cd4e1 100644
--- a/usr/src/uts/common/fs/nfs/nfs_auth.c
+++ b/usr/src/uts/common/fs/nfs/nfs_auth.c
@@ -281,6 +281,9 @@ nfsauth_zone_fini(nfs_globals_t *ng)
 	cv_destroy(&nag->refreshq_cv);
 	mutex_destroy(&nag->refreshq_lock);
 	mutex_destroy(&nag->mountd_lock);
+	/* Extra cleanup. */
+	if (nag->mountd_dh != NULL)
+		door_ki_rele(nag->mountd_dh);
 	kmem_free(nag, sizeof (*nag));
 }
 
diff --git a/usr/src/uts/common/fs/sharefs/sharetab.c b/usr/src/uts/common/fs/sharefs/sharetab.c
index 7b8055e94b..0bb7d18488 100644
--- a/usr/src/uts/common/fs/sharefs/sharetab.c
+++ b/usr/src/uts/common/fs/sharefs/sharetab.c
@@ -25,6 +25,7 @@
 
 /*
  * Copyright 2018 Nexenta Systems, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #include <sys/types.h>
@@ -309,6 +310,27 @@ sharetab_zone_fini(zoneid_t zoneid, void *data)
 	rw_destroy(&sg->sharefs_lock);
 	rw_destroy(&sg->sharetab_lock);
 
+	/* ALL of the allocated things must be cleaned before we free sg. */
+	while (sg->sharefs_sharetab != NULL) {
+		int i;
+		sharetab_t *freeing = sg->sharefs_sharetab;
+
+		sg->sharefs_sharetab = freeing->s_next;
+		kmem_free(freeing->s_fstype, strlen(freeing->s_fstype) + 1);
+		for (i = 0; i < PKP_HASH_SIZE; i++) {
+			sharefs_hash_head_t *bucket;
+
+			bucket = &(freeing->s_buckets[i]);
+			while (bucket->ssh_sh != NULL) {
+				share_t *share = bucket->ssh_sh;
+
+				bucket->ssh_sh = share->sh_next;
+				sharefree(share, NULL);
+			}
+		}
+		kmem_free(freeing, sizeof (*freeing));
+	}
+
 	kmem_free(sg, sizeof (*sg));
 }
 
-- 
2.21.0

