DF-0366 / fix.diff
diff --git a/sys/net/lagg/if_lagg.c b/sys/net/lagg/if_lagg.c --- a/sys/net/lagg/if_lagg.c +++ b/sys/net/lagg/if_lagg.c @@ -1755,15 +1755,25 @@ ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); ASSERT_ALTQ_SQ_SERIALIZED_HW(ifsq); - if (((ifp->if_flags & IFF_RUNNING) == 0) - || (sc->sc_proto == LAGG_PROTO_NONE) - || (sc->sc_count == 0)) { + /* + * Re-validate sc_count INSIDE LAGG_RLOCK. The old lockless + * early-exit check at this point raced lagg_port_destroy's + * sc_count-- (under WLOCK) - if count went 1->0 between the + * lockless check and the RLOCK acquire, the round-robin (and + * loadbalance) select_tx_port routines divide by zero. + */ + if ((ifp->if_flags & IFF_RUNNING) == 0 + || sc->sc_proto == LAGG_PROTO_NONE) { ifsq_purge(ifsq); return; } - LAGG_RLOCK(sc); + if (sc->sc_count == 0) { + LAGG_RUNLOCK(sc); + ifsq_purge(ifsq); + return; + } for (;;) { m = ifsq_dequeue(ifsq); if (m == NULL){ |