Re: [PATCH 1/1] net: fix skb_ext_total_length() BUILD_BUG_ON with CONFIG_GCOV_PROFILE_ALL
From: Konstantin Khorenko
Date: Mon Mar 30 2026 - 13:23:18 EST
On 3/30/26 16:48, Thomas Weißschuh wrote:
On 2026-03-30 16:53:37+0300, Konstantin Khorenko wrote:
When CONFIG_GCOV_PROFILE_ALL=y is enabled, GCC inserts branch profiling
counters into skb_ext_total_length() and, combined with -fno-tree-loop-im
from GCOV, prevents the compiler from constant-folding the loop that
sums skb_ext_type_len[] array elements. This causes the compile-time
BUILD_BUG_ON(skb_ext_total_length() > 255) check to fail, even though
the actual computed value is well below 255.
The kernel already has a guard for CONFIG_KCOV_INSTRUMENT_ALL, which
causes the same problem. Add a similar guard for GCOV.
The number of loop iterations matters: with 4 extension types (as in
earlier kernels), GCC 11 can still constant-fold despite GCOV. With 5+
types (after SKB_EXT_CAN and other additions), it gives up. This is
why the issue only manifests in recent kernels with GCOV enabled.
Tested with GCC 11.4.1 and GCC 16.0.1 20260327 (experimental) - both
exhibit the same behavior.
Note that skb_ext_total_length() is still correct at runtime; this
change only allows the build to succeed when GCOV_PROFILE_ALL is
enabled for coverage analysis.
Fixes: 5d21d0a65b57 ("net: generalize calculation of skb extensions length")
Signed-off-by: Konstantin Khorenko <khorenko@xxxxxxxxxxxxx>
Reviewed-by: Thomas Weißschuh <linux@xxxxxxxxxxxxxx>
Thank you very much for the review, Tomas!
Would it help to mark skb_ext_total_length() as
'notrace'/'no_instrument_function'?
That's interesting.
"notrace" did not help, after all it just disables ftrace instrumentation in the beginning of functions.
But! i have also tried __no_profile (__no_profile_instrument_function__) and it helps!
-static __always_inline unsigned int skb_ext_total_length(void)
+static __always_inline __no_profile unsigned int skb_ext_total_length(void)
__no_profile_instrument_function__ tells GCC not to insert GCOV counters
into this specific function,
so without GCOV counters in the loop body, the loop becomes "clean" and
even though -fno-tree-loop-im is still active globally,
gcc can now constant-fold this clean loop.
As a result skb_ext_total_length() is fully evaluated at compile time and BUILD_BUG_ON succeeds.
Thus we can probably use this hack and create the following patch instead:
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 0e217041958a..47c7f0ab6e84 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -5145,7 +5145,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;
@@ -5159,9 +5159,7 @@ static __always_inline unsigned int skb_ext_total_length(void)
static void 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(),
Tomas, do you want me to send the v2 patch with that solution?
--
Best regards,
Konstantin Khorenko,
Virtuozzo Linux Kernel Team