⬢ DragonFlyBSD Kernel Audit
DF-4260 / fix.diff
← back to finding ↓ download raw
--- 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));