Commit 0f158b32 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

net: selectively purge error queue in IP_RECVERR / IPV6_RECVERR

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 6b5f43ea
("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: default avatarEric Dumazet <edumazet@google.com>
Cc: Willem de Bruijn <willemb@google.com>
Cc: Soheil Hassas Yeganeh <soheil@google.com>
Reviewed-by: default avatarWillem de Bruijn <willemb@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 412a75dc
...@@ -3180,6 +3180,7 @@ static inline void skb_queue_purge(struct sk_buff_head *list) ...@@ -3180,6 +3180,7 @@ static inline void skb_queue_purge(struct sk_buff_head *list)
} }
unsigned int skb_rbtree_purge(struct rb_root *root); 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); void *__netdev_alloc_frag_align(unsigned int fragsz, unsigned int align_mask);
......
...@@ -3745,6 +3745,27 @@ unsigned int skb_rbtree_purge(struct rb_root *root) ...@@ -3745,6 +3745,27 @@ unsigned int skb_rbtree_purge(struct rb_root *root)
return sum; 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 * skb_queue_head - queue a buffer at the list head
* @list: list to use * @list: list to use
......
...@@ -976,7 +976,7 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, ...@@ -976,7 +976,7 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname,
case IP_RECVERR: case IP_RECVERR:
inet_assign_bit(RECVERR, sk, val); inet_assign_bit(RECVERR, sk, val);
if (!val) if (!val)
skb_queue_purge(&sk->sk_error_queue); skb_errqueue_purge(&sk->sk_error_queue);
return 0; return 0;
case IP_RECVERR_RFC4884: case IP_RECVERR_RFC4884:
if (val < 0 || val > 1) if (val < 0 || val > 1)
......
...@@ -923,7 +923,7 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -923,7 +923,7 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
goto e_inval; goto e_inval;
np->recverr = valbool; np->recverr = valbool;
if (!val) if (!val)
skb_queue_purge(&sk->sk_error_queue); skb_errqueue_purge(&sk->sk_error_queue);
retv = 0; retv = 0;
break; break;
case IPV6_FLOWINFO_SEND: case IPV6_FLOWINFO_SEND:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment