aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_input.c
diff options
context:
space:
mode:
authorAlexander Duyck <alexander.h.duyck@intel.com>2012-05-02 17:18:59 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-03 04:21:33 -0400
commitc73c3d9c49daae8acbac4cd14bcd81626887c0e6 (patch)
treeb38ef55d8b2cd88a1e02ee9d990c89071edf136c /net/ipv4/tcp_input.c
parent8c1ae10d792155a7221be12b37dcebc3bcc1b49f (diff)
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: Alexander Duyck <alexander.h.duyck@intel.com> Cc: Eric Dumazet <edumazet@google.com> Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r--net/ipv4/tcp_input.c10
1 files changed, 4 insertions, 6 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index c6f78e2b590f..3cb273ac8821 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4565,12 +4565,10 @@ merge:
4565 if (skb_headlen(from) == 0 && 4565 if (skb_headlen(from) == 0 &&
4566 (skb_shinfo(to)->nr_frags + 4566 (skb_shinfo(to)->nr_frags +
4567 skb_shinfo(from)->nr_frags <= MAX_SKB_FRAGS)) { 4567 skb_shinfo(from)->nr_frags <= MAX_SKB_FRAGS)) {
4568 WARN_ON_ONCE(from->head_frag); 4568 delta = from->truesize -
4569 delta = from->truesize - ksize(from->head) - 4569 SKB_TRUESIZE(skb_end_pointer(from) - from->head);
4570 SKB_DATA_ALIGN(sizeof(struct sk_buff));
4571
4572 WARN_ON_ONCE(delta < len);
4573copyfrags: 4570copyfrags:
4571 WARN_ON_ONCE(delta < len);
4574 memcpy(skb_shinfo(to)->frags + skb_shinfo(to)->nr_frags, 4572 memcpy(skb_shinfo(to)->frags + skb_shinfo(to)->nr_frags,
4575 skb_shinfo(from)->frags, 4573 skb_shinfo(from)->frags,
4576 skb_shinfo(from)->nr_frags * sizeof(skb_frag_t)); 4574 skb_shinfo(from)->nr_frags * sizeof(skb_frag_t));
@@ -4600,7 +4598,7 @@ copyfrags:
4600 skb_fill_page_desc(to, skb_shinfo(to)->nr_frags, 4598 skb_fill_page_desc(to, skb_shinfo(to)->nr_frags,
4601 page, offset, skb_headlen(from)); 4599 page, offset, skb_headlen(from));
4602 *fragstolen = true; 4600 *fragstolen = true;
4603 delta = len; /* we dont know real truesize... */ 4601 delta = from->truesize - SKB_DATA_ALIGN(sizeof(struct sk_buff));
4604 goto copyfrags; 4602 goto copyfrags;
4605 } 4603 }
4606 return false; 4604 return false;