[PATCH net v2] net: Don't allow disabling napi kthread mode while napi instances are disabled

From: Maxime Chevallier

Date: Tue Oct 06 2026 - 10:11:52 EST


Trying to disable the napi threaded state while the napi instance is
disabled will hang forever in napi_stop_kthread(), as it waits for
NAPIF_STATE_SCHED_THREADED to clear.

This won't happen until the next ____napi_schedule() call, which won't
happen as it's disabled.

This happens in 2 instances :

- Drivers that create but don't use napi instances (stmmac's rxtx napi
for AF_XDP for example), here it's a driver bug

- Drivers that create their napi instances in .probe(). Here, setting
threaded off while the interface is down will hang :

ip link set eth0 down
echo 1 > /sys/class/net/eth0/threaded
echo 0 > /sys/class/net/eth0/threaded
-> hang

Checking on netif_running() isn't enough, as napi instances may be
transiently disabled when changing the MTU for example, so let's check
the NAPIF_STATE_NPSVC flag instead, that's clear when the napi instance
is enabled.

This fix only addresses the second case. For the first case where
drivers have unused napi instances, the "threaded" mode can't be
switched off once enabled, these drivers will need fixing. As this
hasn't been seen before on said drivers, I guess it's OK as it used to
just freeze the system.

This was tested on mvpp2 (probe-time napi_add) and stmmac.

Fixes: 689883de94dd ("net: stop napi kthreads when THREADED napi is disabled")
Signed-off-by: Maxime Chevallier <maxime.chevallier@xxxxxxxxxxx>
---
V2:
- Different approach as per Jakub's review, just don't allow setting
the napi threaded mode while interface is down.

I'm unsure about the correctness of this, to me it seems that the
NAPI_STATE_NPSVC flag indicates the condition we're interested in (is
napi instance enabled or not ?), but I may be missing something
obvious :(

V1:
https://lore.kernel.org/r/20260926194714.648819-1-maxime.chevallier@xxxxxxxxxxx

net/core/dev.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/net/core/dev.c b/net/core/dev.c
index f660fccfc0db..fcf18c9eedb8 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -7315,6 +7315,12 @@ int netif_set_threaded(struct net_device *dev,
}
}
}
+ } else {
+ list_for_each_entry(napi, &dev->napi_list, dev_list) {
+ if (napi->thread &&
+ test_bit(NAPI_STATE_NPSVC, &napi->state))
+ return -EBUSY;
+ }
}

WRITE_ONCE(dev->threaded, threaded);
--
2.55.0