| 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); |