]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/core/skbuff.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / net / core / skbuff.c
index 104f8444754aa160fe7922458980ddb57485a2a5..d883dcc78b6b6f10bfa3554fbba654c98526616d 100644 (file)
@@ -210,6 +210,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
        shinfo = skb_shinfo(skb);
        memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
        atomic_set(&shinfo->dataref, 1);
+       kmemcheck_annotate_variable(shinfo->destructor_arg);
 
        if (fclone) {
                struct sk_buff *child = skb + 1;
@@ -380,6 +381,8 @@ static void skb_release_head_state(struct sk_buff *skb)
        }
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        nf_conntrack_put(skb->nfct);
+#endif
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
        nf_conntrack_put_reasm(skb->nfct_reasm);
 #endif
 #ifdef CONFIG_BRIDGE_NETFILTER
@@ -778,6 +781,28 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 
        size = SKB_DATA_ALIGN(size);
 
+       /* Check if we can avoid taking references on fragments if we own
+        * the last reference on skb->head. (see skb_release_data())
+        */
+       if (!skb->cloned)
+               fastpath = true;
+       else {
+               int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
+
+               fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
+       }
+
+       if (fastpath &&
+           size + sizeof(struct skb_shared_info) <= ksize(skb->head)) {
+               memmove(skb->head + size, skb_shinfo(skb),
+                       offsetof(struct skb_shared_info,
+                                frags[skb_shinfo(skb)->nr_frags]));
+               memmove(skb->head + nhead, skb->head,
+                       skb_tail_pointer(skb) - skb->head);
+               off = nhead;
+               goto adjust_others;
+       }
+
        data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
        if (!data)
                goto nodata;
@@ -791,17 +816,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
               skb_shinfo(skb),
               offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));
 
-       /* Check if we can avoid taking references on fragments if we own
-        * the last reference on skb->head. (see skb_release_data())
-        */
-       if (!skb->cloned)
-               fastpath = true;
-       else {
-               int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
-
-               fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
-       }
-
        if (fastpath) {
                kfree(skb->head);
        } else {
@@ -816,6 +830,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
        off = (data + nhead) - skb->head;
 
        skb->head     = data;
+adjust_others:
        skb->data    += off;
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
        skb->end      = size;
@@ -1812,7 +1827,7 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
        long csstart;
 
        if (skb->ip_summed == CHECKSUM_PARTIAL)
-               csstart = skb->csum_start - skb_headroom(skb);
+               csstart = skb_checksum_start_offset(skb);
        else
                csstart = skb_headlen(skb);
 
@@ -2730,8 +2745,12 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
 
 merge:
        if (offset > headlen) {
-               skbinfo->frags[0].page_offset += offset - headlen;
-               skbinfo->frags[0].size -= offset - headlen;
+               unsigned int eat = offset - headlen;
+
+               skbinfo->frags[0].page_offset += eat;
+               skbinfo->frags[0].size -= eat;
+               skb->data_len -= eat;
+               skb->len -= eat;
                offset = headlen;
        }