|
@@ -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;
|