mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 07:33:19 +02:00
net: add skbuff_clear() helper
clang is unable to inline the memset() calls in net/core/skbuff.c when initializing allocated sk_buff. memset(skb, 0, offsetof(struct sk_buff, tail)); This is unfortunate, because: 1) calling external memset_orig() helper adds a call/ret and typical setup cost. 2) offsetof(struct sk_buff, tail) == 0xb8 = 0x80 + 0x38 On x86_64, memset_orig() performs two 64 bytes clear, then has to loop 7 times to clear the final 56 bytes. skbuff_clear() makes sure the minimal and optimal code is generated. Signed-off-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260109203836.1667441-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
d7161b0790
commit
0391ab577c
|
|
@ -307,6 +307,23 @@ static struct sk_buff *napi_skb_cache_get(bool alloc)
|
|||
return skb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only clear those fields we need to clear, not those that we will
|
||||
* actually initialise later. Hence, don't put any more fields after
|
||||
* the tail pointer in struct sk_buff!
|
||||
*/
|
||||
static inline void skbuff_clear(struct sk_buff *skb)
|
||||
{
|
||||
/* Replace memset(skb, 0, offsetof(struct sk_buff, tail))
|
||||
* with two smaller memset(), with a barrier() between them.
|
||||
* This forces the compiler to inline both calls.
|
||||
*/
|
||||
BUILD_BUG_ON(offsetof(struct sk_buff, tail) <= 128);
|
||||
memset(skb, 0, 128);
|
||||
barrier();
|
||||
memset((void *)skb + 128, 0, offsetof(struct sk_buff, tail) - 128);
|
||||
}
|
||||
|
||||
/**
|
||||
* napi_skb_cache_get_bulk - obtain a number of zeroed skb heads from the cache
|
||||
* @skbs: pointer to an at least @n-sized array to fill with skb pointers
|
||||
|
|
@ -357,7 +374,7 @@ u32 napi_skb_cache_get_bulk(void **skbs, u32 n)
|
|||
skbs[i] = nc->skb_cache[base + i];
|
||||
|
||||
kasan_mempool_unpoison_object(skbs[i], skbuff_cache_size);
|
||||
memset(skbs[i], 0, offsetof(struct sk_buff, tail));
|
||||
skbuff_clear(skbs[i]);
|
||||
}
|
||||
|
||||
nc->skb_count -= n;
|
||||
|
|
@ -424,7 +441,7 @@ struct sk_buff *slab_build_skb(void *data)
|
|||
if (unlikely(!skb))
|
||||
return NULL;
|
||||
|
||||
memset(skb, 0, offsetof(struct sk_buff, tail));
|
||||
skbuff_clear(skb);
|
||||
data = __slab_build_skb(data, &size);
|
||||
__finalize_skb_around(skb, data, size);
|
||||
|
||||
|
|
@ -476,7 +493,7 @@ struct sk_buff *__build_skb(void *data, unsigned int frag_size)
|
|||
if (unlikely(!skb))
|
||||
return NULL;
|
||||
|
||||
memset(skb, 0, offsetof(struct sk_buff, tail));
|
||||
skbuff_clear(skb);
|
||||
__build_skb_around(skb, data, frag_size);
|
||||
|
||||
return skb;
|
||||
|
|
@ -537,7 +554,7 @@ static struct sk_buff *__napi_build_skb(void *data, unsigned int frag_size)
|
|||
if (unlikely(!skb))
|
||||
return NULL;
|
||||
|
||||
memset(skb, 0, offsetof(struct sk_buff, tail));
|
||||
skbuff_clear(skb);
|
||||
__build_skb_around(skb, data, frag_size);
|
||||
|
||||
return skb;
|
||||
|
|
@ -696,12 +713,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
|
|||
*/
|
||||
prefetchw(data + SKB_WITH_OVERHEAD(size));
|
||||
|
||||
/*
|
||||
* Only clear those fields we need to clear, not those that we will
|
||||
* actually initialise below. Hence, don't put any more fields after
|
||||
* the tail pointer in struct sk_buff!
|
||||
*/
|
||||
memset(skb, 0, offsetof(struct sk_buff, tail));
|
||||
skbuff_clear(skb);
|
||||
__build_skb_around(skb, data, size);
|
||||
skb->pfmemalloc = pfmemalloc;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user