blob: a9e299ac14318e2680756b582a9ae116d02f3163 [file] [log] [blame]
From fb93134dfc2a6e6fbedc7c270a31da03fce88db9 Mon Sep 17 00:00:00 2001
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Wed, 14 Nov 2007 15:45:21 -0800
To: Greg KH <greg@kroah.com>
Subject: TCP: Fix size calculation in sk_stream_alloc_pskb
From: Herbert Xu <herbert@gondor.apana.org.au>
[TCP]: Fix size calculation in sk_stream_alloc_pskb
[ Upstream commit: fb93134dfc2a6e6fbedc7c270a31da03fce88db9 ]
We round up the header size in sk_stream_alloc_pskb so that
TSO packets get zero tail room. Unfortunately this rounding
up is not coordinated with the select_size() function used by
TCP to calculate the second parameter of sk_stream_alloc_pskb.
As a result, we may allocate more than a page of data in the
non-TSO case when exactly one page is desired.
In fact, rounding up the head room is detrimental in the non-TSO
case because it makes memory that would otherwise be available to
the payload head room. TSO doesn't need this either, all it wants
is the guarantee that there is no tail room.
So this patch fixes this by adjusting the skb_reserve call so that
exactly the requested amount (which all callers have calculated in
a precise way) is made available as tail room.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
include/net/sock.h | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1199,14 +1199,16 @@ static inline struct sk_buff *sk_stream_
gfp_t gfp)
{
struct sk_buff *skb;
- int hdr_len;
- hdr_len = SKB_DATA_ALIGN(sk->sk_prot->max_header);
- skb = alloc_skb_fclone(size + hdr_len, gfp);
+ skb = alloc_skb_fclone(size + sk->sk_prot->max_header, gfp);
if (skb) {
skb->truesize += mem;
if (sk_stream_wmem_schedule(sk, skb->truesize)) {
- skb_reserve(skb, hdr_len);
+ /*
+ * Make sure that we have exactly size bytes
+ * available to the caller, no more, no less.
+ */
+ skb_reserve(skb, skb_tailroom(skb) - size);
return skb;
}
__kfree_skb(skb);