b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | From: Paolo Abeni <pabeni@redhat.com> |
| 2 | Date: Fri, 9 Apr 2021 17:24:17 +0200 |
| 3 | Subject: [PATCH] net: fix hangup on napi_disable for threaded napi |
| 4 | |
| 5 | napi_disable() is subject to an hangup, when the threaded |
| 6 | mode is enabled and the napi is under heavy traffic. |
| 7 | |
| 8 | If the relevant napi has been scheduled and the napi_disable() |
| 9 | kicks in before the next napi_threaded_wait() completes - so |
| 10 | that the latter quits due to the napi_disable_pending() condition, |
| 11 | the existing code leaves the NAPI_STATE_SCHED bit set and the |
| 12 | napi_disable() loop waiting for such bit will hang. |
| 13 | |
| 14 | This patch addresses the issue by dropping the NAPI_STATE_DISABLE |
| 15 | bit test in napi_thread_wait(). The later napi_threaded_poll() |
| 16 | iteration will take care of clearing the NAPI_STATE_SCHED. |
| 17 | |
| 18 | This also addresses a related problem reported by Jakub: |
| 19 | before this patch a napi_disable()/napi_enable() pair killed |
| 20 | the napi thread, effectively disabling the threaded mode. |
| 21 | On the patched kernel napi_disable() simply stops scheduling |
| 22 | the relevant thread. |
| 23 | |
| 24 | v1 -> v2: |
| 25 | - let the main napi_thread_poll() loop clear the SCHED bit |
| 26 | |
| 27 | Reported-by: Jakub Kicinski <kuba@kernel.org> |
| 28 | Fixes: 29863d41bb6e ("net: implement threaded-able napi poll loop support") |
| 29 | Signed-off-by: Paolo Abeni <pabeni@redhat.com> |
| 30 | Reviewed-by: Eric Dumazet <edumazet@google.com> |
| 31 | Link: https://lore.kernel.org/r/883923fa22745a9589e8610962b7dc59df09fb1f.1617981844.git.pabeni@redhat.com |
| 32 | Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| 33 | --- |
| 34 | |
| 35 | --- a/net/core/dev.c |
| 36 | +++ b/net/core/dev.c |
| 37 | @@ -6524,7 +6524,7 @@ static int napi_thread_wait(struct napi_ |
| 38 | |
| 39 | set_current_state(TASK_INTERRUPTIBLE); |
| 40 | |
| 41 | - while (!kthread_should_stop() && !napi_disable_pending(napi)) { |
| 42 | + while (!kthread_should_stop()) { |
| 43 | /* Testing SCHED_THREADED bit here to make sure the current |
| 44 | * kthread owns this napi and could poll on this napi. |
| 45 | * Testing SCHED bit is not enough because SCHED bit might be |
| 46 | @@ -6542,6 +6542,7 @@ static int napi_thread_wait(struct napi_ |
| 47 | set_current_state(TASK_INTERRUPTIBLE); |
| 48 | } |
| 49 | __set_current_state(TASK_RUNNING); |
| 50 | + |
| 51 | return -1; |
| 52 | } |
| 53 | |