aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@marvell.com>2008-10-01 05:33:12 -0400
committerDavid S. Miller <davem@davemloft.net>2008-10-01 05:33:12 -0400
commit04a4bb55bcf35b63d40fd2725e58599ff8310dd7 (patch)
treea4be70eeb5b33829467851904fcdc26522c24a68 /net/core
parent788df7322a7543a337c1ea400d38b621346ea78e (diff)
net: add skb_recycle_check() to enable netdriver skb recycling
This patch adds skb_recycle_check(), which can be used by a network driver after transmitting an skb to check whether this skb can be recycled as a receive buffer. skb_recycle_check() checks that the skb is not shared or cloned, and that it is linear and its head portion large enough (as determined by the driver) to be recycled as a receive buffer. If these conditions are met, it does any necessary reference count dropping and cleans up the skbuff as if it just came from __alloc_skb(). Signed-off-by: Lennert Buytenhek <buytenh@marvell.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/skbuff.c41
1 files changed, 39 insertions, 2 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index ca1ccdf1ef76..2c218a0808b4 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;