[PATCH net-next v3 5/5] netconsole: close netdevice unregister window during target resume
From: Breno Leitao
Date: Thu Jun 04 2026 - 12:22:33 EST
process_resume_target() removes the target from target_list before
calling resume_target() so that netpoll_setup() can run with interrupts
enabled, then re-adds it once setup completes. netpoll_setup() acquires a
net_device reference (netdev_hold()) and releases the RTNL before
returning.
While the target is off target_list and the RTNL is not held,
netconsole_netdev_event() cannot find it. If the egress device is
unregistered in that window, the NETDEV_UNREGISTER notifier walks
target_list, misses the resuming target, and never tears it down. The
target is then re-added in STATE_ENABLED still holding a reference to the
now-unregistered device, leaking it and hanging unregister_netdevice() in
netdev_wait_allrefs().
Re-check under RTNL before re-publishing the target: if the device left
NETREG_REGISTERED while we were off the list, run do_netpoll_cleanup() and
mark the target disabled. Taking the RTNL across the check and the
list_add() serialises against the NETDEV_UNREGISTER notifier, which also
runs under RTNL, so the device is either still registered (and the
notifier will find the re-added target later) or already unregistering
(and we drop the reference here). netdev_wait_allrefs() runs from
netdev_run_todo() outside the RTNL, so dropping the reference here cannot
deadlock against the pending unregister.
Signed-off-by: Breno Leitao <leitao@xxxxxxxxxx>
---
drivers/net/netconsole.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 80c5393ffa1c..606e265cdfd7 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -335,6 +335,24 @@ static void process_resume_target(struct work_struct *work)
resume_target(nt);
+ /* netpoll_setup() took a net_device reference and dropped the RTNL
+ * before returning, all while this target was off target_list and
+ * thus invisible to netconsole_netdev_event(). If the device was
+ * unregistered in that window the NETDEV_UNREGISTER notifier could not
+ * tear this target down, which would leak the reference and hang
+ * unregister_netdevice(). Re-check under the RTNL before re-publishing:
+ * taking it across the check and the list_add() serialises against the
+ * notifier (which also runs under the RTNL), so the device is either
+ * still registered (the notifier will find the re-added target) or
+ * already unregistering (we drop the reference here).
+ */
+ rtnl_lock();
+ if (nt->state == STATE_ENABLED && nt->np.dev &&
+ nt->np.dev->reg_state != NETREG_REGISTERED) {
+ do_netpoll_cleanup(&nt->np);
+ nt->state = STATE_DISABLED;
+ }
+
/* At this point the target is either enabled or disabled and
* was cleaned up before getting deactivated. Either way, add it
* back to target list.
@@ -342,6 +360,7 @@ static void process_resume_target(struct work_struct *work)
spin_lock_irqsave(&target_list_lock, flags);
list_add(&nt->list, &target_list);
spin_unlock_irqrestore(&target_list_lock, flags);
+ rtnl_unlock();
out_unlock:
dynamic_netconsole_mutex_unlock();
--
2.53.0-Meta