Message ID | 20211110195605.1304-1-alexandr.lobakin@intel.com (mailing list archive) |
---|---|
State | Accepted |
Commit | 0315a075f1343966ea2d9a085666a88a69ea6a3d |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [v2,net] net: fix premature exit from NAPI state polling in napi_disable() | expand |
On Wed, Nov 10, 2021 at 11:56 AM Alexander Lobakin <alexandr.lobakin@intel.com> wrote: > > Commit 719c57197010 ("net: make napi_disable() symmetric with > enable") accidentally introduced a bug sometimes leading to a kernel > BUG when bringing an iface up/down under heavy traffic load. > > Prior to this commit, napi_disable() was polling n->state until > none of (NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC) is set and then > always flip them. Now there's a possibility to get away with the > NAPIF_STATE_SCHE unset as 'continue' drops us to the cmpxchg() > call with an unitialized variable, rather than straight to > another round of the state check. > ... > > [0] https://lore.kernel.org/netdev/20211110191126.1214-1-alexandr.lobakin@intel.com > > Fixes: 719c57197010 ("net: make napi_disable() symmetric with enable") > Suggested-by: Eric Dumazet <edumazet@google.com> # for-loop > Signed-off-by: Alexander Lobakin <alexandr.lobakin@intel.com> > Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com> > --- Thanks a lot ! Reviewed-by: Eric Dumazet <edumazet@google.com>
Hello: This patch was applied to netdev/net.git (master) by Jakub Kicinski <kuba@kernel.org>: On Wed, 10 Nov 2021 20:56:05 +0100 you wrote: > Commit 719c57197010 ("net: make napi_disable() symmetric with > enable") accidentally introduced a bug sometimes leading to a kernel > BUG when bringing an iface up/down under heavy traffic load. > > Prior to this commit, napi_disable() was polling n->state until > none of (NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC) is set and then > always flip them. Now there's a possibility to get away with the > NAPIF_STATE_SCHE unset as 'continue' drops us to the cmpxchg() > call with an unitialized variable, rather than straight to > another round of the state check. > > [...] Here is the summary with links: - [v2,net] net: fix premature exit from NAPI state polling in napi_disable() https://git.kernel.org/netdev/net/c/0315a075f134 You are awesome, thank you!
Alexander Lobakin [alexandr.lobakin@intel.com] wrote: > Commit 719c57197010 ("net: make napi_disable() symmetric with > enable") accidentally introduced a bug sometimes leading to a kernel > BUG when bringing an iface up/down under heavy traffic load. > > Prior to this commit, napi_disable() was polling n->state until > none of (NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC) is set and then > always flip them. Now there's a possibility to get away with the > NAPIF_STATE_SCHE unset as 'continue' drops us to the cmpxchg() > call with an unitialized variable, rather than straight to > another round of the state check. Thanks. Tested v1 and it fixes the problem discussed at: https://lore.kernel.org/netdev/dc6902364a8f91c4292fe1c5e01b24be@imap.linux.ibm.com/ Sukadev
diff --git a/net/core/dev.c b/net/core/dev.c index edeb811c454e..15ac064b5562 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6928,7 +6928,7 @@ void napi_disable(struct napi_struct *n) might_sleep(); set_bit(NAPI_STATE_DISABLE, &n->state); - do { + for ( ; ; ) { val = READ_ONCE(n->state); if (val & (NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC)) { usleep_range(20, 200); @@ -6937,7 +6937,10 @@ void napi_disable(struct napi_struct *n) new = val | NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC; new &= ~(NAPIF_STATE_THREADED | NAPIF_STATE_PREFER_BUSY_POLL); - } while (cmpxchg(&n->state, val, new) != val); + + if (cmpxchg(&n->state, val, new) == val) + break; + } hrtimer_cancel(&n->timer);