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 6b5f43ea08
("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>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
412a75dc61
Коммит
0f158b32a9
|
@ -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)
|
||||||
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,
|
||||||
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 @@ done:
|
||||||
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:
|
||||||
|
|
Загрузка…
Ссылка в новой задаче