Index: sys/netinet/ip_mroute.c =================================================================== --- sys/netinet/ip_mroute.c +++ sys/netinet/ip_mroute.c @@ -747,7 +747,8 @@ static int X_ip_mrouter_done(void) { - struct ifnet *ifp; + struct ifnet **ifps; + int nifp = 0; u_long i; vifi_t vifi; struct bw_upcall *bu; @@ -774,6 +775,8 @@ taskqueue_drain(V_task_queue, &V_task); } + ifps = malloc(MAXVIFS * sizeof(*ifps), M_TEMP, M_WAITOK); + MRW_WLOCK(); taskqueue_cancel(V_task_queue, &V_task, NULL); @@ -785,14 +788,17 @@ mtx_destroy(&V_bw_upcalls_ring_mtx); /* - * For each phyint in use, disable promiscuous reception of all IP - * multicasts. + * For each phyint in use, prepare to disable promiscuous reception + * of all IP multicasts. Defer the actual call until the lock is released; + * just record the list of interfaces while locked. Some interfaces use + * sx locks in their ioctl routines, which is not allowed while holding + * a non-sleepable lock. */ + KASSERT(V_numvifs <= MAXVIFS, ("More vifs than possible")); for (vifi = 0; vifi < V_numvifs; vifi++) { if (!in_nullhost(V_viftable[vifi].v_lcl_addr) && !(V_viftable[vifi].v_flags & (VIFF_TUNNEL | VIFF_REGISTER))) { - ifp = V_viftable[vifi].v_ifp; - if_allmulti(ifp, 0); + ifps[nifp++] = V_viftable[vifi].v_ifp; } } bzero((caddr_t)V_viftable, sizeof(*V_viftable) * MAXVIFS); @@ -824,6 +830,11 @@ MRW_WUNLOCK(); + /* Now disable multicast on the interfaces recorded above. */ + for (vifi = 0; vifi < nifp; vifi++) + if_allmulti(ifps[vifi], 0); + free(ifps, M_TEMP); + CTR1(KTR_IPMF, "%s: done", __func__); return 0;