git: ee7f62faa893 - main - e6000sw: stop / drain the taskqueue (and tick) during detach
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 27 Apr 2025 18:38:10 UTC
The branch main has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=ee7f62faa893bd9bbe6650716579072724c427cb commit ee7f62faa893bd9bbe6650716579072724c427cb Author: Adrian Chadd <adrian@FreeBSD.org> AuthorDate: 2025-04-25 18:41:13 +0000 Commit: Adrian Chadd <adrian@FreeBSD.org> CommitDate: 2025-04-27 18:05:05 +0000 e6000sw: stop / drain the taskqueue (and tick) during detach Although the tick isn't running every hz right now, when it /is/ running at hz, the shutdown path will race with an existing running tick routine, causing unpredictable panics. * Introduce a shutdown flag which will abort doing the tick work if set * set the shutdown flag and start cancel/draining the taskqueue during detach. Differential Revision: https://reviews.freebsd.org/D50030 --- sys/dev/etherswitch/e6000sw/e6000sw.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/sys/dev/etherswitch/e6000sw/e6000sw.c b/sys/dev/etherswitch/e6000sw/e6000sw.c index 85900cebc303..be02edb3d5e6 100644 --- a/sys/dev/etherswitch/e6000sw/e6000sw.c +++ b/sys/dev/etherswitch/e6000sw/e6000sw.c @@ -89,6 +89,7 @@ typedef struct e6000sw_softc { device_t miibus[E6000SW_MAX_PORTS]; struct taskqueue *sc_tq; struct timeout_task sc_tt; + bool is_shutdown; int vlans[E6000SW_NUM_VLANS]; uint32_t swid; @@ -851,13 +852,18 @@ e6000sw_detach(device_t dev) sc = device_get_softc(dev); + E6000SW_LOCK(sc); + sc->is_shutdown = true; + if (sc->sc_tq != NULL) { + while (taskqueue_cancel_timeout(sc->sc_tq, &sc->sc_tt, NULL) != 0) + taskqueue_drain_timeout(sc->sc_tq, &sc->sc_tt); + } + E6000SW_UNLOCK(sc); + error = bus_generic_detach(dev); if (error != 0) return (error); - if (device_is_attached(dev)) - taskqueue_drain_timeout(sc->sc_tq, &sc->sc_tt); - if (sc->sc_tq != NULL) taskqueue_free(sc->sc_tq); @@ -1584,6 +1590,12 @@ e6000sw_tick(void *arg, int p __unused) E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); E6000SW_LOCK(sc); + + if (sc->is_shutdown) { + E6000SW_UNLOCK(sc); + return; + } + for (port = 0; port < sc->num_ports; port++) { /* Tick only on PHY ports */ if (!e6000sw_is_portenabled(sc, port) ||