net: fix sk_forward_alloc corruptions
[pandora-kernel.git] / net / core / skbuff.c
index bdea0ef..f2913ae 100644 (file)
@@ -117,7 +117,7 @@ static const struct pipe_buf_operations sock_pipe_buf_ops = {
  *
  *     Out of line support code for skb_put(). Not user callable.
  */
-void skb_over_panic(struct sk_buff *skb, int sz, void *here)
+static void skb_over_panic(struct sk_buff *skb, int sz, void *here)
 {
        printk(KERN_EMERG "skb_over_panic: text:%p len:%d put:%d head:%p "
                          "data:%p tail:%#lx end:%#lx dev:%s\n",
@@ -126,7 +126,6 @@ void skb_over_panic(struct sk_buff *skb, int sz, void *here)
               skb->dev ? skb->dev->name : "<NULL>");
        BUG();
 }
-EXPORT_SYMBOL(skb_over_panic);
 
 /**
  *     skb_under_panic -       private function
@@ -137,7 +136,7 @@ EXPORT_SYMBOL(skb_over_panic);
  *     Out of line support code for skb_push(). Not user callable.
  */
 
-void skb_under_panic(struct sk_buff *skb, int sz, void *here)
+static void skb_under_panic(struct sk_buff *skb, int sz, void *here)
 {
        printk(KERN_EMERG "skb_under_panic: text:%p len:%d put:%d head:%p "
                          "data:%p tail:%#lx end:%#lx dev:%s\n",
@@ -146,7 +145,6 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here)
               skb->dev ? skb->dev->name : "<NULL>");
        BUG();
 }
-EXPORT_SYMBOL(skb_under_panic);
 
 /*     Allocate a new skbuff. We do this ourselves so we can fill in a few
  *     'private' fields and also do memory statistics to find all the
@@ -183,12 +181,14 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
        skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);
        if (!skb)
                goto out;
+       prefetchw(skb);
 
        size = SKB_DATA_ALIGN(size);
        data = kmalloc_node_track_caller(size + sizeof(struct skb_shared_info),
                        gfp_mask, node);
        if (!data)
                goto nodata;
+       prefetchw(data + size);
 
        /*
         * Only clear those fields we need to clear, not those that we will
@@ -210,15 +210,8 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
 
        /* make sure we initialize shinfo sequentially */
        shinfo = skb_shinfo(skb);
+       memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
        atomic_set(&shinfo->dataref, 1);
-       shinfo->nr_frags  = 0;
-       shinfo->gso_size = 0;
-       shinfo->gso_segs = 0;
-       shinfo->gso_type = 0;
-       shinfo->ip6_frag_id = 0;
-       shinfo->tx_flags.flags = 0;
-       skb_frag_list_init(skb);
-       memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps));
 
        if (fclone) {
                struct sk_buff *child = skb + 1;
@@ -489,40 +482,34 @@ EXPORT_SYMBOL(consume_skb);
  *     reference count dropping and cleans up the skbuff as if it
  *     just came from __alloc_skb().
  */
-int skb_recycle_check(struct sk_buff *skb, int skb_size)
+bool skb_recycle_check(struct sk_buff *skb, int skb_size)
 {
        struct skb_shared_info *shinfo;
 
        if (irqs_disabled())
-               return 0;
+               return false;
 
        if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE)
-               return 0;
+               return false;
 
        skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD);
        if (skb_end_pointer(skb) - skb->head < skb_size)
-               return 0;
+               return false;
 
        if (skb_shared(skb) || skb_cloned(skb))
-               return 0;
+               return false;
 
        skb_release_head_state(skb);
+
        shinfo = skb_shinfo(skb);
+       memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
        atomic_set(&shinfo->dataref, 1);
-       shinfo->nr_frags = 0;
-       shinfo->gso_size = 0;
-       shinfo->gso_segs = 0;
-       shinfo->gso_type = 0;
-       shinfo->ip6_frag_id = 0;
-       shinfo->tx_flags.flags = 0;
-       skb_frag_list_init(skb);
-       memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps));
 
        memset(skb, 0, offsetof(struct sk_buff, tail));
        skb->data = skb->head + NET_SKB_PAD;
        skb_reset_tail_pointer(skb);
 
-       return 1;
+       return true;
 }
 EXPORT_SYMBOL(skb_recycle_check);
 
@@ -533,7 +520,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->transport_header   = old->transport_header;
        new->network_header     = old->network_header;
        new->mac_header         = old->mac_header;
-       skb_dst_set(new, dst_clone(skb_dst(old)));
+       skb_dst_copy(new, old);
        new->rxhash             = old->rxhash;
 #ifdef CONFIG_XFRM
        new->sp                 = secpath_get(old->sp);
@@ -1053,7 +1040,7 @@ EXPORT_SYMBOL(skb_push);
  */
 unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)
 {
-       return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len);
+       return skb_pull_inline(skb, len);
 }
 EXPORT_SYMBOL(skb_pull);
 
@@ -2731,6 +2718,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
        *NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p);
        skb_shinfo(nskb)->frag_list = p;
        skb_shinfo(nskb)->gso_size = pinfo->gso_size;
+       pinfo->gso_size = 0;
        skb_header_release(p);
        nskb->prev = p;
 
@@ -3004,7 +2992,11 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
        memset(serr, 0, sizeof(*serr));
        serr->ee.ee_errno = ENOMSG;
        serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
+
+       bh_lock_sock(sk);
        err = sock_queue_err_skb(sk, skb);
+       bh_unlock_sock(sk);
+
        if (err)
                kfree_skb(skb);
 }