--- old/usr/src/uts/common/os/netstack.c	Sun Nov  5 20:02:10 2017
+++ new/usr/src/uts/common/os/netstack.c	Sun Nov  5 20:02:10 2017
@@ -37,6 +37,7 @@
 #include <sys/mutex.h>
 #include <sys/bitmap.h>
 #include <sys/atomic.h>
+#include <sys/sunddi.h>
 #include <sys/kobj.h>
 #include <sys/disp.h>
 #include <vm/seg_kmem.h>
@@ -122,6 +123,10 @@
 static boolean_t wait_for_nms_inprogress(netstack_t *, nm_state_t *,
     kmutex_t *);
 
+static void netstack_hold_locked(netstack_t *);
+static void netstack_reap_work(netstack_t *, boolean_t);
+ksema_t netstack_reap_limiter;
+
 void
 netstack_init(void)
 {
@@ -128,6 +133,9 @@
 	mutex_init(&netstack_g_lock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&netstack_shared_lock, NULL, MUTEX_DEFAULT, NULL);
 
+	/* XXX KEBE SAYS hard-coded constant needs to be fixed. */
+	sema_init(&netstack_reap_limiter, 1024, NULL, SEMA_DRIVER, NULL);
+
 	netstack_initialized = 1;
 
 	/*
@@ -1030,8 +1038,8 @@
 		mutex_enter(&ns->netstack_lock);
 		if (ns->netstack_stackid == stackid &&
 		    !(ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))) {
+			netstack_hold_locked(ns);
 			mutex_exit(&ns->netstack_lock);
-			netstack_hold(ns);
 			mutex_exit(&netstack_g_lock);
 			return (ns);
 		}
@@ -1061,14 +1069,77 @@
 	return (rval);
 }
 
-void
-netstack_rele(netstack_t *ns)
+
+static void
+netstack_reap(void *arg)
 {
+	/* Indicate we took a semaphore to get here. */
+	netstack_reap_work((netstack_t *)arg, B_TRUE);
+}
+
+static void
+netstack_reap_intr(void *arg)
+{
+	/* Indicate we did NOT TAKE a semaphore to get here. */
+	netstack_reap_work((netstack_t *)arg, B_FALSE);
+}
+
+static void
+netstack_reap_work(netstack_t *ns, boolean_t semaphore_signal)
+{
 	netstack_t **nsp;
 	boolean_t found;
-	int refcnt, numzones;
 	int i;
 
+	/*
+	 * Time to call the destroy functions and free up
+	 * the structure
+	 */
+	netstack_stack_inactive(ns);
+
+	/* Make sure nothing increased the references */
+	ASSERT(ns->netstack_refcnt == 0);
+	ASSERT(ns->netstack_numzones == 0);
+
+	/* Finally remove from list of netstacks */
+	mutex_enter(&netstack_g_lock);
+	found = B_FALSE;
+	for (nsp = &netstack_head; *nsp != NULL;
+	     nsp = &(*nsp)->netstack_next) {
+		if (*nsp == ns) {
+			*nsp = ns->netstack_next;
+			ns->netstack_next = NULL;
+			found = B_TRUE;
+			break;
+		}
+	}
+	ASSERT(found);
+	mutex_exit(&netstack_g_lock);
+
+	/* Make sure nothing increased the references */
+	ASSERT(ns->netstack_refcnt == 0);
+	ASSERT(ns->netstack_numzones == 0);
+
+	ASSERT(ns->netstack_flags & NSF_CLOSING);
+
+	for (i = 0; i < NS_MAX; i++) {
+		nm_state_t *nms = &ns->netstack_m_state[i];
+
+		cv_destroy(&nms->nms_cv);
+	}
+	mutex_destroy(&ns->netstack_lock);
+	cv_destroy(&ns->netstack_cv);
+	kmem_free(ns, sizeof (*ns));
+	/* Allow another reap to be scheduled. */
+	if (semaphore_signal)
+		sema_v(&netstack_reap_limiter);
+}
+
+void
+netstack_rele(netstack_t *ns)
+{
+	int refcnt, numzones;
+
 	mutex_enter(&ns->netstack_lock);
 	ASSERT(ns->netstack_refcnt > 0);
 	ns->netstack_refcnt--;
@@ -1084,56 +1155,62 @@
 	mutex_exit(&ns->netstack_lock);
 
 	if (refcnt == 0 && numzones == 0) {
+		boolean_t is_not_intr = !servicing_interrupt();
+
 		/*
-		 * Time to call the destroy functions and free up
-		 * the structure
+		 * Because there are possibilities of kstats being held by
+		 * callers, which would then be immediately freed, but held up
+		 * due to kstat's odd reference model recording the thread, we
+		 * choose to schedule the actual deletion of this netstack as
+		 * a deferred task on the system taskq.  This way, any
+		 * store-the-thread-pointer semantics won't trip over
+		 * themselves.
+		 *
+		 * On the off chance this is called in interrupt context, we
+		 * cannot use the semaphore to enforce rate-limiting.
 		 */
-		netstack_stack_inactive(ns);
+		if (is_not_intr && sema_tryp(&netstack_reap_limiter) == 0) {
+			/*
+			 * XXX KEBE SAYS inidicate we're slamming against
+			 * a limit.
+			 */
+			hrtime_t measurement = gethrtime();
 
-		/* Make sure nothing increased the references */
-		ASSERT(ns->netstack_refcnt == 0);
-		ASSERT(ns->netstack_numzones == 0);
-
-		/* Finally remove from list of netstacks */
-		mutex_enter(&netstack_g_lock);
-		found = B_FALSE;
-		for (nsp = &netstack_head; *nsp != NULL;
-		    nsp = &(*nsp)->netstack_next) {
-			if (*nsp == ns) {
-				*nsp = ns->netstack_next;
-				ns->netstack_next = NULL;
-				found = B_TRUE;
-				break;
-			}
+			sema_p(&netstack_reap_limiter);
+			/* Caputre delay in ns. */
+			DTRACE_PROBE1(netstack__reap__rate__limited,
+			    hrtime_t *, gethrtime() - measurement);
 		}
-		ASSERT(found);
-		mutex_exit(&netstack_g_lock);
 
-		/* Make sure nothing increased the references */
-		ASSERT(ns->netstack_refcnt == 0);
-		ASSERT(ns->netstack_numzones == 0);
-
-		ASSERT(ns->netstack_flags & NSF_CLOSING);
-
-		for (i = 0; i < NS_MAX; i++) {
-			nm_state_t *nms = &ns->netstack_m_state[i];
-
-			cv_destroy(&nms->nms_cv);
+		if (taskq_dispatch(system_taskq,
+		    is_not_intr ? netstack_reap : netstack_reap_intr, ns,
+		    TQ_NOSLEEP) == NULL) {
+			/*
+			 * Well shoot, why can't we taskq_dispatch?
+			 * Take our chances with a direct call.
+			 */
+			DTRACE_PROBE1(netstack__reap__taskq__fail,
+			    netstack_t *, ns);
+			netstack_reap_work(ns, is_not_intr);
 		}
-		mutex_destroy(&ns->netstack_lock);
-		cv_destroy(&ns->netstack_cv);
-		kmem_free(ns, sizeof (*ns));
 	}
 }
 
+static void
+netstack_hold_locked(netstack_t *ns)
+{
+	ASSERT(MUTEX_HELD(&ns->netstack_lock));
+	ns->netstack_refcnt++;
+	ASSERT(ns->netstack_refcnt > 0);
+	DTRACE_PROBE1(netstack__inc__ref, netstack_t *, ns);
+}
+
 void
 netstack_hold(netstack_t *ns)
 {
 	mutex_enter(&ns->netstack_lock);
-	ns->netstack_refcnt++;
-	ASSERT(ns->netstack_refcnt > 0);
+	netstack_hold_locked(ns);
 	mutex_exit(&ns->netstack_lock);
-	DTRACE_PROBE1(netstack__inc__ref, netstack_t *, ns);
 }
 
 /*
