]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/core/skbuff.c
net: add skb_recycle_check() to enable netdriver skb recycling
[linux-2.6-omap-h63xx.git] / net / core / skbuff.c
index 4e0c922741897eb1ad158880ea9cb96f692894fe..2c218a0808b4d5fa0a09e90ae8edac6c2b27affe 100644 (file)
@@ -363,8 +363,7 @@ static void kfree_skbmem(struct sk_buff *skb)
        }
 }
 
-/* Free everything but the sk_buff shell. */
-static void skb_release_all(struct sk_buff *skb)
+static void skb_release_head_state(struct sk_buff *skb)
 {
        dst_release(skb->dst);
 #ifdef CONFIG_XFRM
@@ -388,6 +387,12 @@ static void skb_release_all(struct sk_buff *skb)
        skb->tc_verd = 0;
 #endif
 #endif
+}
+
+/* Free everything but the sk_buff shell. */
+static void skb_release_all(struct sk_buff *skb)
+{
+       skb_release_head_state(skb);
        skb_release_data(skb);
 }
 
@@ -424,6 +429,38 @@ void kfree_skb(struct sk_buff *skb)
        __kfree_skb(skb);
 }
 
+int skb_recycle_check(struct sk_buff *skb, int skb_size)
+{
+       struct skb_shared_info *shinfo;
+
+       if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE)
+               return 0;
+
+       skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD);
+       if (skb_end_pointer(skb) - skb->head < skb_size)
+               return 0;
+
+       if (skb_shared(skb) || skb_cloned(skb))
+               return 0;
+
+       skb_release_head_state(skb);
+       shinfo = skb_shinfo(skb);
+       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->frag_list = NULL;
+
+       memset(skb, 0, offsetof(struct sk_buff, tail));
+       skb_reset_tail_pointer(skb);
+       skb->data = skb->head + NET_SKB_PAD;
+
+       return 1;
+}
+EXPORT_SYMBOL(skb_recycle_check);
+
 static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 {
        new->tstamp             = old->tstamp;
@@ -485,6 +522,9 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
        C(head);
        C(data);
        C(truesize);
+#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
+       C(do_not_encrypt);
+#endif
        atomic_set(&n->users, 1);
 
        atomic_inc(&(skb_shinfo(skb)->dataref));
@@ -2253,14 +2293,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
                        segs = nskb;
                tail = nskb;
 
-               nskb->dev = skb->dev;
-               skb_copy_queue_mapping(nskb, skb);
-               nskb->priority = skb->priority;
-               nskb->protocol = skb->protocol;
-               nskb->vlan_tci = skb->vlan_tci;
-               nskb->dst = dst_clone(skb->dst);
-               memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
-               nskb->pkt_type = skb->pkt_type;
+               __copy_skb_header(nskb, skb);
                nskb->mac_len = skb->mac_len;
 
                skb_reserve(nskb, headroom);
@@ -2271,6 +2304,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
                skb_copy_from_linear_data(skb, skb_put(nskb, doffset),
                                          doffset);
                if (!sg) {
+                       nskb->ip_summed = CHECKSUM_NONE;
                        nskb->csum = skb_copy_and_csum_bits(skb, offset,
                                                            skb_put(nskb, len),
                                                            len, 0);
@@ -2280,8 +2314,6 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
                frag = skb_shinfo(nskb)->frags;
                k = 0;
 
-               nskb->ip_summed = CHECKSUM_PARTIAL;
-               nskb->csum = skb->csum;
                skb_copy_from_linear_data_offset(skb, offset,
                                                 skb_put(nskb, hsize), hsize);