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:
parent
22fb43f360
commit
858f501744
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue