summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/os/netstack.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/os/netstack.c')
-rw-r--r--usr/src/uts/common/os/netstack.c33
1 files changed, 30 insertions, 3 deletions
diff --git a/usr/src/uts/common/os/netstack.c b/usr/src/uts/common/os/netstack.c
index b8467fbe13..93fd1a387d 100644
--- a/usr/src/uts/common/os/netstack.c
+++ b/usr/src/uts/common/os/netstack.c
@@ -22,6 +22,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -205,6 +206,7 @@ void
netstack_unregister(int moduleid)
{
netstack_t *ns;
+ boolean_t created = B_FALSE;
ASSERT(moduleid >= 0 && moduleid < NS_MAX);
@@ -223,7 +225,33 @@ netstack_unregister(int moduleid)
nm_state_t *nms = &ns->netstack_m_state[moduleid];
mutex_enter(&ns->netstack_lock);
- if (ns_reg[moduleid].nr_shutdown != NULL &&
+
+ /*
+ * We need to be careful here. We could actually have a netstack
+ * being created as we speak waiting for us to let go of this
+ * lock to proceed. It may have set NSS_CREATE_NEEDED, but not
+ * have gotten to the point of completing it yet. If
+ * NSS_CREATE_NEEDED, we can safely just remove it here and
+ * never create the module. However, if NSS_CREATE_INPROGRESS is
+ * set, we need to still flag this module for shutdown and
+ * deletion, just as though it had reached NSS_CREATE_COMPLETED.
+ *
+ * It is safe to do that because of two different guarantees
+ * that exist in the system. The first is that before we do a
+ * create, shutdown, or destroy, we ensure that nothing else is
+ * in progress in the system for this netstack and wait for it
+ * to complete. Secondly, because the zone is being created, we
+ * know that the following call to apply_all_netstack will block
+ * on the zone finishing its initialization.
+ */
+ if (nms->nms_flags & NSS_CREATE_NEEDED)
+ nms->nms_flags &= ~NSS_CREATE_NEEDED;
+
+ if (nms->nms_flags & NSS_CREATE_INPROGRESS ||
+ nms->nms_flags & NSS_CREATE_COMPLETED)
+ created = B_TRUE;
+
+ if (ns_reg[moduleid].nr_shutdown != NULL && created &&
(nms->nms_flags & NSS_CREATE_COMPLETED) &&
(nms->nms_flags & NSS_SHUTDOWN_ALL) == 0) {
nms->nms_flags |= NSS_SHUTDOWN_NEEDED;
@@ -231,8 +259,7 @@ netstack_unregister(int moduleid)
netstack_t *, ns, int, moduleid);
}
if ((ns_reg[moduleid].nr_flags & NRF_REGISTERED) &&
- ns_reg[moduleid].nr_destroy != NULL &&
- (nms->nms_flags & NSS_CREATE_COMPLETED) &&
+ ns_reg[moduleid].nr_destroy != NULL && created &&
(nms->nms_flags & NSS_DESTROY_ALL) == 0) {
nms->nms_flags |= NSS_DESTROY_NEEDED;
DTRACE_PROBE2(netstack__destroy__needed,