aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2019-03-26 11:34:55 -0400
committerDavid S. Miller <davem@davemloft.net>2019-03-27 16:59:02 -0400
commit4f661542a40217713f2cee0bb6678fbb30d9d367 (patch)
tree8c49f8cb2bb8e14e76b8f912ec39659dc06cb4e5 /net/ipv4/tcp.c
parent4d5ec89fc8d14dcdab7214a0c13a1c7321dc6ea9 (diff)
tcp: fix zerocopy and notsent_lowat issues
My recent patch had at least three problems : 1) TX zerocopy wants notification when skb is acknowledged, thus we need to call skb_zcopy_clear() if the skb is cached into sk->sk_tx_skb_cache 2) Some applications might expect precise EPOLLOUT notifications, so we need to update sk->sk_wmem_queued and call sk_mem_uncharge() from sk_wmem_free_skb() in all cases. The SOCK_QUEUE_SHRUNK flag must also be set. 3) Reuse of saved skb should have used skb_cloned() instead of simply checking if the fast clone has been freed. Fixes: 472c2e07eef0 ("tcp: add one skb cache for tx") Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Willem de Bruijn <willemb@google.com> Cc: Soheil Hassas Yeganeh <soheil@google.com> Acked-by: Soheil Hassas Yeganeh <soheil@google.com> Tested-by: Holger Hoffstätte <holger@applied-asynchrony.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r--net/ipv4/tcp.c13
1 files changed, 3 insertions, 10 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 29b94edf05f9..82bd707c0347 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -865,14 +865,9 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp,
865{ 865{
866 struct sk_buff *skb; 866 struct sk_buff *skb;
867 867
868 skb = sk->sk_tx_skb_cache; 868 if (likely(!size)) {
869 if (skb && !size) { 869 skb = sk->sk_tx_skb_cache;
870 const struct sk_buff_fclones *fclones; 870 if (skb && !skb_cloned(skb)) {
871
872 fclones = container_of(skb, struct sk_buff_fclones, skb1);
873 if (refcount_read(&fclones->fclone_ref) == 1) {
874 sk->sk_wmem_queued -= skb->truesize;
875 sk_mem_uncharge(sk, skb->truesize);
876 skb->truesize -= skb->data_len; 871 skb->truesize -= skb->data_len;
877 sk->sk_tx_skb_cache = NULL; 872 sk->sk_tx_skb_cache = NULL;
878 pskb_trim(skb, 0); 873 pskb_trim(skb, 0);
@@ -2543,8 +2538,6 @@ void tcp_write_queue_purge(struct sock *sk)
2543 tcp_rtx_queue_purge(sk); 2538 tcp_rtx_queue_purge(sk);
2544 skb = sk->sk_tx_skb_cache; 2539 skb = sk->sk_tx_skb_cache;
2545 if (skb) { 2540 if (skb) {
2546 sk->sk_wmem_queued -= skb->truesize;
2547 sk_mem_uncharge(sk, skb->truesize);
2548 __kfree_skb(skb); 2541 __kfree_skb(skb);
2549 sk->sk_tx_skb_cache = NULL; 2542 sk->sk_tx_skb_cache = NULL;
2550 } 2543 }