Skip to content

Commit ce1a4ea

Browse files
edumazetdavem330
authored andcommitted
net: avoid one atomic operation in skb_clone()
Fast clone cloning can actually avoid an atomic_inc(), if we guarantee prior clone_ref value is 1. This requires a change kfree_skbmem(), to perform the atomic_dec_and_test() on clone_ref before setting fclone to SKB_FCLONE_UNAVAILABLE. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent e500f48 commit ce1a4ea

File tree

1 file changed

+17
-6
lines changed

1 file changed

+17
-6
lines changed

net/core/skbuff.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -541,13 +541,20 @@ static void kfree_skbmem(struct sk_buff *skb)
541541
case SKB_FCLONE_CLONE:
542542
fclones = container_of(skb, struct sk_buff_fclones, skb2);
543543

544-
/* The clone portion is available for
545-
* fast-cloning again.
544+
/* Warning : We must perform the atomic_dec_and_test() before
545+
* setting skb->fclone back to SKB_FCLONE_UNAVAILABLE, otherwise
546+
* skb_clone() could set clone_ref to 2 before our decrement.
547+
* Anyway, if we are going to free the structure, no need to
548+
* rewrite skb->fclone.
546549
*/
547-
skb->fclone = SKB_FCLONE_UNAVAILABLE;
548-
549-
if (atomic_dec_and_test(&fclones->fclone_ref))
550+
if (atomic_dec_and_test(&fclones->fclone_ref)) {
550551
kmem_cache_free(skbuff_fclone_cache, fclones);
552+
} else {
553+
/* The clone portion is available for
554+
* fast-cloning again.
555+
*/
556+
skb->fclone = SKB_FCLONE_UNAVAILABLE;
557+
}
551558
break;
552559
}
553560
}
@@ -869,7 +876,11 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
869876
if (skb->fclone == SKB_FCLONE_ORIG &&
870877
n->fclone == SKB_FCLONE_UNAVAILABLE) {
871878
n->fclone = SKB_FCLONE_CLONE;
872-
atomic_inc(&fclones->fclone_ref);
879+
/* As our fastclone was free, clone_ref must be 1 at this point.
880+
* We could use atomic_inc() here, but it is faster
881+
* to set the final value.
882+
*/
883+
atomic_set(&fclones->fclone_ref, 2);
873884
} else {
874885
if (skb_pfmemalloc(skb))
875886
gfp_mask |= __GFP_MEMALLOC;

0 commit comments

Comments
 (0)