KUnit support is not consistently present across distributions, some
include it in their stock kernels, while others do not.
While both KUNIT and KUNIT_SUPPRESS_BACKTRACE can be considered debug
features, the fact that some distros ship with KUnit enabled means it's
important to minimize the runtime impact of this patch.
To that end, this patch introduces a counter for the number of
suppressed symbols and skips execution of __kunit_is_suppressed_warning()
entirely when no symbols are currently being suppressed.
Signed-off-by: Alessandro Carminati <acarmina@redhat.com>
---
include/asm-generic/bug.h | 21 ++++++++++++++-------
include/kunit/bug.h | 1 +
lib/kunit/bug.c | 4 ++++
3 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index 3cc8cb100ccd..c5587820bd8c 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -62,7 +62,8 @@ struct bug_entry {
*/
#ifndef HAVE_ARCH_BUG
#define BUG() do { \
- if (!KUNIT_IS_SUPPRESSED_WARNING(__func__)) { \
+ if (suppressed_symbols_cnt && \
+ !KUNIT_IS_SUPPRESSED_WARNING(__func__)) { \
printk("BUG: failure at %s:%d/%s()!\n", __FILE__, \
__LINE__, __func__); \
barrier_before_unreachable(); \
@@ -99,7 +100,8 @@ extern __printf(1, 2) void __warn_printk(const char *fmt, ...);
#ifndef __WARN_FLAGS
#define __WARN() __WARN_printf(TAINT_WARN, NULL)
#define __WARN_printf(taint, arg...) do { \
- if (!KUNIT_IS_SUPPRESSED_WARNING(__func__)) { \
+ if (suppressed_symbols_cnt && \
+ !KUNIT_IS_SUPPRESSED_WARNING(__func__)) { \
instrumentation_begin(); \
warn_slowpath_fmt(__FILE__, __LINE__, taint, arg);\
instrumentation_end(); \
@@ -108,7 +110,8 @@ extern __printf(1, 2) void __warn_printk(const char *fmt, ...);
#else
#define __WARN() __WARN_FLAGS(BUGFLAG_TAINT(TAINT_WARN))
#define __WARN_printf(taint, arg...) do { \
- if (!KUNIT_IS_SUPPRESSED_WARNING(__func__)) { \
+ if (suppressed_symbols_cnt && \
+ !KUNIT_IS_SUPPRESSED_WARNING(__func__)) { \
instrumentation_begin(); \
__warn_printk(arg); \
__WARN_FLAGS(BUGFLAG_NO_CUT_HERE | \
@@ -118,7 +121,8 @@ extern __printf(1, 2) void __warn_printk(const char *fmt, ...);
} while (0)
#define WARN_ON_ONCE(condition) ({ \
int __ret_warn_on = !!(condition); \
- if (unlikely(__ret_warn_on) && !KUNIT_IS_SUPPRESSED_WARNING(__func__)) \
+ if (unlikely(__ret_warn_on) && suppressed_symbols_cnt &&\
+ !KUNIT_IS_SUPPRESSED_WARNING(__func__)) \
__WARN_FLAGS(BUGFLAG_ONCE | \
BUGFLAG_TAINT(TAINT_WARN)); \
unlikely(__ret_warn_on); \
@@ -130,7 +134,8 @@ extern __printf(1, 2) void __warn_printk(const char *fmt, ...);
#ifndef WARN_ON
#define WARN_ON(condition) ({ \
int __ret_warn_on = !!(condition); \
- if (unlikely(__ret_warn_on) && !KUNIT_IS_SUPPRESSED_WARNING(__func__)) \
+ if (unlikely(__ret_warn_on) && suppressed_symbols_cnt && \
+ !KUNIT_IS_SUPPRESSED_WARNING(__func__)) \
__WARN(); \
unlikely(__ret_warn_on); \
})
@@ -147,7 +152,8 @@ extern __printf(1, 2) void __warn_printk(const char *fmt, ...);
#define WARN_TAINT(condition, taint, format...) ({ \
int __ret_warn_on = !!(condition); \
- if (unlikely(__ret_warn_on) && !KUNIT_IS_SUPPRESSED_WARNING(__func__)) \
+ if (unlikely(__ret_warn_on) && suppressed_symbols_cnt && \
+ !KUNIT_IS_SUPPRESSED_WARNING(__func__)) \
__WARN_printf(taint, format); \
unlikely(__ret_warn_on); \
})
@@ -166,7 +172,8 @@ extern __printf(1, 2) void __warn_printk(const char *fmt, ...);
#else /* !CONFIG_BUG */
#ifndef HAVE_ARCH_BUG
#define BUG() do { \
- if (!KUNIT_IS_SUPPRESSED_WARNING(__func__)) { \
+ if (suppressed_symbols_cnt && \
+ !KUNIT_IS_SUPPRESSED_WARNING(__func__)) { \
do {} while (1); \
unreachable(); \
} \
diff --git a/include/kunit/bug.h b/include/kunit/bug.h
index 9a4eff2897e9..3256e3f2c165 100644
--- a/include/kunit/bug.h
+++ b/include/kunit/bug.h
@@ -23,6 +23,7 @@ struct __suppressed_warning {
const char *function;
int counter;
};
+extern int suppressed_symbols_cnt;
void __kunit_start_suppress_warning(struct __suppressed_warning *warning);
void __kunit_end_suppress_warning(struct __suppressed_warning *warning);
diff --git a/lib/kunit/bug.c b/lib/kunit/bug.c
index 4da9ae478f25..5beaee1049eb 100644
--- a/lib/kunit/bug.c
+++ b/lib/kunit/bug.c
@@ -11,15 +11,19 @@
#include <linux/list.h>
static LIST_HEAD(suppressed_warnings);
+int suppressed_symbols_cnt = 0;
+EXPORT_SYMBOL_GPL(suppressed_symbols_cnt);
void __kunit_start_suppress_warning(struct __suppressed_warning *warning)
{
+ suppressed_symbols_cnt++;
list_add(&warning->node, &suppressed_warnings);
}
EXPORT_SYMBOL_GPL(__kunit_start_suppress_warning);
void __kunit_end_suppress_warning(struct __suppressed_warning *warning)
{
+ suppressed_symbols_cnt--;
list_del(&warning->node);
}
EXPORT_SYMBOL_GPL(__kunit_end_suppress_warning);
--
2.34.1
On Mon, May 26, 2025 at 01:27:52PM +0000, Alessandro Carminati wrote: > KUnit support is not consistently present across distributions, some > include it in their stock kernels, while others do not. > While both KUNIT and KUNIT_SUPPRESS_BACKTRACE can be considered debug > features, the fact that some distros ship with KUnit enabled means it's > important to minimize the runtime impact of this patch. > To that end, this patch introduces a counter for the number of > suppressed symbols and skips execution of __kunit_is_suppressed_warning() > entirely when no symbols are currently being suppressed. If KUnit already serialized? I should have asked this before: you're reading and writing a global list -- I think some kind of RCU may be needed for the list? One thread may be removing a function from the list while another thread is executing a WARN-induced walk of the list... This global may have the same problem. Why not use a static branch, or is that just overkill? -Kees -- Kees Cook
© 2016 - 2025 Red Hat, Inc.