public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Albert Esteve <aesteve@redhat.com>
To: Arnd Bergmann <arnd@arndb.de>,
	 Brendan Higgins <brendan.higgins@linux.dev>,
	David Gow <david@davidgow.net>,  Rae Moar <raemoar63@gmail.com>,
	 Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
	 Maxime Ripard <mripard@kernel.org>,
	Thomas Zimmermann <tzimmermann@suse.de>,
	 David Airlie <airlied@gmail.com>,
	Simona Vetter <simona@ffwll.ch>,
	 Jonathan Corbet <corbet@lwn.net>,
	Shuah Khan <skhan@linuxfoundation.org>,
	 Andrew Morton <akpm@linux-foundation.org>
Cc: linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org,
	 linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com,
	 dri-devel@lists.freedesktop.org, workflows@vger.kernel.org,
	 linux-doc@vger.kernel.org, peterz@infradead.org,
	 Alessandro Carminati <acarmina@redhat.com>,
	 Guenter Roeck <linux@roeck-us.net>, Kees Cook <kees@kernel.org>,
	 Albert Esteve <aesteve@redhat.com>
Subject: [PATCH v7 1/5] bug/kunit: Core support for suppressing warning backtraces
Date: Mon, 20 Apr 2026 14:28:03 +0200	[thread overview]
Message-ID: <20260420-kunit_add_support-v7-1-e8bc6e0f70de@redhat.com> (raw)
In-Reply-To: <20260420-kunit_add_support-v7-0-e8bc6e0f70de@redhat.com>

From: Alessandro Carminati <acarmina@redhat.com>

Some unit tests intentionally trigger warning backtraces by passing bad
parameters to kernel API functions. Such unit tests typically check the
return value from such calls, not the existence of the warning backtrace.

Such intentionally generated warning backtraces are neither desirable
nor useful for a number of reasons:
- They can result in overlooked real problems.
- A warning that suddenly starts to show up in unit tests needs to be
  investigated and has to be marked to be ignored, for example by
  adjusting filter scripts. Such filters are ad hoc because there is
  no real standard format for warnings. On top of that, such filter
  scripts would require constant maintenance.

Solve the problem by providing a means to identify and suppress specific
warning backtraces while executing test code. Support suppressing multiple
backtraces while at the same time limiting changes to generic code to the
absolute minimum.

Implementation details:
Suppression is checked at two points in the warning path:
- In warn_slowpath_fmt(), the check runs before any output, fully
  suppressing both message and backtrace.
- In __report_bug(), the check runs before __warn() is called,
  suppressing the backtrace and stack dump. Note that on this path,
  the WARN() format message may still appear in the kernel log since
  __warn_printk() runs before the trap that enters __report_bug().

A helper function, `__kunit_is_suppressed_warning()`, walks an
RCU-protected list of active suppressions, matching by current task.
The suppression state is tied to the KUnit test lifecycle via
kunit_add_action(), ensuring automatic cleanup at test exit.

The list of suppressed warnings is protected with RCU to allow
concurrent read access without locks.

The implementation is deliberately simple and avoids architecture-specific
optimizations to preserve portability.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Alessandro Carminati <acarmina@redhat.com>
Reviewed-by: Kees Cook <kees@kernel.org>
Signed-off-by: Albert Esteve <aesteve@redhat.com>
---
 include/kunit/bug.h  | 56 +++++++++++++++++++++++++++++++++++
 include/kunit/test.h |  1 +
 kernel/panic.c       |  8 ++++-
 lib/bug.c            |  8 +++++
 lib/kunit/Kconfig    |  9 ++++++
 lib/kunit/Makefile   |  6 ++--
 lib/kunit/bug.c      | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 169 insertions(+), 3 deletions(-)

diff --git a/include/kunit/bug.h b/include/kunit/bug.h
new file mode 100644
index 0000000000000..e52c9d21d9fe6
--- /dev/null
+++ b/include/kunit/bug.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * KUnit helpers for backtrace suppression
+ *
+ * Copyright (C) 2025 Alessandro Carminati <acarmina@redhat.com>
+ * Copyright (C) 2024 Guenter Roeck <linux@roeck-us.net>
+ */
+
+#ifndef _KUNIT_BUG_H
+#define _KUNIT_BUG_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/kconfig.h>
+
+struct kunit;
+
+#ifdef CONFIG_KUNIT_SUPPRESS_BACKTRACE
+
+#include <linux/types.h>
+
+struct task_struct;
+
+struct __suppressed_warning {
+	struct list_head node;
+	struct task_struct *task;
+	int counter;
+};
+
+struct __suppressed_warning *
+__kunit_start_suppress_warning(struct kunit *test);
+void __kunit_end_suppress_warning(struct kunit *test,
+				  struct __suppressed_warning *warning);
+int __kunit_suppressed_warning_count(struct __suppressed_warning *warning);
+bool __kunit_is_suppressed_warning(void);
+
+#define KUNIT_START_SUPPRESSED_WARNING(test) \
+	struct __suppressed_warning *__kunit_suppress =	\
+		__kunit_start_suppress_warning(test)
+
+#define KUNIT_END_SUPPRESSED_WARNING(test) \
+	__kunit_end_suppress_warning(test, __kunit_suppress)
+
+#define KUNIT_SUPPRESSED_WARNING_COUNT() \
+	__kunit_suppressed_warning_count(__kunit_suppress)
+
+#else /* CONFIG_KUNIT_SUPPRESS_BACKTRACE */
+
+#define KUNIT_START_SUPPRESSED_WARNING(test)
+#define KUNIT_END_SUPPRESSED_WARNING(test)
+#define KUNIT_SUPPRESSED_WARNING_COUNT() 0
+static inline bool __kunit_is_suppressed_warning(void) { return false; }
+
+#endif /* CONFIG_KUNIT_SUPPRESS_BACKTRACE */
+#endif /* __ASSEMBLY__ */
+#endif /* _KUNIT_BUG_H */
diff --git a/include/kunit/test.h b/include/kunit/test.h
index 9cd1594ab697d..4ec07b3fa0204 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -10,6 +10,7 @@
 #define _KUNIT_TEST_H
 
 #include <kunit/assert.h>
+#include <kunit/bug.h>
 #include <kunit/try-catch.h>
 
 #include <linux/args.h>
diff --git a/kernel/panic.c b/kernel/panic.c
index c78600212b6c1..d7a7a679f56c4 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -39,6 +39,7 @@
 #include <linux/sys_info.h>
 #include <trace/events/error_report.h>
 #include <asm/sections.h>
+#include <kunit/bug.h>
 
 #define PANIC_TIMER_STEP 100
 #define PANIC_BLINK_SPD 18
@@ -1080,9 +1081,14 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
 void warn_slowpath_fmt(const char *file, int line, unsigned taint,
 		       const char *fmt, ...)
 {
-	bool rcu = warn_rcu_enter();
+	bool rcu;
 	struct warn_args args;
 
+	if (__kunit_is_suppressed_warning())
+		return;
+
+	rcu = warn_rcu_enter();
+
 	pr_warn(CUT_HERE);
 
 	if (!fmt) {
diff --git a/lib/bug.c b/lib/bug.c
index 623c467a8b76c..606205c8c302f 100644
--- a/lib/bug.c
+++ b/lib/bug.c
@@ -48,6 +48,7 @@
 #include <linux/rculist.h>
 #include <linux/ftrace.h>
 #include <linux/context_tracking.h>
+#include <kunit/bug.h>
 
 extern struct bug_entry __start___bug_table[], __stop___bug_table[];
 
@@ -223,6 +224,13 @@ static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long buga
 	no_cut   = bug->flags & BUGFLAG_NO_CUT_HERE;
 	has_args = bug->flags & BUGFLAG_ARGS;
 
+	/*
+	 * Before the once logic so suppressed warnings do not consume
+	 * the single-fire budget of WARN_ON_ONCE().
+	 */
+	if (warning && __kunit_is_suppressed_warning())
+		return BUG_TRAP_TYPE_WARN;
+
 	if (warning && once) {
 		if (done)
 			return BUG_TRAP_TYPE_WARN;
diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig
index 498cc51e493dc..57527418fcf09 100644
--- a/lib/kunit/Kconfig
+++ b/lib/kunit/Kconfig
@@ -15,6 +15,15 @@ menuconfig KUNIT
 
 if KUNIT
 
+config KUNIT_SUPPRESS_BACKTRACE
+	bool "KUnit - Enable backtrace suppression"
+	default y
+	help
+	  Enable backtrace suppression for KUnit. If enabled, backtraces
+	  generated intentionally by KUnit tests are suppressed. Disable
+	  to reduce kernel image size if image size is more important than
+	  suppression of backtraces generated by KUnit tests.
+
 config KUNIT_DEBUGFS
 	bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" if !KUNIT_ALL_TESTS
 	default KUNIT_ALL_TESTS
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 656f1fa35abcc..fe177ff3ebdef 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -16,8 +16,10 @@ ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
 kunit-objs +=				debugfs.o
 endif
 
-# KUnit 'hooks' are built-in even when KUnit is built as a module.
-obj-$(if $(CONFIG_KUNIT),y) +=		hooks.o
+# KUnit 'hooks' and bug handling are built-in even when KUnit is built
+# as a module.
+obj-$(if $(CONFIG_KUNIT),y) +=		hooks.o \
+					bug.o
 
 obj-$(CONFIG_KUNIT_TEST) +=		kunit-test.o
 obj-$(CONFIG_KUNIT_TEST) +=		platform-test.o
diff --git a/lib/kunit/bug.c b/lib/kunit/bug.c
new file mode 100644
index 0000000000000..356c8a5928828
--- /dev/null
+++ b/lib/kunit/bug.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit helpers for backtrace suppression
+ *
+ * Copyright (C) 2025 Alessandro Carminati <acarmina@redhat.com>
+ * Copyright (C) 2024 Guenter Roeck <linux@roeck-us.net>
+ */
+
+#include <kunit/bug.h>
+#include <kunit/resource.h>
+#include <linux/export.h>
+#include <linux/rculist.h>
+#include <linux/sched.h>
+
+#ifdef CONFIG_KUNIT_SUPPRESS_BACKTRACE
+
+static LIST_HEAD(suppressed_warnings);
+
+static void __kunit_suppress_warning_remove(struct __suppressed_warning *warning)
+{
+	list_del_rcu(&warning->node);
+	synchronize_rcu(); /* Wait for readers to finish */
+}
+
+KUNIT_DEFINE_ACTION_WRAPPER(__kunit_suppress_warning_cleanup,
+			    __kunit_suppress_warning_remove,
+			    struct __suppressed_warning *);
+
+struct __suppressed_warning *
+__kunit_start_suppress_warning(struct kunit *test)
+{
+	struct __suppressed_warning *warning;
+	int ret;
+
+	warning = kunit_kzalloc(test, sizeof(*warning), GFP_KERNEL);
+	if (!warning)
+		return NULL;
+
+	warning->task = current;
+	list_add_rcu(&warning->node, &suppressed_warnings);
+
+	ret = kunit_add_action_or_reset(test,
+					__kunit_suppress_warning_cleanup,
+					warning);
+	if (ret)
+		return NULL;
+
+	return warning;
+}
+EXPORT_SYMBOL_GPL(__kunit_start_suppress_warning);
+
+void __kunit_end_suppress_warning(struct kunit *test,
+				  struct __suppressed_warning *warning)
+{
+	if (!warning)
+		return;
+	kunit_release_action(test, __kunit_suppress_warning_cleanup, warning);
+}
+EXPORT_SYMBOL_GPL(__kunit_end_suppress_warning);
+
+int __kunit_suppressed_warning_count(struct __suppressed_warning *warning)
+{
+	return warning ? warning->counter : 0;
+}
+EXPORT_SYMBOL_GPL(__kunit_suppressed_warning_count);
+
+bool __kunit_is_suppressed_warning(void)
+{
+	struct __suppressed_warning *warning;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(warning, &suppressed_warnings, node) {
+		if (warning->task == current) {
+			warning->counter++;
+			rcu_read_unlock();
+			return true;
+		}
+	}
+	rcu_read_unlock();
+
+	return false;
+}
+
+#endif /* CONFIG_KUNIT_SUPPRESS_BACKTRACE */

-- 
2.52.0


  reply	other threads:[~2026-04-20 12:29 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-20 12:28 [PATCH v7 0/5] kunit: Add support for suppressing warning backtraces Albert Esteve
2026-04-20 12:28 ` Albert Esteve [this message]
2026-04-20 14:39   ` [PATCH v7 1/5] bug/kunit: Core " Peter Zijlstra
2026-04-21  8:22     ` Albert Esteve
2026-04-20 14:45   ` Peter Zijlstra
2026-04-21  8:29     ` Albert Esteve
2026-04-20 12:28 ` [PATCH v7 2/5] bug/kunit: Reduce runtime impact of warning backtrace suppression Albert Esteve
2026-04-20 14:44   ` Peter Zijlstra
2026-04-21  8:41     ` Albert Esteve
2026-04-20 12:28 ` [PATCH v7 3/5] kunit: Add backtrace suppression self-tests Albert Esteve
2026-04-20 12:28 ` [PATCH v7 4/5] drm: Suppress intentional warning backtraces in scaling unit tests Albert Esteve
2026-04-20 14:47   ` Peter Zijlstra
2026-04-21  8:49     ` Albert Esteve
2026-04-21 11:50       ` Jani Nikula
2026-04-20 12:28 ` [PATCH v7 5/5] kunit: Add documentation for warning backtrace suppression API Albert Esteve

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260420-kunit_add_support-v7-1-e8bc6e0f70de@redhat.com \
    --to=aesteve@redhat.com \
    --cc=acarmina@redhat.com \
    --cc=airlied@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=arnd@arndb.de \
    --cc=brendan.higgins@linux.dev \
    --cc=corbet@lwn.net \
    --cc=david@davidgow.net \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=kees@kernel.org \
    --cc=kunit-dev@googlegroups.com \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=mripard@kernel.org \
    --cc=peterz@infradead.org \
    --cc=raemoar63@gmail.com \
    --cc=simona@ffwll.ch \
    --cc=skhan@linuxfoundation.org \
    --cc=tzimmermann@suse.de \
    --cc=workflows@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox