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) ||