Commit c73c3d9c authored by Alexander Duyck's avatar Alexander Duyck Committed by David S. Miller

tcp: Fix truesize accounting in tcp_try_coalesce

This patch addresses several issues in the way we were tracking the
truesize in tcp_try_coalesce.

First it was using ksize which prevents us from having a 0 sized head frag
and getting a usable result.  To resolve that this patch uses the end
pointer which is set based off either ksize, or the frag_size supplied in
build_skb.  This allows us to compute the original truesize of the entire
buffer and remove that value leaving us with just what was added as pages.

The second issue was the use of skb->len if there is a mergeable head frag.
We should only need to remove the size of an data aligned sk_buff from our
current skb->truesize to compute the delta for a buffer with a reused head.
By using skb->len the value of truesize was being artificially reduced
which means that head frags could use more memory than buffers using
standard allocations.
Signed-off-by: default avatarAlexander Duyck <alexander.h.duyck@intel.com>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Acked-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8c1ae10d
...@@ -4565,12 +4565,10 @@ static bool tcp_try_coalesce(struct sock *sk, ...@@ -4565,12 +4565,10 @@ static bool tcp_try_coalesce(struct sock *sk,
if (skb_headlen(from) == 0 && if (skb_headlen(from) == 0 &&
(skb_shinfo(to)->nr_frags + (skb_shinfo(to)->nr_frags +
skb_shinfo(from)->nr_frags <= MAX_SKB_FRAGS)) { skb_shinfo(from)->nr_frags <= MAX_SKB_FRAGS)) {
WARN_ON_ONCE(from->head_frag); delta = from->truesize -
delta = from->truesize - ksize(from->head) - SKB_TRUESIZE(skb_end_pointer(from) - from->head);
SKB_DATA_ALIGN(sizeof(struct sk_buff));
WARN_ON_ONCE(delta < len);
copyfrags: copyfrags:
WARN_ON_ONCE(delta < len);
memcpy(skb_shinfo(to)->frags + skb_shinfo(to)->nr_frags, memcpy(skb_shinfo(to)->frags + skb_shinfo(to)->nr_frags,
skb_shinfo(from)->frags, skb_shinfo(from)->frags,
skb_shinfo(from)->nr_frags * sizeof(skb_frag_t)); skb_shinfo(from)->nr_frags * sizeof(skb_frag_t));
...@@ -4600,7 +4598,7 @@ static bool tcp_try_coalesce(struct sock *sk, ...@@ -4600,7 +4598,7 @@ static bool tcp_try_coalesce(struct sock *sk,
skb_fill_page_desc(to, skb_shinfo(to)->nr_frags, skb_fill_page_desc(to, skb_shinfo(to)->nr_frags,
page, offset, skb_headlen(from)); page, offset, skb_headlen(from));
*fragstolen = true; *fragstolen = true;
delta = len; /* we dont know real truesize... */ delta = from->truesize - SKB_DATA_ALIGN(sizeof(struct sk_buff));
goto copyfrags; goto copyfrags;
} }
return false; return false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment