[RFC PATCH net 2/2] net/ncsi: stop device work before freeing channels
From: Runyu Xiao <hidden>
Date: 2026-06-27 09:27:32
Also in:
lkml
Subsystem:
ncsi library, networking [general], the rest · Maintainers:
Samuel Mendoza-Jonas, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
ncsi_unregister_dev() tears down packages and channels before it disables the NCSI device work item. Current trees already stop the work before freeing ndp itself, but a teardown window remains where a running or already scheduled ncsi_dev_work() can still reach package/channel readers after ncsi_remove_package() has freed the underlying objects. One visible path is the configuration flow through ncsi_channel_is_tx(), which walks package channels and ndp->channel_queue while choosing a transmit channel. Channel queue entries are struct ncsi_channel objects owned by the package channel lists, and ncsi_remove_channel() frees those objects during package removal. Disable the device work before package/channel teardown. Also clear any remaining channel_queue links while the channel objects are still alive, so no stale queue membership is carried into teardown. This was found by our static analysis tool and then manually reviewed against the current tree. CONFIG_PROVE_RCU_LIST was used as target-matched triage evidence; the teardown change is based on the source-level workqueue and channel lifetime review rather than on the dynamic warning alone. This is deliberately limited to the teardown ordering problem. It does not change the normal package/channel RCU-list update model. Signed-off-by: Runyu Xiao <redacted> --- net/ncsi/ncsi-manage.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 5316eadd8ce4..289974dff0c1 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c@@ -1956,10 +1956,18 @@ void ncsi_unregister_dev(struct ncsi_dev *nd) { struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd); struct ncsi_package *np, *tmp; + struct ncsi_channel *nc, *ntmp; unsigned long flags; dev_remove_pack(&ndp->ptype); + disable_work_sync(&ndp->work); + + spin_lock_irqsave(&ndp->lock, flags); + list_for_each_entry_safe(nc, ntmp, &ndp->channel_queue, link) + list_del_init(&nc->link); + spin_unlock_irqrestore(&ndp->lock, flags); + list_for_each_entry_safe(np, tmp, &ndp->packages, node) ncsi_remove_package(np);
@@ -1967,7 +1975,6 @@ void ncsi_unregister_dev(struct ncsi_dev *nd) list_del_rcu(&ndp->node); spin_unlock_irqrestore(&ncsi_dev_lock, flags); - disable_work_sync(&ndp->work); kfree(ndp); }
--
2.34.1