Message ID | 20230818174145.199194-1-edumazet@google.com (mailing list archive) |
---|---|
State | Not Applicable |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [net-next] net: selectively purge error queue in IP_RECVERR / IPV6_RECVERR | expand |
Eric Dumazet wrote: > Setting IP_RECVERR and IPV6_RECVERR options to zero currently > purges the socket error queue, which was probably not expected > for zerocopy and tx_timestamp users. > > I discovered this issue while preparing commit 6b5f43ea0815 > ("inet: move inet->recverr to inet->inet_flags"), I presume this > change does not need to be backported to stable kernels. > > Add skb_errqueue_purge() helper to purge error messages only. > > Signed-off-by: Eric Dumazet <edumazet@google.com> > Cc: Willem de Bruijn <willemb@google.com> > Cc: Soheil Hassas Yeganeh <soheil@google.com> Reviewed-by: Willem de Bruijn <willemb@google.com>
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index aa57e2eca33be01d6d1d55297a8ffcdb5b6a1f55..9a8200c7a0c3124d78e95f9524b854043a6fd368 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3165,6 +3165,7 @@ static inline void __skb_queue_purge(struct sk_buff_head *list) void skb_queue_purge(struct sk_buff_head *list); unsigned int skb_rbtree_purge(struct rb_root *root); +void skb_errqueue_purge(struct sk_buff_head *list); void *__netdev_alloc_frag_align(unsigned int fragsz, unsigned int align_mask); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 33fdf04d4334dd71481bc1ecf7c131aff8f18826..e2ece6b822f442079c1ea20cdd5f6d0dc27ba8a5 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3742,6 +3742,27 @@ unsigned int skb_rbtree_purge(struct rb_root *root) return sum; } +void skb_errqueue_purge(struct sk_buff_head *list) +{ + struct sk_buff *skb, *next; + struct sk_buff_head kill; + unsigned long flags; + + __skb_queue_head_init(&kill); + + spin_lock_irqsave(&list->lock, flags); + skb_queue_walk_safe(list, skb, next) { + if (SKB_EXT_ERR(skb)->ee.ee_origin == SO_EE_ORIGIN_ZEROCOPY || + SKB_EXT_ERR(skb)->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) + continue; + __skb_unlink(skb, list); + __skb_queue_tail(&kill, skb); + } + spin_unlock_irqrestore(&list->lock, flags); + __skb_queue_purge(&kill); +} +EXPORT_SYMBOL(skb_errqueue_purge); + /** * skb_queue_head - queue a buffer at the list head * @list: list to use diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 61b2e7bc7031501ff5a3ebeffc3f90be180fa09e..54ad0f0d5c2dd2273f290de5693060a2cb185534 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -976,7 +976,7 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, case IP_RECVERR: inet_assign_bit(RECVERR, sk, val); if (!val) - skb_queue_purge(&sk->sk_error_queue); + skb_errqueue_purge(&sk->sk_error_queue); return 0; case IP_RECVERR_RFC4884: if (val < 0 || val > 1) diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index d19577a94bcc6120e85dafb2768521e6567c0511..0e2a0847b387f0f6f50211b89f92ac1e00a0b07a 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -923,7 +923,7 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname, goto e_inval; np->recverr = valbool; if (!val) - skb_queue_purge(&sk->sk_error_queue); + skb_errqueue_purge(&sk->sk_error_queue); retv = 0; break; case IPV6_FLOWINFO_SEND:
Setting IP_RECVERR and IPV6_RECVERR options to zero currently purges the socket error queue, which was probably not expected for zerocopy and tx_timestamp users. I discovered this issue while preparing commit 6b5f43ea0815 ("inet: move inet->recverr to inet->inet_flags"), I presume this change does not need to be backported to stable kernels. Add skb_errqueue_purge() helper to purge error messages only. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Willem de Bruijn <willemb@google.com> Cc: Soheil Hassas Yeganeh <soheil@google.com> --- include/linux/skbuff.h | 1 + net/core/skbuff.c | 21 +++++++++++++++++++++ net/ipv4/ip_sockglue.c | 2 +- net/ipv6/ipv6_sockglue.c | 2 +- 4 files changed, 24 insertions(+), 2 deletions(-)