aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2012-05-02 19:33:21 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-03 13:18:37 -0400
commit715dc1f342713816d1be1c37643a2c9e6ee181a7 (patch)
tree493d46be738d5cacba3ba110c2aa35e58e53cb93 /net/core
parentaf94bf6db1d58d26f1cdab145b6312ad363254a6 (diff)
net: Fix truesize accounting in skb_gro_receive()
GRO is very optimistic in skb truesize estimates, only taking into account the used part of fragments. Be conservative, and use more precise computation, so that bloated GRO skbs can be collapsed eventually. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Alexander Duyck <alexander.h.duyck@intel.com> Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Acked-by: Alexander Duyck <alexander.h.duyck@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/skbuff.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 9e8caa0c4f7..e1f8bbaadf5 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2871,6 +2871,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
2871 unsigned int len = skb_gro_len(skb); 2871 unsigned int len = skb_gro_len(skb);
2872 unsigned int offset = skb_gro_offset(skb); 2872 unsigned int offset = skb_gro_offset(skb);
2873 unsigned int headlen = skb_headlen(skb); 2873 unsigned int headlen = skb_headlen(skb);
2874 unsigned int delta_truesize;
2874 2875
2875 if (p->len + len >= 65536) 2876 if (p->len + len >= 65536)
2876 return -E2BIG; 2877 return -E2BIG;
@@ -2900,11 +2901,14 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
2900 frag->page_offset += offset; 2901 frag->page_offset += offset;
2901 skb_frag_size_sub(frag, offset); 2902 skb_frag_size_sub(frag, offset);
2902 2903
2904 /* all fragments truesize : remove (head size + sk_buff) */
2905 delta_truesize = skb->truesize - SKB_TRUESIZE(skb_end_pointer(skb) - skb->head);
2906
2903 skb->truesize -= skb->data_len; 2907 skb->truesize -= skb->data_len;
2904 skb->len -= skb->data_len; 2908 skb->len -= skb->data_len;
2905 skb->data_len = 0; 2909 skb->data_len = 0;
2906 2910
2907 NAPI_GRO_CB(skb)->free = 1; 2911 NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE;
2908 goto done; 2912 goto done;
2909 } else if (skb->head_frag) { 2913 } else if (skb->head_frag) {
2910 int nr_frags = pinfo->nr_frags; 2914 int nr_frags = pinfo->nr_frags;
@@ -2929,6 +2933,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
2929 memcpy(frag + 1, skbinfo->frags, sizeof(*frag) * skbinfo->nr_frags); 2933 memcpy(frag + 1, skbinfo->frags, sizeof(*frag) * skbinfo->nr_frags);
2930 /* We dont need to clear skbinfo->nr_frags here */ 2934 /* We dont need to clear skbinfo->nr_frags here */
2931 2935
2936 delta_truesize = skb->truesize - SKB_DATA_ALIGN(sizeof(struct sk_buff));
2932 NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE_STOLEN_HEAD; 2937 NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE_STOLEN_HEAD;
2933 goto done; 2938 goto done;
2934 } else if (skb_gro_len(p) != pinfo->gso_size) 2939 } else if (skb_gro_len(p) != pinfo->gso_size)
@@ -2971,7 +2976,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
2971 p = nskb; 2976 p = nskb;
2972 2977
2973merge: 2978merge:
2974 p->truesize += skb->truesize - len; 2979 delta_truesize = skb->truesize;
2975 if (offset > headlen) { 2980 if (offset > headlen) {
2976 unsigned int eat = offset - headlen; 2981 unsigned int eat = offset - headlen;
2977 2982
@@ -2991,7 +2996,7 @@ merge:
2991done: 2996done:
2992 NAPI_GRO_CB(p)->count++; 2997 NAPI_GRO_CB(p)->count++;
2993 p->data_len += len; 2998 p->data_len += len;
2994 p->truesize += len; 2999 p->truesize += delta_truesize;
2995 p->len += len; 3000 p->len += len;
2996 3001
2997 NAPI_GRO_CB(skb)->same_flow = 1; 3002 NAPI_GRO_CB(skb)->same_flow = 1;