@@ -98,6 +98,7 @@ struct page {
#ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS
unsigned long debug_flags; /* Use atomic bitops on this */
#endif
+ unsigned long _pad; /* so that sizeof(struct page) is 64 bytes */
};
/*
@@ -2660,28 +2660,37 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
struct sk_buff *nskb;
unsigned int headroom;
unsigned int len = skb_gro_len(skb);
+ int delta;
+ struct skb_shared_info *skb_shinfo_p = skb_shinfo(p);
if (p->len + len >= 65536)
return -E2BIG;
- if (skb_shinfo(p)->frag_list)
+ delta = skb_gro_offset(skb) - skb_headlen(skb);
+ if (skb_shinfo_p->frag_list)
goto merge;
- else if (skb_headlen(skb) <= skb_gro_offset(skb)) {
- if (skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags >
+ if (delta >= 0) {
+ struct skb_shared_info *skb_shinfo_skb = skb_shinfo(skb);
+
+ if (skb_shinfo_p->nr_frags + skb_shinfo_skb->nr_frags >
MAX_SKB_FRAGS)
return -E2BIG;
- skb_shinfo(skb)->frags[0].page_offset +=
- skb_gro_offset(skb) - skb_headlen(skb);
- skb_shinfo(skb)->frags[0].size -=
- skb_gro_offset(skb) - skb_headlen(skb);
-
- memcpy(skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags,
- skb_shinfo(skb)->frags,
- skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t));
+ skb_shinfo_skb->frags[0].page_offset += delta;
+ skb_shinfo_skb->frags[0].size -= delta;
- skb_shinfo(p)->nr_frags += skb_shinfo(skb)->nr_frags;
- skb_shinfo(skb)->nr_frags = 0;
+ if (likely(skb_shinfo_skb->nr_frags == 1)) {
+ memcpy(skb_shinfo_p->frags + skb_shinfo_p->nr_frags,
+ skb_shinfo_skb->frags,
+ sizeof(skb_frag_t));
+ skb_shinfo_p->nr_frags += 1;
+ } else {
+ memcpy(skb_shinfo_p->frags + skb_shinfo_p->nr_frags,
+ skb_shinfo_skb->frags,
+ skb_shinfo_skb->nr_frags * sizeof(skb_frag_t));
+ skb_shinfo_p->nr_frags += skb_shinfo_skb->nr_frags;
+ }
+ skb_shinfo_skb->nr_frags = 0;
skb->truesize -= skb->data_len;
skb->len -= skb->data_len;
@@ -2726,12 +2735,11 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
p = nskb;
+ delta = skb_gro_offset(skb) - skb_headlen(skb);
merge:
- if (skb_gro_offset(skb) > skb_headlen(skb)) {
- skb_shinfo(skb)->frags[0].page_offset +=
- skb_gro_offset(skb) - skb_headlen(skb);
- skb_shinfo(skb)->frags[0].size -=
- skb_gro_offset(skb) - skb_headlen(skb);
+ if (delta > 0) {
+ skb_shinfo(skb)->frags[0].page_offset += delta;
+ skb_shinfo(skb)->frags[0].size -= delta;
skb_gro_reset_offset(skb);
skb_gro_pull(skb, skb_headlen(skb));
}