aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/skbuff.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2014-12-03 20:04:39 -0500
committerDavid S. Miller <davem@davemloft.net>2014-12-09 13:40:20 -0500
commit6ffe75eb53564953e75c051e1c28676e1e56f385 (patch)
treedf3ded93cb68f3e739d1c490e8377dfee2fc028a /net/core/skbuff.c
parent395eea6ccf2b253f81b4718ffbcae67d36fe2e69 (diff)
net: avoid two atomic operations in fast clones
Commit ce1a4ea3f125 ("net: avoid one atomic operation in skb_clone()") took the wrong way to save one atomic operation. It is actually possible to avoid two atomic operations, if we do not change skb->fclone values, and only rely on clone_ref content to signal if the clone is available or not. skb_clone() can simply use the fast clone if clone_ref is 1. kfree_skbmem() can avoid the atomic_dec_and_test() if clone_ref is 1. Note that because we usually free the clone before the original skb, this particular attempt is only done for the original skb to have better branch prediction. SKB_FCLONE_FREE is removed. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Chris Mason <clm@fb.com> Cc: Sabrina Dubroca <sd@queasysnail.net> Cc: Vijay Subramanian <subramanian.vijay@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r--net/core/skbuff.c35
1 files changed, 18 insertions, 17 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 92116dfe827c..7a338fb55cc4 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -265,7 +265,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
265 skb->fclone = SKB_FCLONE_ORIG; 265 skb->fclone = SKB_FCLONE_ORIG;
266 atomic_set(&fclones->fclone_ref, 1); 266 atomic_set(&fclones->fclone_ref, 1);
267 267
268 fclones->skb2.fclone = SKB_FCLONE_FREE; 268 fclones->skb2.fclone = SKB_FCLONE_CLONE;
269 fclones->skb2.pfmemalloc = pfmemalloc; 269 fclones->skb2.pfmemalloc = pfmemalloc;
270 } 270 }
271out: 271out:
@@ -541,26 +541,27 @@ static void kfree_skbmem(struct sk_buff *skb)
541 switch (skb->fclone) { 541 switch (skb->fclone) {
542 case SKB_FCLONE_UNAVAILABLE: 542 case SKB_FCLONE_UNAVAILABLE:
543 kmem_cache_free(skbuff_head_cache, skb); 543 kmem_cache_free(skbuff_head_cache, skb);
544 break; 544 return;
545 545
546 case SKB_FCLONE_ORIG: 546 case SKB_FCLONE_ORIG:
547 fclones = container_of(skb, struct sk_buff_fclones, skb1); 547 fclones = container_of(skb, struct sk_buff_fclones, skb1);
548 if (atomic_dec_and_test(&fclones->fclone_ref))
549 kmem_cache_free(skbuff_fclone_cache, fclones);
550 break;
551
552 case SKB_FCLONE_CLONE:
553 fclones = container_of(skb, struct sk_buff_fclones, skb2);
554 548
555 /* The clone portion is available for 549 /* We usually free the clone (TX completion) before original skb
556 * fast-cloning again. 550 * This test would have no chance to be true for the clone,
551 * while here, branch prediction will be good.
557 */ 552 */
558 skb->fclone = SKB_FCLONE_FREE; 553 if (atomic_read(&fclones->fclone_ref) == 1)
554 goto fastpath;
555 break;
559 556
560 if (atomic_dec_and_test(&fclones->fclone_ref)) 557 default: /* SKB_FCLONE_CLONE */
561 kmem_cache_free(skbuff_fclone_cache, fclones); 558 fclones = container_of(skb, struct sk_buff_fclones, skb2);
562 break; 559 break;
563 } 560 }
561 if (!atomic_dec_and_test(&fclones->fclone_ref))
562 return;
563fastpath:
564 kmem_cache_free(skbuff_fclone_cache, fclones);
564} 565}
565 566
566static void skb_release_head_state(struct sk_buff *skb) 567static void skb_release_head_state(struct sk_buff *skb)
@@ -872,15 +873,15 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
872 struct sk_buff_fclones *fclones = container_of(skb, 873 struct sk_buff_fclones *fclones = container_of(skb,
873 struct sk_buff_fclones, 874 struct sk_buff_fclones,
874 skb1); 875 skb1);
875 struct sk_buff *n = &fclones->skb2; 876 struct sk_buff *n;
876 877
877 if (skb_orphan_frags(skb, gfp_mask)) 878 if (skb_orphan_frags(skb, gfp_mask))
878 return NULL; 879 return NULL;
879 880
880 if (skb->fclone == SKB_FCLONE_ORIG && 881 if (skb->fclone == SKB_FCLONE_ORIG &&
881 n->fclone == SKB_FCLONE_FREE) { 882 atomic_read(&fclones->fclone_ref) == 1) {
882 n->fclone = SKB_FCLONE_CLONE; 883 n = &fclones->skb2;
883 atomic_inc(&fclones->fclone_ref); 884 atomic_set(&fclones->fclone_ref, 2);
884 } else { 885 } else {
885 if (skb_pfmemalloc(skb)) 886 if (skb_pfmemalloc(skb))
886 gfp_mask |= __GFP_MEMALLOC; 887 gfp_mask |= __GFP_MEMALLOC;