[PATCH OLK-6.6 0/3] net: stop napi kthreads when THREADED napi is disabled
Maxime Chevallier (1): net: Use a dedicated flag to track disabled napi instances Samiullah Khawaja (2): net: stop napi kthreads when THREADED napi is disabled net: Use NAPI_* in test_bit when stopping napi kthread include/linux/netdevice.h | 2 ++ net/core/dev.c | 59 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 4 deletions(-) -- 2.33.8
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,转换为PR失败! 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/YPA... 失败原因:同步源码仓代码到fork仓失败 建议解决方法:请稍等,机器人会在下一次任务重新执行 FeedBack: The patch(es) which you have sent to kernel@openeuler.org has been converted to PR failed! Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/YPA... Failed Reason: sync origin kernel's codes to the fork repository failed Suggest Solution: please wait, the bot will retry in the next interval
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/30856 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/YPA... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/30856 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/YPA...
From: Samiullah Khawaja <skhawaja@google.com> mainline inclusion from mainline-v6.17-rc1 commit 689883de94dd8a43a0ea77311327effab240afda category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/10109 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Once the THREADED napi is disabled, the napi kthread should also be stopped. Keeping the kthread intact after disabling THREADED napi makes the PID of this kthread show up in the output of netlink 'napi-get' and ps -ef output. The is discussed in the patch below: https://lore.kernel.org/all/20250502191548.559cc416@kernel.org NAPI kthread should stop only if, - There are no pending napi poll scheduled for this thread. - There are no new napi poll scheduled for this thread while it has stopped. - The ____napi_schedule can correctly fallback to the softirq for napi polling. Since napi_schedule_prep provides mutual exclusion over STATE_SCHED bit, it is safe to unset the STATE_THREADED when SCHED_THREADED is set or the SCHED bit is not set. SCHED_THREADED being set means that SCHED is already set and the kthread owns this napi. To disable threaded napi, unset STATE_THREADED bit safely if SCHED_THREADED is set or SCHED is unset. Once STATE_THREADED is unset safely then wait for the kthread to unset the SCHED_THREADED bit so it safe to stop the kthread. Add a new test in nl_netdev to verify this behaviour. Tested: ./tools/testing/selftests/net/nl_netdev.py TAP version 13 1..6 ok 1 nl_netdev.empty_check ok 2 nl_netdev.lo_check ok 3 nl_netdev.page_pool_check ok 4 nl_netdev.napi_list_check ok 5 nl_netdev.dev_set_threaded ok 6 nl_netdev.nsim_rxq_reset_down # Totals: pass:6 fail:0 xfail:0 xpass:0 skip:0 error:0 Ran neper for 300 seconds and did enable/disable of thread napi in a loop continuously. Signed-off-by: Samiullah Khawaja <skhawaja@google.com> Link: https://patch.msgid.link/20250609173015.3851695-1-skhawaja@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Conflicts: net/core/dev.c tools/testing/selftests/net/nl_netdev.py [Conflicts are caused by the following patches not being merged: init_gro_hash() still sits between napi_watchdog() and dev_set_threaded() 388d31417ce0 ("net: gro: expose GRO init/cleanup to use outside of NAPI") tools/testing/selftests/net/nl_netdev.py does not exist in this tree] Signed-off-by: JiangJieHua <jiangjiehua1@huawei.com> --- net/core/dev.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 173e3f78abba1..da7ed251c8cbc 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6651,6 +6651,43 @@ static void init_gro_hash(struct napi_struct *napi) napi->gro_bitmask = 0; } +static void napi_stop_kthread(struct napi_struct *napi) +{ + unsigned long val, new; + + /* Wait until the napi STATE_THREADED is unset. */ + while (true) { + val = READ_ONCE(napi->state); + + /* If napi kthread own this napi or the napi is idle, + * STATE_THREADED can be unset here. + */ + if ((val & NAPIF_STATE_SCHED_THREADED) || + !(val & NAPIF_STATE_SCHED)) { + new = val & (~NAPIF_STATE_THREADED); + } else { + msleep(20); + continue; + } + + if (try_cmpxchg(&napi->state, &val, new)) + break; + } + + /* Once STATE_THREADED is unset, wait for SCHED_THREADED to be unset by + * the kthread. + */ + while (true) { + if (!test_bit(NAPIF_STATE_SCHED_THREADED, &napi->state)) + break; + + msleep(20); + } + + kthread_stop(napi->thread); + napi->thread = NULL; +} + int dev_set_threaded(struct net_device *dev, bool threaded) { struct napi_struct *napi; @@ -6684,8 +6721,12 @@ int dev_set_threaded(struct net_device *dev, bool threaded) * softirq mode will happen in the next round of napi_schedule(). * This should not cause hiccups/stalls to the live traffic. */ - list_for_each_entry(napi, &dev->napi_list, dev_list) - assign_bit(NAPI_STATE_THREADED, &napi->state, threaded); + list_for_each_entry(napi, &dev->napi_list, dev_list) { + if (!threaded && napi->thread) + napi_stop_kthread(napi); + else + assign_bit(NAPI_STATE_THREADED, &napi->state, threaded); + } return err; } -- 2.33.8
From: Samiullah Khawaja <skhawaja@google.com> mainline inclusion from mainline-v6.17-rc7 commit 247981eecd3dd6ff51bd0a0223deba8af39c5498 category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/10109 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- napi_stop_kthread waits for the NAPI_STATE_SCHED_THREADED to be unset before stopping the kthread. But it uses test_bit with the NAPIF_STATE_SCHED_THREADED and that might stop the kthread early before the flag is unset. Use the NAPI_* variant of the NAPI state bits in test_bit instead. Tested: ./tools/testing/selftests/net/nl_netdev.py TAP version 13 1..7 ok 1 nl_netdev.empty_check ok 2 nl_netdev.lo_check ok 3 nl_netdev.page_pool_check ok 4 nl_netdev.napi_list_check ok 5 nl_netdev.dev_set_threaded ok 6 nl_netdev.napi_set_threaded ok 7 nl_netdev.nsim_rxq_reset_down # Totals: pass:7 fail:0 xfail:0 xpass:0 skip:0 error:0 ./tools/testing/selftests/drivers/net/napi_threaded.py TAP version 13 1..2 ok 1 napi_threaded.change_num_queues ok 2 napi_threaded.enable_dev_threaded_disable_napi_threaded # Totals: pass:2 fail:0 xfail:0 xpass:0 skip:0 error:0 Fixes: 689883de94dd ("net: stop napi kthreads when THREADED napi is disabled") Signed-off-by: Samiullah Khawaja <skhawaja@google.com> Link: https://patch.msgid.link/20250910203716.1016546-1-skhawaja@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: JiangJieHua <jiangjiehua1@huawei.com> --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index da7ed251c8cbc..0a2b0ad2296c0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6678,7 +6678,7 @@ static void napi_stop_kthread(struct napi_struct *napi) * the kthread. */ while (true) { - if (!test_bit(NAPIF_STATE_SCHED_THREADED, &napi->state)) + if (!test_bit(NAPI_STATE_SCHED_THREADED, &napi->state)) break; msleep(20); -- 2.33.8
From: Maxime Chevallier <maxime.chevallier@bootlin.com> mainline inclusion from mainline-v7.4-rc2 commit 8dc87fc5d6a0eb337744737008177342a708bf36 category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/10109 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- 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, let's use a dedicated flag to track if the instance is disabled. This allows immediately disabling the kthread when the instance is disabled. This was tested on mvpp2 (probe-time napi_add) and stmmac. Fixes: 689883de94dd ("net: stop napi kthreads when THREADED napi is disabled") Tested-by: Daniel Machon <daniel.machon@microchip.com> Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com> Link: https://patch.msgid.link/20261029153130.121204-1-maxime.chevallier@bootlin.c... Signed-off-by: Jakub Kicinski <kuba@kernel.org> Conflicts: include/linux/netdevice.h net/core/dev.c [Missing prerequisites in OLK-6.6: 1b23cdbd2bbc net: protect netdev->napi_list with netdev_lock() 413f0271f396 net: protect NAPI enablement with netdev_lock() c18d4b190a46 net: Extend NAPI threaded polling to allow kthread based busy polling OLK-6.6 therefore has no netif_napi_add_weight_locked(), napi_disable_locked(), napi_enable_locked(), or NAPI_STATE_THREADED_BUSY_POLL.] Signed-off-by: JiangJieHua <jiangjiehua1@huawei.com> --- include/linux/netdevice.h | 2 ++ net/core/dev.c | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8668973f363c9..e5d8afe4d714a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -411,6 +411,7 @@ enum { NAPI_STATE_PREFER_BUSY_POLL, /* prefer busy-polling over softirq processing*/ NAPI_STATE_THREADED, /* The poll is performed inside its own thread*/ NAPI_STATE_SCHED_THREADED, /* Napi is currently scheduled in threaded mode */ + NAPI_STATE_DISABLED, /* NAPI is disabled */ }; enum { @@ -424,6 +425,7 @@ enum { NAPIF_STATE_PREFER_BUSY_POLL = BIT(NAPI_STATE_PREFER_BUSY_POLL), NAPIF_STATE_THREADED = BIT(NAPI_STATE_THREADED), NAPIF_STATE_SCHED_THREADED = BIT(NAPI_STATE_SCHED_THREADED), + NAPIF_STATE_DISABLED = BIT(NAPI_STATE_DISABLED), }; enum gro_result { diff --git a/net/core/dev.c b/net/core/dev.c index 0a2b0ad2296c0..199a2b97d005b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6655,6 +6655,12 @@ static void napi_stop_kthread(struct napi_struct *napi) { unsigned long val, new; + /* Instance is disabled, we can immediately stop the kthread */ + if (test_bit(NAPI_STATE_DISABLED, &napi->state)) { + clear_bit(NAPI_STATE_THREADED, &napi->state); + goto stop; + } + /* Wait until the napi STATE_THREADED is unset. */ while (true) { val = READ_ONCE(napi->state); @@ -6684,6 +6690,7 @@ static void napi_stop_kthread(struct napi_struct *napi) msleep(20); } +stop: kthread_stop(napi->thread); napi->thread = NULL; } @@ -6795,6 +6802,7 @@ void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi, napi->list_owner = -1; set_bit(NAPI_STATE_SCHED, &napi->state); set_bit(NAPI_STATE_NPSVC, &napi->state); + set_bit(NAPI_STATE_DISABLED, &napi->state); list_add_rcu(&napi->dev_list, &dev->napi_list); napi_hash_add(napi); napi_get_frags_check(napi); @@ -6822,7 +6830,8 @@ void napi_disable(struct napi_struct *n) val = READ_ONCE(n->state); } - new = val | NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC; + new = val | NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC | + NAPIF_STATE_DISABLED; new &= ~(NAPIF_STATE_THREADED | NAPIF_STATE_PREFER_BUSY_POLL); } while (!try_cmpxchg(&n->state, &val, new)); @@ -6846,7 +6855,8 @@ void napi_enable(struct napi_struct *n) do { BUG_ON(!test_bit(NAPI_STATE_SCHED, &val)); - new = val & ~(NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC); + new = val & ~(NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC | + NAPIF_STATE_DISABLED); if (n->dev->threaded && n->thread) new |= NAPIF_STATE_THREADED; } while (!try_cmpxchg(&n->state, &val, new)); -- 2.33.8
participants (2)
-
JiangJieHua -
patchwork bot