tcp: do not recycle cloned skbs

It is illegal to change arbitrary fields in skb_shared_info if the
skb is cloned.

Before calling skb_zcopy_clear() we need to ensure this rule,
therefore we need to move the test from sk_stream_alloc_skb()
to sk_wmem_free_skb()

Fixes: 4f661542a4 ("tcp: fix zerocopy and notsent_lowat issues")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Diagnosed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric Dumazet 2019-05-15 09:10:15 -07:00 committed by David S. Miller
parent 22fb43f360
commit 858f501744
2 changed files with 2 additions and 2 deletions

View File

@ -1473,7 +1473,7 @@ static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb)
sock_set_flag(sk, SOCK_QUEUE_SHRUNK); sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
sk->sk_wmem_queued -= skb->truesize; sk->sk_wmem_queued -= skb->truesize;
sk_mem_uncharge(sk, skb->truesize); sk_mem_uncharge(sk, skb->truesize);
if (!sk->sk_tx_skb_cache) { if (!sk->sk_tx_skb_cache && !skb_cloned(skb)) {
skb_zcopy_clear(skb, true); skb_zcopy_clear(skb, true);
sk->sk_tx_skb_cache = skb; sk->sk_tx_skb_cache = skb;
return; return;

View File

@ -855,7 +855,7 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp,
if (likely(!size)) { if (likely(!size)) {
skb = sk->sk_tx_skb_cache; skb = sk->sk_tx_skb_cache;
if (skb && !skb_cloned(skb)) { if (skb) {
skb->truesize = SKB_TRUESIZE(skb_end_offset(skb)); skb->truesize = SKB_TRUESIZE(skb_end_offset(skb));
sk->sk_tx_skb_cache = NULL; sk->sk_tx_skb_cache = NULL;
pskb_trim(skb, 0); pskb_trim(skb, 0);