bridge_linkstate() calls bstp_linkstate() inside the network epoch, but the SIOCGIFMEDIA ioctl can acquire sleepable driver locks and wait for hardware. Reuse the port's media task on taskqueue_thread for link events and existing media polling. Query in the interface's VNET without an epoch or BSTP mutex, then recheck port activity and update STP under the mutex and an epoch, since the state update can transmit BPDUs. Run the subsequent STP state update for every media refresh, including polling and reinitialization. This preserves query before update ordering for link events and lets other refreshes process pending transitions without waiting for the next STP tick. It does not add media queries or increase the existing polling frequency. Assert epoch coverage in bstp_linkstate(), and serialize link and packet input admission with port disable so late callbacks cannot enqueue work after teardown drains it. Initialize STP before publishing the bridge member. Drain media work before the notifications it can generate, and keep the member's bridge pointer valid until those callbacks finish. Defer BSTP mutex destruction to the bridge's epoch cleanup callback so input and link-state readers finish before the mutex is destroyed. Protect the final root-port cleanup with the mutex and an epoch. PR: 264549 Reported by: mfbott <bugaddress@posteo.net> MFC after: 2 weeks
Details
Diff Detail
- Repository
- rG FreeBSD src repository
- Lint
Lint Skipped - Unit
Tests Skipped
Event Timeline
| sys/net/bridgestp.c | ||
|---|---|---|
| 1797 | This feels kind of weird. bridge_linkstate() is already running as an asynchronous task; it enters a network epoch and now here we are deferring some of the work again because of that. Why can't bridge_linkstate() instead take the (sleepable) bridge lock? | |
| 2209 | Can't you use taskqueue_drain() instead? NET_EPOCH_WAIT() is a heavy hammer. | |
Unfortunately, I'm not expert on bridge driver.
| sys/net/bridgestp.c | ||
|---|---|---|
| 1794 | Maybe KASSERT that? | |
Added NET_EPOCH_ASSERT() at entry to bstp_linkstate(). Removed the synchronous wait by moving STP mutex destruction into the bridge’s existing epoch cleanup callback. Draining tasks alone would not cover packet input readers, which can still acquire the mutex before checking whether the port is inactive. The existing callback provides the required grace period.
| sys/net/bridgestp.c | ||
|---|---|---|
| 1797 | You’re right that link handling already runs asynchronously. Taking the bridge lock here would require reworking teardown: member deletion holds that lock while draining STP notification tasks on taskqueue_swi, which also runs the link task. If the link task blocks on the bridge lock, those notifications cannot complete. The epoch also protects the member/bridge lookup, so changing this requires replacement lifetime protection. That rework is possible, but polling and reinitialization already need the media task. I’ve retained the shared media-task path to keep this fix’s lifetime and teardown rules simpler unless you see a better design. | |