DF-4310 / fix.diff
--- a/sys/dev/netif/ste/if_ste.c +++ b/sys/dev/netif/ste/if_ste.c @@ -787,29 +787,46 @@ ifp = &sc->arpcom.ac_if; mii = device_get_softc(sc->ste_miibus); - lwkt_serialize_enter(ifp->if_serializer); - - IFNET_STAT_INC(ifp, collisions, CSR_READ_1(sc, STE_LATE_COLLS) - + CSR_READ_1(sc, STE_MULTI_COLLS) - + CSR_READ_1(sc, STE_SINGLE_COLLS)); - - if (!sc->ste_link) { - mii_pollstat(mii); - if (mii->mii_media_status & IFM_ACTIVE && - IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { - sc->ste_link++; - /* - * we don't get a call-back on re-init so do it - * otherwise we get stuck in the wrong link state - */ - ste_miibus_statchg(sc->ste_dev); - if (!ifq_is_empty(&ifp->if_snd)) - if_devstart(ifp); + /* + * DF-4310 (DF-3715 family): must NOT block on if_serializer from + * this callout callback. ste_stop() and ste_intr()'s STATS_OFLOW + * path issue the *synchronous* callout_stop(&sc->ste_stat_timer) + * while holding if_serializer; a dequeued callback parked in + * lwkt_serialize_enter() deadlocks against them (AB-BA, both + * threads sleep forever) and, being a non-MP callout, it parks + * while holding the MP lock. Skip this tick's work when the + * serializer is contended. + */ + if (lwkt_serialize_try(ifp->if_serializer)) { + IFNET_STAT_INC(ifp, collisions, CSR_READ_1(sc, STE_LATE_COLLS) + + CSR_READ_1(sc, STE_MULTI_COLLS) + + CSR_READ_1(sc, STE_SINGLE_COLLS)); + + if (!sc->ste_link) { + mii_pollstat(mii); + if (mii->mii_media_status & IFM_ACTIVE && + IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { + sc->ste_link++; + /* + * we don't get a call-back on re-init so do + * it otherwise we get stuck in the wrong + * link state + */ + ste_miibus_statchg(sc->ste_dev); + if (!ifq_is_empty(&ifp->if_snd)) + if_devstart(ifp); + } } + lwkt_serialize_exit(ifp->if_serializer); } + /* + * Re-arm OUTSIDE the serializer: a recursive callout_reset() from + * inside the callback overrides a racing callout_stop() (RESET + * beats STOP in kern_timeout.c) and would resurrect the timer + * after ste_stop()/ste_detach() (post-detach use-after-free). + */ callout_reset(&sc->ste_stat_timer, hz, ste_stats_update, sc); - lwkt_serialize_exit(ifp->if_serializer); } |