aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2022-05-18 11:55:22 -0700
committerJakub Kicinski <kuba@kernel.org>2022-05-20 17:05:36 -0700
commitc09b0cd2cc6c3f91988a20d45fa45c889f72c56c (patch)
tree16ea16ba1844e45c17fce73d9cb911ec2d7de338 /net/core
parentsfc/siena: Remove duplicate check on segments (diff)
downloadlinux-dev-c09b0cd2cc6c3f91988a20d45fa45c889f72c56c.tar.xz
linux-dev-c09b0cd2cc6c3f91988a20d45fa45c889f72c56c.zip
net: avoid strange behavior with skb_defer_max == 1
When user sets skb_defer_max to 1 the kick threshold is 0 (half of 1). If we increment queue length before the check the kick will never happen, and the skb may get stranded. This is likely harmless but can be avoided by moving the increment after the check. This way skb_defer_max == 1 will always kick. Still a silly config to have, but somehow that feels more correct. While at it drop a comment which seems to be outdated or confusing, and wrap the defer_count write with a WRITE_ONCE() since it's read on the fast path that avoids taking the lock. Reviewed-by: Eric Dumazet <edumazet@google.com> Link: https://lore.kernel.org/r/20220518185522.2038683-1-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/skbuff.c13
1 files changed, 5 insertions, 8 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 1d10bb4adec1..5b3559cb1d82 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -6512,18 +6512,15 @@ nodefer: __kfree_skb(skb);
if (READ_ONCE(sd->defer_count) >= defer_max)
goto nodefer;
- /* We do not send an IPI or any signal.
- * Remote cpu will eventually call skb_defer_free_flush()
- */
spin_lock_irqsave(&sd->defer_lock, flags);
- skb->next = sd->defer_list;
- /* Paired with READ_ONCE() in skb_defer_free_flush() */
- WRITE_ONCE(sd->defer_list, skb);
- sd->defer_count++;
-
/* Send an IPI every time queue reaches half capacity. */
kick = sd->defer_count == (defer_max >> 1);
+ /* Paired with the READ_ONCE() few lines above */
+ WRITE_ONCE(sd->defer_count, sd->defer_count + 1);
+ skb->next = sd->defer_list;
+ /* Paired with READ_ONCE() in skb_defer_free_flush() */
+ WRITE_ONCE(sd->defer_list, skb);
spin_unlock_irqrestore(&sd->defer_lock, flags);
/* Make sure to trigger NET_RX_SOFTIRQ on the remote CPU