diff options
Diffstat (limited to 'net/core/skbuff.c')
| -rw-r--r-- | net/core/skbuff.c | 64 |
1 files changed, 20 insertions, 44 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 0e217041958a..7dad68e3b518 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -94,6 +94,7 @@ #include "dev.h" #include "devmem.h" +#include "net-sysfs.h" #include "netmem_priv.h" #include "sock_destructor.h" @@ -105,10 +106,9 @@ static struct kmem_cache *skbuff_ext_cache __ro_after_init; #define SKB_SMALL_HEAD_SIZE SKB_HEAD_ALIGN(max(MAX_TCP_HEADER, \ GRO_MAX_HEAD_PAD)) -/* We want SKB_SMALL_HEAD_CACHE_SIZE to not be a power of two. - * This should ensure that SKB_SMALL_HEAD_HEADROOM is a unique - * size, and we can differentiate heads from skb_small_head_cache - * vs system slabs by looking at their size (skb_end_offset()). +/* SKB_SMALL_HEAD_CACHE_SIZE is the size used for the skbuff_small_head + * kmem_cache. The non-power-of-2 padding is kept for historical reasons and + * to avoid potential collisions with generic kmalloc bucket sizes. */ #define SKB_SMALL_HEAD_CACHE_SIZE \ (is_power_of_2(SKB_SMALL_HEAD_SIZE) ? \ @@ -891,17 +891,6 @@ skb_fail: } EXPORT_SYMBOL(napi_alloc_skb); -void skb_add_rx_frag_netmem(struct sk_buff *skb, int i, netmem_ref netmem, - int off, int size, unsigned int truesize) -{ - DEBUG_NET_WARN_ON_ONCE(size > truesize); - - skb_fill_netmem_desc(skb, i, netmem, off, size); - skb->len += size; - skb->data_len += size; - skb->truesize += truesize; -} -EXPORT_SYMBOL(skb_add_rx_frag_netmem); void skb_coalesce_rx_frag(struct sk_buff *skb, int i, int size, unsigned int truesize) @@ -1081,12 +1070,9 @@ static int skb_pp_frag_ref(struct sk_buff *skb) return 0; } -static void skb_kfree_head(void *head, unsigned int end_offset) +static void skb_kfree_head(void *head) { - if (end_offset == SKB_SMALL_HEAD_HEADROOM) - kmem_cache_free(net_hotdata.skb_small_head_cache, head); - else - kfree(head); + kfree(head); } static void skb_free_head(struct sk_buff *skb) @@ -1098,7 +1084,7 @@ static void skb_free_head(struct sk_buff *skb) return; skb_free_frag(head); } else { - skb_kfree_head(head, skb_end_offset(skb)); + skb_kfree_head(head); } } @@ -1530,7 +1516,8 @@ void napi_consume_skb(struct sk_buff *skb, int budget) DEBUG_NET_WARN_ON_ONCE(!in_softirq()); - if (skb->alloc_cpu != smp_processor_id() && !skb_shared(skb)) { + if (!static_branch_unlikely(&skb_defer_disable_key) && + skb->alloc_cpu != smp_processor_id() && !skb_shared(skb)) { skb_release_head_state(skb); return skb_attempt_defer_free(skb); } @@ -2373,7 +2360,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, return 0; nofrags: - skb_kfree_head(data, size); + skb_kfree_head(data); nodata: return -ENOMEM; } @@ -2419,20 +2406,6 @@ int __skb_unclone_keeptruesize(struct sk_buff *skb, gfp_t pri) if (likely(skb_end_offset(skb) == saved_end_offset)) return 0; - /* We can not change skb->end if the original or new value - * is SKB_SMALL_HEAD_HEADROOM, as it might break skb_kfree_head(). - */ - if (saved_end_offset == SKB_SMALL_HEAD_HEADROOM || - skb_end_offset(skb) == SKB_SMALL_HEAD_HEADROOM) { - /* We think this path should not be taken. - * Add a temporary trace to warn us just in case. - */ - pr_err_once("__skb_unclone_keeptruesize() skb_end_offset() %u -> %u\n", - saved_end_offset, skb_end_offset(skb)); - WARN_ON_ONCE(1); - return 0; - } - shinfo = skb_shinfo(skb); /* We are about to change back skb->end, @@ -5145,7 +5118,7 @@ static const u8 skb_ext_type_len[] = { #endif }; -static __always_inline unsigned int skb_ext_total_length(void) +static __always_inline __no_profile unsigned int skb_ext_total_length(void) { unsigned int l = SKB_EXT_CHUNKSIZEOF(struct skb_ext); int i; @@ -5156,12 +5129,10 @@ static __always_inline unsigned int skb_ext_total_length(void) return l; } -static void skb_extensions_init(void) +static noinline void __init __no_profile skb_extensions_init(void) { BUILD_BUG_ON(SKB_EXT_NUM > 8); -#if !IS_ENABLED(CONFIG_KCOV_INSTRUMENT_ALL) BUILD_BUG_ON(skb_ext_total_length() > 255); -#endif skbuff_ext_cache = kmem_cache_create("skbuff_ext_cache", SKB_EXT_ALIGN_VALUE * skb_ext_total_length(), @@ -6827,7 +6798,7 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off, if (skb_cloned(skb)) { /* drop the old head gracefully */ if (skb_orphan_frags(skb, gfp_mask)) { - skb_kfree_head(data, size); + skb_kfree_head(data); return -ENOMEM; } for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) @@ -6934,7 +6905,7 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off, memcpy((struct skb_shared_info *)(data + size), skb_shinfo(skb), offsetof(struct skb_shared_info, frags[0])); if (skb_orphan_frags(skb, gfp_mask)) { - skb_kfree_head(data, size); + skb_kfree_head(data); return -ENOMEM; } shinfo = (struct skb_shared_info *)(data + size); @@ -6970,7 +6941,7 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off, /* skb_frag_unref() is not needed here as shinfo->nr_frags = 0. */ if (skb_has_frag_list(skb)) kfree_skb_list(skb_shinfo(skb)->frag_list); - skb_kfree_head(data, size); + skb_kfree_head(data); return -ENOMEM; } skb_release_data(skb, SKB_CONSUMED); @@ -7267,6 +7238,8 @@ static void kfree_skb_napi_cache(struct sk_buff *skb) local_bh_enable(); } +DEFINE_STATIC_KEY_FALSE(skb_defer_disable_key); + /** * skb_attempt_defer_free - queue skb for remote freeing * @skb: buffer @@ -7283,6 +7256,9 @@ void skb_attempt_defer_free(struct sk_buff *skb) bool kick; int cpu; + if (static_branch_unlikely(&skb_defer_disable_key)) + goto nodefer; + /* zero copy notifications should not be delayed. */ if (skb_zcopy(skb)) goto nodefer; |
