⬢ DragonFlyBSD Kernel Audit
DF-3761 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/netif/alc/if_alc.c
+++ b/sys/dev/netif/alc/if_alc.c
@@ -3224,7 +3224,7 @@
 	struct ifnet *ifp;
 	struct rx_rdesc *rrd;
 	uint32_t nsegs, status;
-	int rr_cons, prog;
+	int n, rr_cons, prog;
 
 	bus_dmamap_sync(sc->alc_cdata.alc_rr_ring_tag,
 	    sc->alc_cdata.alc_rr_ring_map,
@@ -3233,7 +3233,18 @@
 	    sc->alc_cdata.alc_rx_ring_map, BUS_DMASYNC_POSTWRITE);
 	rr_cons = sc->alc_cdata.alc_rr_cons;
 	ifp = sc->alc_ifp;
+	/*
+	 * Bound the number of Rx events serviced per interrupt with
+	 * the (already existing but never used) process_limit knob.
+	 * Without it a line-rate flood keeps the return ring
+	 * perpetually non-empty and this loop never terminates while
+	 * the interrupt handler holds the serializer: NIC + one CPU
+	 * livelock (FreeBSD bounds this loop the same way).
+	 */
+	n = sc->alc_process_limit;
 	for (prog = 0; (ifp->if_flags & IFF_RUNNING) != 0;) {
+		if (n-- <= 0)
+			break;
 		rrd = &sc->alc_rdata.alc_rr_ring[rr_cons];
 		status = le32toh(rrd->status);
 		if ((status & RRD_VALID) == 0)