--- /dev/null
+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);