summaryrefslogtreecommitdiff
path: root/usr/src/cmd/dlmgmtd
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2011-04-01 11:56:50 -0700
committerJerry Jelinek <jerry.jelinek@joyent.com>2011-04-01 11:56:50 -0700
commit5a4764fbfb71e8f3f428eaca759acba01ecd6061 (patch)
tree60891dff401ff2b7bf23c46c120ca1ad9ce854bd /usr/src/cmd/dlmgmtd
parent4e79c50cac072a506defdd893c6182af93e5b895 (diff)
downloadillumos-joyent-5a4764fbfb71e8f3f428eaca759acba01ecd6061.tar.gz
OS-328 dlmgmtd/mac_link_flow_add() deadlock
Diffstat (limited to 'usr/src/cmd/dlmgmtd')
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_door.c32
1 files changed, 29 insertions, 3 deletions
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_door.c b/usr/src/cmd/dlmgmtd/dlmgmt_door.c
index b80ffcc280..e3e7fccd84 100644
--- a/usr/src/cmd/dlmgmtd/dlmgmt_door.c
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_door.c
@@ -59,6 +59,7 @@
#include <libsysevent.h>
#include <libdlmgmt.h>
#include <librcm.h>
+#include <thread.h>
#include "dlmgmt_impl.h"
typedef void dlmgmt_door_handler_t(void *, void *, size_t *, zoneid_t,
@@ -1317,6 +1318,14 @@ done:
retvalp->lr_err = err;
}
+static void
+do_zonehalt(void *zid)
+{
+ dlmgmt_table_lock(B_TRUE);
+ dlmgmt_db_fini((zoneid_t)zid);
+ dlmgmt_table_unlock();
+}
+
/* ARGSUSED */
static void
dlmgmt_zonehalt(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
@@ -1332,9 +1341,26 @@ dlmgmt_zonehalt(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
} else if (zonehalt->ld_zoneid == GLOBAL_ZONEID) {
err = EINVAL;
} else {
- dlmgmt_table_lock(B_TRUE);
- dlmgmt_db_fini(zonehalt->ld_zoneid);
- dlmgmt_table_unlock();
+ /*
+ * dlmgmt_db_fini makes ioctls which lead to the
+ * following kernel stack:
+ * vnic_ioc_delete
+ * vnic_dev_delete
+ * dls_devnet_destroy
+ * dls_devnet_destroy calls mac_perim_enter_by_mh
+ * which could lead to deadlock if another process is
+ * holding the mac perimeter then made an upcall to
+ * dlmgmtd. To avoid this, we run the dlmgmt_db_fini
+ * in a thread so that we can continue to service
+ * upcalls in parallel with cleaning up zones.
+ */
+ err = thr_create(NULL, 0,
+ (void *(*)(void *))do_zonehalt,
+ (void *)(zonehalt->ld_zoneid), THR_DAEMON, NULL);
+ if (err != 0)
+ dlmgmt_log(LOG_ERR, "unable to create thread "
+ "to clean up zone %d: %s",
+ zonehalt->ld_zoneid, strerror(err));
}
}
retvalp->lr_err = err;