Print this page
MFV: illumos-gate@68c34d0407d130a7e8cb7dfb5394a985db03d785
9951 hook_stack_notify_unregister can leave stack locked
Reviewed by: Andy Fiddaman <omnios@citrus-it.net>
Reviewed by: Igor Kozhukhov <igor@dilos.org>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
Approved by: Dan McDonald <danmcd@joyent.com>
Author: Jason King <jason.king@joyent.com>

*** 20,30 **** */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * ! * Copyright 2013 Joyent, Inc. All rights reserved. * Copyright (c) 2016 by Delphix. All rights reserved. */ #include <sys/param.h> #include <sys/types.h> #include <sys/systm.h> --- 20,30 ---- */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * ! * Copyright 2018 Joyent, Inc. All rights reserved. * Copyright (c) 2016 by Delphix. All rights reserved. */ #include <sys/param.h> #include <sys/types.h> #include <sys/systm.h>
*** 705,735 **** int hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback) { hook_family_int_t *hfi; hook_stack_t *hks; - boolean_t canrun; char buffer[16]; void *arg; int error; mutex_enter(&hook_stack_lock); hks = hook_stack_get(stackid); ! if (hks != NULL) { CVW_ENTER_WRITE(&hks->hks_lock); ! canrun = (hook_wait_setflag(&hks->hks_waiter, FWF_ADD_WAIT_MASK, ! FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1); error = hook_notify_unregister(&hks->hks_nhead, callback, &arg); CVW_EXIT_WRITE(&hks->hks_lock); - } else { - error = ESRCH; - } mutex_exit(&hook_stack_lock); if (error == 0) { - if (canrun) { /* * Generate fake unregister event for callback that * is being removed, letting it know everything that * currently exists is now "disappearing." */ --- 705,747 ---- int hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback) { hook_family_int_t *hfi; hook_stack_t *hks; char buffer[16]; void *arg; int error; mutex_enter(&hook_stack_lock); hks = hook_stack_get(stackid); ! if (hks == NULL) { ! mutex_exit(&hook_stack_lock); ! return (ESRCH); ! } ! CVW_ENTER_WRITE(&hks->hks_lock); ! /* ! * If hook_wait_setflag returns -1, another thread has flagged that it ! * is attempting to destroy this hook stack. Before it can flag that ! * it's destroying the hook stack, it must first verify (with ! * hook_stack_lock held) that the hook stack is empty. If we ! * encounter this, it means we should have nothing to do and we ! * just snuck in. ! */ ! if (hook_wait_setflag(&hks->hks_waiter, FWF_DEL_WAIT_MASK, ! FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { ! VERIFY(TAILQ_EMPTY(&hks->hks_nhead)); ! CVW_EXIT_WRITE(&hks->hks_lock); ! mutex_exit(&hook_stack_lock); ! return (ESRCH); ! } error = hook_notify_unregister(&hks->hks_nhead, callback, &arg); CVW_EXIT_WRITE(&hks->hks_lock); mutex_exit(&hook_stack_lock); if (error == 0) { /* * Generate fake unregister event for callback that * is being removed, letting it know everything that * currently exists is now "disappearing." */
*** 738,757 **** SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) { callback(HN_UNREGISTER, arg, buffer, NULL, hfi->hfi_family.hf_name); } ! ! hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE); } mutex_enter(&hook_stack_lock); ! hks = hook_stack_get(stackid); ! if ((error == 0) && (hks->hks_shutdown == 2)) hook_stack_remove(hks); mutex_exit(&hook_stack_lock); - } return (error); } /* --- 750,772 ---- SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) { callback(HN_UNREGISTER, arg, buffer, NULL, hfi->hfi_family.hf_name); } ! } else { ! /* ! * hook_notify_unregister() should only fail if the callback has ! * already been deleted (ESRCH). ! */ ! VERIFY3S(error, ==, ESRCH); } mutex_enter(&hook_stack_lock); ! hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE); ! if (hks->hks_shutdown == 2) hook_stack_remove(hks); mutex_exit(&hook_stack_lock); return (error); } /*