aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/skbuff.h2
-rw-r--r--net/core/skbuff.c41
2 files changed, 41 insertions, 2 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index a19ea43fea0..720b688c22b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -383,6 +383,8 @@ static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
383 return __alloc_skb(size, priority, 1, -1); 383 return __alloc_skb(size, priority, 1, -1);
384} 384}
385 385
386extern int skb_recycle_check(struct sk_buff *skb, int skb_size);
387
386extern struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src); 388extern struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src);
387extern struct sk_buff *skb_clone(struct sk_buff *skb, 389extern struct sk_buff *skb_clone(struct sk_buff *skb,
388 gfp_t priority); 390 gfp_t priority);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index ca1ccdf1ef7..2c218a0808b 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -363,8 +363,7 @@ static void kfree_skbmem(struct sk_buff *skb)
363 } 363 }
364} 364}
365 365
366/* Free everything but the sk_buff shell. */ 366static void skb_release_head_state(struct sk_buff *skb)
367static void skb_release_all(struct sk_buff *skb)
368{ 367{
369 dst_release(skb->dst); 368 dst_release(skb->dst);
370#ifdef CONFIG_XFRM 369#ifdef CONFIG_XFRM
@@ -388,6 +387,12 @@ static void skb_release_all(struct sk_buff *skb)
388 skb->tc_verd = 0; 387 skb->tc_verd = 0;
389#endif 388#endif
390#endif 389#endif
390}
391
392/* Free everything but the sk_buff shell. */
393static void skb_release_all(struct sk_buff *skb)
394{
395 skb_release_head_state(skb);
391 skb_release_data(skb); 396 skb_release_data(skb);
392} 397}
393 398
@@ -424,6 +429,38 @@ void kfree_skb(struct sk_buff *skb)
424 __kfree_skb(skb); 429 __kfree_skb(skb);
425} 430}
426 431
432int skb_recycle_check(struct sk_buff *skb, int skb_size)
433{
434 struct skb_shared_info *shinfo;
435
436 if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE)
437 return 0;
438
439 skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD);
440 if (skb_end_pointer(skb) - skb->head < skb_size)
441 return 0;
442
443 if (skb_shared(skb) || skb_cloned(skb))
444 return 0;
445
446 skb_release_head_state(skb);
447 shinfo = skb_shinfo(skb);
448 atomic_set(&shinfo->dataref, 1);
449 shinfo->nr_frags = 0;
450 shinfo->gso_size = 0;
451 shinfo->gso_segs = 0;
452 shinfo->gso_type = 0;
453 shinfo->ip6_frag_id = 0;
454 shinfo->frag_list = NULL;
455
456 memset(skb, 0, offsetof(struct sk_buff, tail));
457 skb_reset_tail_pointer(skb);
458 skb->data = skb->head + NET_SKB_PAD;
459
460 return 1;
461}
462EXPORT_SYMBOL(skb_recycle_check);
463
427static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) 464static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
428{ 465{
429 new->tstamp = old->tstamp; 466 new->tstamp = old->tstamp;