--- sys/dev/netif/vr/if_vr.c.orig +++ sys/dev/netif/vr/if_vr.c @@ -827,6 +827,18 @@ ether_ifdetach(ifp); } + /* + * Drain vr_tick() OUTSIDE ifp->if_serializer. vr_tick() + * (if_vr.c) acquires this serializer, and callout_stop()/ + * callout_drain() are synchronous on this kernel + * (sys/kern/kern_timeout.c, _callout_cancel_or_stop with + * sync=1 sleeps in ssleep("costp") waiting for an INPROG + * callback). Draining while holding the serializer deadlocks + * against a vr_tick() that is blocked trying to acquire it: + * the softclock thread of one CPU and the stopping thread + * wedge permanently (system-wide timer death on that CPU). + */ + callout_drain(&sc->vr_stat_timer); if (sc->vr_miibus != NULL) device_delete_child(dev, sc->vr_miibus); bus_generic_detach(dev); @@ -1627,7 +1639,11 @@ ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; - callout_stop(&sc->vr_stat_timer); + /* + * Never call the synchronous callout_stop() while holding + * ifp->if_serializer -- vr_tick() needs that serializer. + */ + callout_stop_async(&sc->vr_stat_timer); VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));