diff options
| author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2011-04-01 11:56:50 -0700 |
|---|---|---|
| committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2011-04-01 11:56:50 -0700 |
| commit | 5a4764fbfb71e8f3f428eaca759acba01ecd6061 (patch) | |
| tree | 60891dff401ff2b7bf23c46c120ca1ad9ce854bd /usr/src/cmd/dlmgmtd | |
| parent | 4e79c50cac072a506defdd893c6182af93e5b895 (diff) | |
| download | illumos-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.c | 32 |
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; |
