diff options
author | Eric Dumazet <edumazet@google.com> | 2019-05-15 09:10:15 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-05-15 09:22:41 -0700 |
commit | 858f5017446764e8bca0b29589a3b164186ae471 (patch) | |
tree | 373f0ffe2041cc465d0c0582b27da70f6179d7ee | |
parent | 22fb43f36006a3d42b7ab34df0f14ded3d513eda (diff) | |
download | linux-858f5017446764e8bca0b29589a3b164186ae471.tar.gz linux-858f5017446764e8bca0b29589a3b164186ae471.tar.bz2 linux-858f5017446764e8bca0b29589a3b164186ae471.zip |
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: 4f661542a402 ("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>
-rw-r--r-- | include/net/sock.h | 2 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 2 |
2 files changed, 2 insertions, 2 deletions
diff --git a/include/net/sock.h b/include/net/sock.h index 4d208c0f9c14..0680fa988497 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -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); sk->sk_wmem_queued -= 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); sk->sk_tx_skb_cache = skb; return; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 1fa15beb8380..53d61ca3ac4b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -855,7 +855,7 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp, if (likely(!size)) { skb = sk->sk_tx_skb_cache; - if (skb && !skb_cloned(skb)) { + if (skb) { skb->truesize = SKB_TRUESIZE(skb_end_offset(skb)); sk->sk_tx_skb_cache = NULL; pskb_trim(skb, 0); |