diff mbox series

[net-next] net: selectively purge error queue in IP_RECVERR / IPV6_RECVERR

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

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 6393 this patch: 6393
netdev/cc_maintainers warning 1 maintainers not CCed: dsahern@kernel.org
netdev/build_clang success Errors and warnings before: 3297 this patch: 3297
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 6641 this patch: 6641
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 50 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Eric Dumazet Aug. 18, 2023, 5:41 p.m. UTC
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(-)

Comments

Willem de Bruijn Aug. 18, 2023, 6:04 p.m. UTC | #1
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 mbox series

Patch

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: