Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet/in_mcast.c
Show First 20 Lines • Show All 218 Lines • ▼ Show 20 Lines | if (ifp != NULL) { | ||||
*/ | */ | ||||
KASSERT(inm->inm_ifp == ifp, ("%s: bad ifp", __func__)); | KASSERT(inm->inm_ifp == ifp, ("%s: bad ifp", __func__)); | ||||
} | } | ||||
return (ifp == NULL); | return (ifp == NULL); | ||||
} | } | ||||
#endif | #endif | ||||
static struct task free_task; | /* | ||||
* Interface detach can happen in a taskqueue thread context, so we must use a | |||||
* dedicated thread to avoid deadlocks when draining inm_release tasks. | |||||
*/ | |||||
TASKQUEUE_DEFINE_THREAD(inm_free); | |||||
static struct task inm_free_task; | |||||
static struct in_multi_head inm_free_list = SLIST_HEAD_INITIALIZER(); | static struct in_multi_head inm_free_list = SLIST_HEAD_INITIALIZER(); | ||||
static void inm_release_task(void *arg __unused, int pending __unused); | static void inm_release_task(void *arg __unused, int pending __unused); | ||||
static void | static void | ||||
inm_init(void *arg __unused) | inm_init(void *arg __unused) | ||||
{ | { | ||||
TASK_INIT(&free_task, 0, inm_release_task, NULL); | TASK_INIT(&inm_free_task, 0, inm_release_task, NULL); | ||||
} | } | ||||
SYSINIT(inm_init, SI_SUB_TASKQ, SI_ORDER_ANY, inm_init, NULL); | SYSINIT(inm_init, SI_SUB_TASKQ, SI_ORDER_ANY, inm_init, NULL); | ||||
void | void | ||||
inm_release_wait(void *arg __unused) | |||||
{ | |||||
/* | |||||
* Make sure all pending multicast addresses are freed before | |||||
* the VNET or network device is destroyed: | |||||
*/ | |||||
taskqueue_drain(taskqueue_inm_free, &inm_free_task); | |||||
} | |||||
#ifdef VIMAGE | |||||
VNET_SYSUNINIT(inm_release_wait, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, inm_release_wait, NULL); | |||||
#endif | |||||
void | |||||
inm_release_list_deferred(struct in_multi_head *inmh) | inm_release_list_deferred(struct in_multi_head *inmh) | ||||
{ | { | ||||
if (SLIST_EMPTY(inmh)) | if (SLIST_EMPTY(inmh)) | ||||
return; | return; | ||||
mtx_lock(&in_multi_free_mtx); | mtx_lock(&in_multi_free_mtx); | ||||
SLIST_CONCAT(&inm_free_list, inmh, in_multi, inm_nrele); | SLIST_CONCAT(&inm_free_list, inmh, in_multi, inm_nrele); | ||||
mtx_unlock(&in_multi_free_mtx); | mtx_unlock(&in_multi_free_mtx); | ||||
taskqueue_enqueue(taskqueue_thread, &free_task); | taskqueue_enqueue(taskqueue_inm_free, &inm_free_task); | ||||
} | } | ||||
void | void | ||||
inm_disconnect(struct in_multi *inm) | inm_disconnect(struct in_multi *inm) | ||||
{ | { | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct ifmultiaddr *ifma, *ll_ifma; | struct ifmultiaddr *ifma, *ll_ifma; | ||||
▲ Show 20 Lines • Show All 2,808 Lines • Show Last 20 Lines |