Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / net / core / skbuff.c
index 104f844..19d6c21 100644 (file)
@@ -778,6 +778,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 +813,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 +827,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 +1824,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);