* Re: [PATCH v3 2/9] kernel/api: enable kerneldoc-based API specifications
From: Sasha Levin @ 2026-05-05 7:45 UTC (permalink / raw)
To: Nicolas Schier
Cc: Sasha Levin, Nathan Chancellor, linux-api, linux-kernel,
linux-doc, linux-fsdevel, linux-kbuild, linux-kselftest,
workflows, tools, x86, Thomas Gleixner, Paul E . McKenney,
Greg Kroah-Hartman, Jonathan Corbet, Dmitry Vyukov, Randy Dunlap,
Cyril Hrubis, Kees Cook, Jake Edge, David Laight, Askar Safin,
Gabriele Paoloni, Mauro Carvalho Chehab, Christian Brauner,
Alexander Viro, Andrew Morton, Masahiro Yamada, Shuah Khan,
Ingo Molnar, Arnd Bergmann
In-Reply-To: <afNrbm8URHlClZ-8@levanger>
On Thu, Apr 30, 2026 at 04:47:10PM +0200, Nicolas Schier wrote:
> On Fri, Apr 24, 2026 at 12:51:22PM -0400, Sasha Levin wrote:
> > +# Generate API spec headers from kernel-doc comments
> > +ifeq ($(CONFIG_KAPI_SPEC),y)
> > +# Function to check if a file has API specifications
> > +has-apispec = $(shell grep -qE '^\s*\*\s*context-flags:' $(src)/$(1) 2>/dev/null && echo $(1))
> > +
> > +# Get base names without directory prefix
> > +c-objs-base := $(notdir $(real-obj-y) $(real-obj-m))
> > +# Filter to only .o files with corresponding .c source files
> > +c-files := $(foreach o,$(c-objs-base),$(if $(wildcard $(src)/$(o:.o=.c)),$(o:.o=.c)))
>
> Looks to me as if the two lines above are redundant, since 'find'
> (below) will find all files gathered in $(c-files).
Right, those two lines are dropped in v4. The replacement uses the
kbuild-derived file list described below, so neither set survives.
> > +# Also check for any additional .c files that contain API specs but are included
> > +extra-c-files := $(shell find $(src) -maxdepth 1 -name "*.c" -exec grep -l '^\s*\*\s*\(long-desc\|context-flags\|state-trans\):' {} \; 2>/dev/null | xargs -r basename -a)
> > +# Combine both lists and remove duplicates
> > +all-c-files := $(sort $(c-files) $(extra-c-files))
> > +# Only include files that actually have API specifications
> > +apispec-files := $(foreach f,$(all-c-files),$(call has-apispec,$(f)))
> > +# Generate apispec targets with proper directory prefix
> > +apispec-y := $(addprefix $(obj)/,$(apispec-files:.c=.apispec.h))
>
> To goal is to find any relevant C file in $(src)/ (but not deeper below)
> that holds KAPI documentation, right?
>
> I do not like the find call, as it picks up anything. Might it make
> sense to evaluate $(obj-) along with $(obj-y) and $(obj-m) to pick up
> all C files that are references in kbuild?
>
>
>
> # in top definition block -- before 'include $(kbuild-file)' et al.
> obj- :=
>
> # below the definitions of real-obj-{y,m}
> real-obj-any := $(call real-search, $(obj-y) $(obj-m) $(obj-), .o, -objs -y -m -)
>
> has-apispec = $(shell grep -lE '^\s*\*\s*context-flags:' $(1) 2>/dev/null)
> apispec-y := $(patsubst $(src)/%.c, $(obj)/%.apispec.h, $(call has-apispec,
> $(patsubst $(obj)/%.o, $(src)/%.c, $(real-obj-any))))
>
> #...
>
> # Source files that include their own apispec.h need to depend on it
> $(apispec-y:.apispec.h=.o): $(obj)/%.o: $(obj)/%.apispec.h
>
> (untested)
Thanks, the kbuild-driven approach is much cleaner. v4 takes your sketch
with two adjustments:
1. obj-m is already addprefix'd with $(obj)/ by line 116 of
Makefile.build at the point where this block runs, so calling
real-search again on the mixed list double-prefixes the module
entries (giving $(src)/$(obj)/foo.c). v4 uses the existing
$(real-obj-y)/$(real-obj-m) and strips the prefix in patsubst
instead:
apispec-c-files := $(call has-apispec, \
$(patsubst $(obj)/%.o,$(src)/%.c, \
$(filter-out %/built-in.a,$(real-obj-y) $(real-obj-m))))
apispec-y := $(patsubst $(src)/%.c,$(obj)/%.apispec.h,$(apispec-c-files))
2. The has-apispec grep needs to match the same set of keys that
tools/lib/python/kdoc/kdoc_apispec.py actually parses, which is
"contexts:", "context-flags:" and "context:" interchangeably (see
_get_section calls around line 866 of kdoc_apispec.py). The original
grep for "context-flags:" matched zero files in the tree (every
instrumented file uses "contexts:"), which is the latent bug behind
the build failure you saw. v4 widens the regex:
has-apispec = $(shell grep -lE \
'^[[:space:]]*\*[[:space:]]*(contexts|context-flags|context):' \
$(1) 2>/dev/null)
> > diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean
> > index 6ead00ec7313b..f78dbbe637f27 100644
> > --- a/scripts/Makefile.clean
> > +++ b/scripts/Makefile.clean
> > @@ -35,6 +35,9 @@ __clean-files := $(filter-out $(no-clean-files), $(__clean-files))
> >
> > __clean-files := $(wildcard $(addprefix $(obj)/, $(__clean-files)))
> >
> > +# Also clean generated apispec headers (computed dynamically in Makefile.build)
> > +__clean-files += $(wildcard $(obj)/*.apispec.h)
>
> We have a list of wildcard clean patterns in top-level Makefile
> (line 2114 ff.); please add '*.apispec.h' there instead.
Will fix.
> When I apply the series on top of v7.1, compilation fails with
>
> ../fs/open.c:2148:10: fatal error: open.apispec.h: No such file or directory
> ../fs/read_write.c:2519:10: fatal error: read_write.apispec.h: No such file or directory
This is the symptom of (2) above. fs/open.c and fs/read_write.c only
declare "contexts: process, sleepable" (no "context-flags:" anywhere in
the tree, confirmed via grep), so apispec-files was always empty and no
*.apispec.h ever got generated. With CONFIG_KAPI_SPEC=y the
"#if IS_ENABLED(CONFIG_KAPI_SPEC)" guarded include then fails. Also
reproducible on v7.0; thanks for catching it.
Thanks for the review and the kbuild sketch!
--
Thanks,
Sasha
^ permalink raw reply
* Re: [PATCH v2 3/3] Documentation: security-bugs: clarify requirements for AI-assisted reports
From: Leon Romanovsky @ 2026-05-05 14:09 UTC (permalink / raw)
To: Willy Tarreau
Cc: greg, security, Jonathan Corbet, skhan, workflows, linux-doc,
linux-kernel, Greg KH
In-Reply-To: <20260503113506.5710-4-w@1wt.eu>
On Sun, May 03, 2026 at 01:35:06PM +0200, Willy Tarreau wrote:
> AI tools are increasingly used to assist in bug discovery. While these
> tools can identify valid issues, reports that are submitted without
> manual verification often lack context, contain speculative impact
> assessments, or include unnecessary formatting. Such reports increase
> triage effort, waste maintainers' time and may be ignored.
>
> Reports where the reporter has verified the issue and the proposed fix
> typically meet quality standards. This documentation outlines specific
> requirements for length, formatting, and impact evaluation to reduce
> the effort needed to deal with these reports.
>
> Cc: Greg KH <gregkh@linuxfoundation.org>
> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Signed-off-by: Willy Tarreau <w@1wt.eu>
> ---
> Documentation/process/security-bugs.rst | 55 +++++++++++++++++++++++++
> 1 file changed, 55 insertions(+)
>
Thanks,
Reviewed-by: Leon Romanovsky <leon@kernel.org>
^ permalink raw reply
* Re: [PATCH v2 2/3] Documentation: security-bugs: explain what is and is not a security bug
From: Leon Romanovsky @ 2026-05-05 14:10 UTC (permalink / raw)
To: Willy Tarreau
Cc: greg, security, Jonathan Corbet, skhan, workflows, linux-doc,
linux-kernel, Greg KH
In-Reply-To: <20260503113506.5710-3-w@1wt.eu>
On Sun, May 03, 2026 at 01:35:05PM +0200, Willy Tarreau wrote:
> The use of automated tools to find bugs in random locations of the kernel
> induces a raise of security reports even if most of them should just be
> reported as regular bugs. This patch is an attempt at drawing a line
> between what qualifies as a security bug and what does not, hoping to
> improve the situation and ease decision on the reporter's side.
>
> It defers the enumeration to a new file, threat-model.rst, that tries
> to enumerate various classes of issues that are and are not security
> bugs. This should permit to more easily update this file for various
> subsystem-specific rules without having to revisit the security bug
> reporting guide.
>
> Cc: Greg KH <gregkh@linuxfoundation.org>
> Cc: Leon Romanovsky <leon@kernel.org>
> Suggested-by: Leon Romanovsky <leon@kernel.org>
> Suggested-by: Greg KH <gregkh@linuxfoundation.org>
> Signed-off-by: Willy Tarreau <w@1wt.eu>
> ---
> Documentation/process/index.rst | 1 +
> Documentation/process/security-bugs.rst | 28 +++
> Documentation/process/threat-model.rst | 231 ++++++++++++++++++++++++
> 3 files changed, 260 insertions(+)
> create mode 100644 Documentation/process/threat-model.rst
Thanks,
Reviewed-by: Leon Romanovsky <leon@kernel.org>
^ permalink raw reply
* Re: [PATCH v2 1/3] Documentation: security-bugs: do not systematically Cc the security team
From: Leon Romanovsky @ 2026-05-05 14:10 UTC (permalink / raw)
To: Willy Tarreau
Cc: greg, security, Jonathan Corbet, skhan, workflows, linux-doc,
linux-kernel, Greg KH
In-Reply-To: <20260503113506.5710-2-w@1wt.eu>
On Sun, May 03, 2026 at 01:35:04PM +0200, Willy Tarreau wrote:
> With the increase of automated reports, the security team is dealing
> with way more messages than really needed. The reporting process works
> well with most teams so there is no need to systematically involve the
> security team in reports.
>
> Let's suggest to keep it for small lists of recipients and new reporters
> only. This should continue to cover the risk of lost messages while
> reducing the volume from prolific reporters.
>
> Cc: Greg KH <gregkh@linuxfoundation.org>
> Cc: Leon Romanovsky <leon@kernel.org>
> Signed-off-by: Willy Tarreau <w@1wt.eu>
> ---
> Documentation/process/security-bugs.rst | 10 +++++++++-
> 1 file changed, 9 insertions(+), 1 deletion(-)
Thanks,
Reviewed-by: Leon Romanovsky <leon@kernel.org>
^ permalink raw reply
* Re: [PATCH v8 3/4] drm: Suppress intentional warning backtraces in scaling unit tests
From: Albert Esteve @ 2026-05-06 8:37 UTC (permalink / raw)
To: Maxime Ripard
Cc: Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar,
Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Andrew Morton, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, linux-kernel,
linux-arch, linux-kselftest, kunit-dev, dri-devel, workflows,
linux-riscv, linux-doc, peterz, Guenter Roeck,
Linux Kernel Functional Testing, Dan Carpenter, Maíra Canal,
Alessandro Carminati, Simona Vetter
In-Reply-To: <20260504-tentacled-free-lobster-38d8d9@houat>
On Mon, May 4, 2026 at 12:04 PM Maxime Ripard <mripard@kernel.org> wrote:
>
> Hi,
>
> On Mon, May 04, 2026 at 09:41:27AM +0200, Albert Esteve wrote:
> > From: Guenter Roeck <linux@roeck-us.net>
> >
> > The drm_test_rect_calc_hscale and drm_test_rect_calc_vscale unit tests
> > intentionally trigger warning backtraces by providing bad parameters to
> > the tested functions. What is tested is the return value, not the existence
> > of a warning backtrace. Suppress the backtraces to avoid clogging the
> > kernel log and distraction from real problems.
> >
> > Tested-by: Linux Kernel Functional Testing <lkft@linaro.org>
> > Acked-by: Dan Carpenter <dan.carpenter@linaro.org>
> > Acked-by: Maíra Canal <mcanal@igalia.com>
> > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > Cc: David Airlie <airlied@gmail.com>
> > Cc: Daniel Vetter <daniel@ffwll.ch>
> > Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> > Signed-off-by: Alessandro Carminati <acarmina@redhat.com>
> > Acked-by: David Gow <david@davidgow.net>
> > Signed-off-by: Albert Esteve <aesteve@redhat.com>
> > ---
> > drivers/gpu/drm/tests/drm_rect_test.c | 23 +++++++++++++++++++----
> > 1 file changed, 19 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/tests/drm_rect_test.c b/drivers/gpu/drm/tests/drm_rect_test.c
> > index 17e1f34b76101..818e16e80c8f9 100644
> > --- a/drivers/gpu/drm/tests/drm_rect_test.c
> > +++ b/drivers/gpu/drm/tests/drm_rect_test.c
> > @@ -409,8 +409,16 @@ static void drm_test_rect_calc_hscale(struct kunit *test)
> > const struct drm_rect_scale_case *params = test->param_value;
> > int scaling_factor;
> >
> > - scaling_factor = drm_rect_calc_hscale(¶ms->src, ¶ms->dst,
> > - params->min_range, params->max_range);
> > + /*
> > + * drm_rect_calc_hscale() generates a warning backtrace whenever bad
> > + * parameters are passed to it. This affects all unit tests with an
> > + * error code in expected_scaling_factor.
> > + */
> > + kunit_warning_suppress(test) {
> > + scaling_factor = drm_rect_calc_hscale(¶ms->src, ¶ms->dst,
> > + params->min_range,
> > + params->max_range);
> > + }
> >
> > KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
> > }
> > @@ -420,8 +428,15 @@ static void drm_test_rect_calc_vscale(struct kunit *test)
> > const struct drm_rect_scale_case *params = test->param_value;
> > int scaling_factor;
> >
> > - scaling_factor = drm_rect_calc_vscale(¶ms->src, ¶ms->dst,
> > - params->min_range, params->max_range);
> > + /*
> > + * drm_rect_calc_vscale() generates a warning backtrace whenever bad
> > + * parameters are passed to it. This affects all unit tests with an
> > + * error code in expected_scaling_factor.
> > + */
> > + kunit_warning_suppress(test) {
> > + scaling_factor = drm_rect_calc_vscale(¶ms->src, ¶ms->dst,
> > + params->min_range, params->max_range);
> > + }
> >
> > KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
> > }
>
> For both I think we should add KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT calls, no?
Hi Maxime,
It may indeed add verification value by ensuring the call actually
generates the expected warning.
The original patch did not include count checks on the version I
inherited it from (i.e.,
https://lore.kernel.org/all/20250526132755.166150-5-acarmina@redhat.com/),
so I kept the same approach while adapting to the API changes. That
said, the check is simple to add, so I could include it in the next
version.
BR,
Albert
>
> Maxime
^ permalink raw reply
* Re: [PATCH v8 1/4] bug/kunit: Core support for suppressing warning backtraces
From: David Gow @ 2026-05-06 9:38 UTC (permalink / raw)
To: Albert Esteve, Arnd Bergmann, Brendan Higgins, Rae Moar,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jonathan Corbet, Shuah Khan, Andrew Morton,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
workflows, linux-riscv, linux-doc, peterz, Alessandro Carminati,
Guenter Roeck, Kees Cook
In-Reply-To: <20260504-kunit_add_support-v8-1-3e5957cdd235@redhat.com>
Le 04/05/2026 à 3:41 PM, Albert Esteve a écrit :
> 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 suppress warning backtraces
> originating from the current kthread while executing test code. Since
> each KUnit test runs in its own kthread, this effectively scopes
> suppression to the test that enabled it. Limit changes to generic code
> to the absolute minimum.
>
> Implementation details:
> Suppression is integrated into the existing KUnit hooks infrastructure
> in test-bug.h, reusing the kunit_running static branch for zero
> overhead when no tests are running.
>
> Suppression is checked at three points in the warning path:
> - In warn_slowpath_fmt(), the check runs before any output, fully
> suppressing both message and backtrace. This covers architectures
> without __WARN_FLAGS.
> - In __warn_printk(), the check suppresses the warning message text.
> This covers architectures that define __WARN_FLAGS but not their own
> __WARN_printf (arm64, loongarch, parisc, powerpc, riscv, sh), where
> the message is printed before the trap enters __report_bug().
> - In __report_bug(), the check runs before __warn() is called,
> suppressing the backtrace and stack dump.
>
> To avoid double-counting on architectures where both __warn_printk()
> and __report_bug() run for the same warning, kunit_is_suppressed_warning()
> takes a bool parameter: true to increment the suppression counter
> (used in warn_slowpath_fmt and __report_bug), false to check only
> (used in __warn_printk).
>
> The suppression state is dynamically allocated via kunit_kzalloc() and
> tied to the KUnit test lifecycle via kunit_add_action(), ensuring
> automatic cleanup at test exit. Writer-side access to the global
> suppression list is serialized with a spinlock; readers use RCU.
>
> Three API forms are provided:
> - kunit_warning_suppress(test) { ... }: scoped, uses __cleanup for
> automatic teardown on scope exit, kunit_add_action() as safety net
> for abnormal exits (e.g. kthread_exit from failed assertions).
> Suppression handle is only accessible inside the block.
> - KUNIT_START/END_SUPPRESSED_WARNING(test): manual macros for larger
> blocks or when warning counts need to be checked after suppression
> ends. Limited to one pair per scope.
> - kunit_start/end_suppress_warning(test): direct functions returning
> an explicit handle, for retaining the handle within the test,
> or for cross-function usage.
>
> 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>
> ---
This looks pretty good to me, thanks.
Reviewed-by: David Gow <david@davidgow.net>
It's maybe slightly over-the-top to now have three different ways of
enabling warning suppression: I'd probably personally get rid of
KUNIT_START/END_SUPPRESSED_WARNING() if we had to lose one. But if
there's a real reason to prefer keeping all three, it's not actually a
problem to do so.
Regardless, this series is looking pretty ready to me. Let me know if
you're planning a v9, otherwise we'll take this when you're ready.
Cheers,
-- David
> include/kunit/test-bug.h | 25 +++++++++
> include/kunit/test.h | 138 +++++++++++++++++++++++++++++++++++++++++++++++
> kernel/panic.c | 15 +++++-
> lib/bug.c | 10 ++++
> lib/kunit/Makefile | 3 +-
> lib/kunit/bug.c | 115 +++++++++++++++++++++++++++++++++++++++
> lib/kunit/hooks-impl.h | 2 +
> 7 files changed, 305 insertions(+), 3 deletions(-)
>
> diff --git a/include/kunit/test-bug.h b/include/kunit/test-bug.h
> index 47aa8f21ccce8..6237e48ceadfd 100644
> --- a/include/kunit/test-bug.h
> +++ b/include/kunit/test-bug.h
> @@ -23,6 +23,7 @@ DECLARE_STATIC_KEY_FALSE(kunit_running);
> extern struct kunit_hooks_table {
> __printf(3, 4) void (*fail_current_test)(const char*, int, const char*, ...);
> void *(*get_static_stub_address)(struct kunit *test, void *real_fn_addr);
> + bool (*is_suppressed_warning)(bool count);
> } kunit_hooks;
>
> /**
> @@ -60,9 +61,33 @@ static inline struct kunit *kunit_get_current_test(void)
> } \
> } while (0)
>
> +/**
> + * kunit_is_suppressed_warning() - Check if warnings are being suppressed
> + * by the current KUnit test.
> + * @count: if true, increment the suppression counter on match.
> + *
> + * Returns true if the current task has active warning suppression.
> + * Uses the kunit_running static branch for zero overhead when no tests run.
> + *
> + * A single WARN*() may traverse multiple call sites in the warning path
> + * (e.g., __warn_printk() and __report_bug()). Pass @count = true at the
> + * primary suppression point to count each warning exactly once, and
> + * @count = false at secondary points to suppress output without
> + * inflating the count.
> + */
> +static inline bool kunit_is_suppressed_warning(bool count)
> +{
> + if (!static_branch_unlikely(&kunit_running))
> + return false;
> +
> + return kunit_hooks.is_suppressed_warning &&
> + kunit_hooks.is_suppressed_warning(count);
> +}
> +
> #else
>
> static inline struct kunit *kunit_get_current_test(void) { return NULL; }
> +static inline bool kunit_is_suppressed_warning(bool count) { return false; }
>
> #define kunit_fail_current_test(fmt, ...) do {} while (0)
>
> diff --git a/include/kunit/test.h b/include/kunit/test.h
> index 9cd1594ab697d..f278ec028019c 100644
> --- a/include/kunit/test.h
> +++ b/include/kunit/test.h
> @@ -1795,4 +1795,142 @@ do { \
> // include resource.h themselves if they need it.
> #include <kunit/resource.h>
>
> +/*
> + * Warning backtrace suppression API.
> + *
> + * Suppresses WARN*() backtraces on the current task while active. Three forms
> + * are provided, in order of convenience:
> + *
> + * - Scoped: kunit_warning_suppress(test) { ... }
> + * Suppression is active for the duration of the block. On normal exit,
> + * the for-loop increment deactivates suppression. On early exit (break,
> + * return, goto), the __cleanup attribute fires. On kthread_exit() (e.g.,
> + * a failed KUnit assertion), kunit_add_action() cleans up at test
> + * teardown. The suppression handle is only accessible inside the block,
> + * so warning counts must be checked before the block exits.
> + *
> + * - Manual macros: KUNIT_[START|END]_SUPPRESSED_WARNING(test)
> + * Suppression spans an explicit range in the same scope. kunit_add_action()
> + * guarantees cleanup even if KUNIT_END_SUPPRESSED_WARNING() is not reached.
> + * Prefer this form when suppressing warnings across a large block where
> + * extra indentation is undesirable, or when the warning count needs to be
> + * checked after suppression ends. Limited to one pair per scope.
> + *
> + * - Direct: kunit_start_suppress_warning() / kunit_end_suppress_warning()
> + * The underlying functions, returning an explicit handle pointer. Use
> + * when the handle needs to be retained (e.g., for post-suppression
> + * count checks) or passed across helper functions.
> + */
> +struct kunit_suppressed_warning;
> +
> +struct kunit_suppressed_warning *
> +kunit_start_suppress_warning(struct kunit *test);
> +void kunit_end_suppress_warning(struct kunit *test,
> + struct kunit_suppressed_warning *w);
> +int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w);
> +void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp);
> +bool kunit_has_active_suppress_warning(void);
> +
> +/**
> + * kunit_warning_suppress() - Suppress WARN*() backtraces for the duration
> + * of a block.
> + * @test: The test context object.
> + *
> + * Scoped form of the suppression API. Suppression starts when the block is
> + * entered and ends automatically when the block exits through any path. See
> + * the section comment above for the cleanup guarantees on each exit path.
> + * Fails the test if suppression is already active; nesting is not supported.
> + *
> + * The warning count can be checked inside the block via
> + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(). The handle is not accessible
> + * after the block exits.
> + *
> + * Example::
> + *
> + * kunit_warning_suppress(test) {
> + * trigger_warning();
> + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> + * }
> + */
> +#define kunit_warning_suppress(test) \
> + for (struct kunit_suppressed_warning *__kunit_suppress \
> + __cleanup(__kunit_suppress_auto_cleanup) = \
> + kunit_start_suppress_warning(test); \
> + __kunit_suppress; \
> + kunit_end_suppress_warning(test, __kunit_suppress), \
> + __kunit_suppress = NULL)
> +
> +/**
> + * KUNIT_START_SUPPRESSED_WARNING() - Begin suppressing WARN*() backtraces.
> + * @test: The test context object.
> + *
> + * Manual form of the suppression API. Must be paired with
> + * KUNIT_END_SUPPRESSED_WARNING() in the same scope. See the section comment
> + * above for cleanup guarantees. Fails the test if suppression is already
> + * active; nesting is not supported. Limited to one pair per scope; use
> + * sequential kunit_warning_suppress() blocks or the direct function API
> + * when more than one suppression region is needed.
> + *
> + * Example::
> + *
> + * KUNIT_START_SUPPRESSED_WARNING(test);
> + * trigger_code_that_should_warn_once();
> + * KUNIT_END_SUPPRESSED_WARNING(test);
> + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> + */
> +#define KUNIT_START_SUPPRESSED_WARNING(test) \
> + struct kunit_suppressed_warning *__kunit_suppress = \
> + kunit_start_suppress_warning(test)
> +
> +/**
> + * KUNIT_END_SUPPRESSED_WARNING() - End suppressing WARN*() backtraces.
> + * @test: The test context object.
> + *
> + * Deactivates suppression started by KUNIT_START_SUPPRESSED_WARNING().
> + * The warning count remains readable via KUNIT_SUPPRESSED_WARNING_COUNT()
> + * after this call.
> + */
> +#define KUNIT_END_SUPPRESSED_WARNING(test) \
> + kunit_end_suppress_warning(test, __kunit_suppress)
> +
> +/**
> + * KUNIT_SUPPRESSED_WARNING_COUNT() - Returns the suppressed warning count.
> + *
> + * Returns the number of WARN*() calls suppressed since the current
> + * suppression block started, or 0 if the handle is NULL. Usable inside a
> + * kunit_warning_suppress() block or after KUNIT_END_SUPPRESSED_WARNING().
> + */
> +#define KUNIT_SUPPRESSED_WARNING_COUNT() \
> + kunit_suppressed_warning_count(__kunit_suppress)
> +
> +/**
> + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT() - Sets an expectation that the
> + * suppressed warning count equals
> + * @expected.
> + * @test: The test context object.
> + * @expected: an expression that evaluates to the expected warning count.
> + *
> + * Sets an expectation that the number of suppressed WARN*() calls equals
> + * @expected. This is semantically equivalent to
> + * KUNIT_EXPECT_EQ(@test, KUNIT_SUPPRESSED_WARNING_COUNT(), @expected).
> + * See KUNIT_EXPECT_EQ() for more information.
> + */
> +#define KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, expected) \
> + KUNIT_EXPECT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected)
> +
> +/**
> + * KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT() - Sets an assertion that the
> + * suppressed warning count equals
> + * @expected.
> + * @test: The test context object.
> + * @expected: an expression that evaluates to the expected warning count.
> + *
> + * Sets an assertion that the number of suppressed WARN*() calls equals
> + * @expected. This is the same as KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(),
> + * except it causes an assertion failure (see KUNIT_ASSERT_TRUE()) when the
> + * assertion is not met.
> + */
> +#define KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT(test, expected) \
> + KUNIT_ASSERT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected)
> +
> #endif /* _KUNIT_TEST_H */
> diff --git a/kernel/panic.c b/kernel/panic.c
> index c78600212b6c1..697d8ca054bef 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/test-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(true))
> + return;
> +
> + rcu = warn_rcu_enter();
> +
> pr_warn(CUT_HERE);
>
> if (!fmt) {
> @@ -1102,9 +1108,14 @@ EXPORT_SYMBOL(warn_slowpath_fmt);
> #else
> void __warn_printk(const char *fmt, ...)
> {
> - bool rcu = warn_rcu_enter();
> + bool rcu;
> va_list args;
>
> + if (kunit_is_suppressed_warning(false))
> + return;
> +
> + rcu = warn_rcu_enter();
> +
> pr_warn(CUT_HERE);
>
> va_start(args, fmt);
> diff --git a/lib/bug.c b/lib/bug.c
> index 623c467a8b76c..a5cebde554ed8 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/test-bug.h>
>
> extern struct bug_entry __start___bug_table[], __stop___bug_table[];
>
> @@ -223,6 +224,15 @@ 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;
>
> +#ifdef CONFIG_KUNIT
> + /*
> + * Before the once logic so suppressed warnings do not consume
> + * the single-fire budget of WARN_ON_ONCE().
> + */
> + if (warning && kunit_is_suppressed_warning(true))
> + return BUG_TRAP_TYPE_WARN;
> +#endif
> +
> if (warning && once) {
> if (done)
> return BUG_TRAP_TYPE_WARN;
> diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
> index 656f1fa35abcc..4592f9d0aa8dd 100644
> --- a/lib/kunit/Makefile
> +++ b/lib/kunit/Makefile
> @@ -10,7 +10,8 @@ kunit-objs += test.o \
> executor.o \
> attributes.o \
> device.o \
> - platform.o
> + platform.o \
> + bug.o
>
> ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
> kunit-objs += debugfs.o
> diff --git a/lib/kunit/bug.c b/lib/kunit/bug.c
> new file mode 100644
> index 0000000000000..b0b6778d7399a
> --- /dev/null
> +++ b/lib/kunit/bug.c
> @@ -0,0 +1,115 @@
> +// 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/resource.h>
> +#include <linux/export.h>
> +#include <linux/rculist.h>
> +#include <linux/sched.h>
> +#include <linux/spinlock.h>
> +
> +#include "hooks-impl.h"
> +
> +struct kunit_suppressed_warning {
> + struct list_head node;
> + struct task_struct *task;
> + struct kunit *test;
> + int counter;
> +};
> +
> +static LIST_HEAD(suppressed_warnings);
> +static DEFINE_SPINLOCK(suppressed_warnings_lock);
> +
> +static void kunit_suppress_warning_remove(struct kunit_suppressed_warning *w)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&suppressed_warnings_lock, flags);
> + list_del_rcu(&w->node);
> + spin_unlock_irqrestore(&suppressed_warnings_lock, flags);
> + synchronize_rcu(); /* Wait for readers to finish */
> +}
> +
> +KUNIT_DEFINE_ACTION_WRAPPER(kunit_suppress_warning_cleanup,
> + kunit_suppress_warning_remove,
> + struct kunit_suppressed_warning *);
> +
> +bool kunit_has_active_suppress_warning(void)
> +{
> + return __kunit_is_suppressed_warning_impl(false);
> +}
> +EXPORT_SYMBOL_GPL(kunit_has_active_suppress_warning);
> +
> +struct kunit_suppressed_warning *
> +kunit_start_suppress_warning(struct kunit *test)
> +{
> + struct kunit_suppressed_warning *w;
> + unsigned long flags;
> + int ret;
> +
> + if (kunit_has_active_suppress_warning()) {
> + KUNIT_FAIL(test, "Another suppression block is already active");
> + return NULL;
> + }
> +
> + w = kunit_kzalloc(test, sizeof(*w), GFP_KERNEL);
> + if (!w)
> + return NULL;
> +
> + w->task = current;
> + w->test = test;
> +
> + spin_lock_irqsave(&suppressed_warnings_lock, flags);
> + list_add_rcu(&w->node, &suppressed_warnings);
> + spin_unlock_irqrestore(&suppressed_warnings_lock, flags);
> +
> + ret = kunit_add_action_or_reset(test,
> + kunit_suppress_warning_cleanup, w);
> + if (ret)
> + return NULL;
> +
> + return w;
> +}
> +EXPORT_SYMBOL_GPL(kunit_start_suppress_warning);
> +
> +void kunit_end_suppress_warning(struct kunit *test,
> + struct kunit_suppressed_warning *w)
> +{
> + if (!w)
> + return;
> + kunit_release_action(test, kunit_suppress_warning_cleanup, w);
> +}
> +EXPORT_SYMBOL_GPL(kunit_end_suppress_warning);
> +
> +void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp)
> +{
> + if (*wp)
> + kunit_end_suppress_warning((*wp)->test, *wp);
> +}
> +EXPORT_SYMBOL_GPL(__kunit_suppress_auto_cleanup);
> +
> +int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w)
> +{
> + return w ? w->counter : 0;
> +}
> +EXPORT_SYMBOL_GPL(kunit_suppressed_warning_count);
> +
> +bool __kunit_is_suppressed_warning_impl(bool count)
> +{
> + struct kunit_suppressed_warning *w;
> +
> + guard(rcu)();
> + list_for_each_entry_rcu(w, &suppressed_warnings, node) {
> + if (w->task == current) {
> + if (count)
> + w->counter++;
> + return true;
> + }
> + }
> +
> + return false;
> +}
> diff --git a/lib/kunit/hooks-impl.h b/lib/kunit/hooks-impl.h
> index 4e71b2d0143ba..d8720f2616925 100644
> --- a/lib/kunit/hooks-impl.h
> +++ b/lib/kunit/hooks-impl.h
> @@ -19,6 +19,7 @@ void __printf(3, 4) __kunit_fail_current_test_impl(const char *file,
> int line,
> const char *fmt, ...);
> void *__kunit_get_static_stub_address_impl(struct kunit *test, void *real_fn_addr);
> +bool __kunit_is_suppressed_warning_impl(bool count);
>
> /* Code to set all of the function pointers. */
> static inline void kunit_install_hooks(void)
> @@ -26,6 +27,7 @@ static inline void kunit_install_hooks(void)
> /* Install the KUnit hook functions. */
> kunit_hooks.fail_current_test = __kunit_fail_current_test_impl;
> kunit_hooks.get_static_stub_address = __kunit_get_static_stub_address_impl;
> + kunit_hooks.is_suppressed_warning = __kunit_is_suppressed_warning_impl;
> }
>
> #endif /* _KUNIT_HOOKS_IMPL_H */
>
^ permalink raw reply
* Re: [PATCH v8 2/4] kunit: Add backtrace suppression self-tests
From: David Gow @ 2026-05-06 9:38 UTC (permalink / raw)
To: Albert Esteve, Arnd Bergmann, Brendan Higgins, Rae Moar,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jonathan Corbet, Shuah Khan, Andrew Morton,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
workflows, linux-riscv, linux-doc, peterz, Guenter Roeck,
Linux Kernel Functional Testing, Dan Carpenter,
Alessandro Carminati, Kees Cook
In-Reply-To: <20260504-kunit_add_support-v8-2-3e5957cdd235@redhat.com>
Le 04/05/2026 à 3:41 PM, Albert Esteve a écrit :
> From: Guenter Roeck <linux@roeck-us.net>
>
> Add unit tests to verify that warning backtrace suppression works.
>
> Tests cover all three API forms:
> - Scoped: kunit_warning_suppress() with in-block count verification
> and post-block inactivity check.
> - Manual macros: KUNIT_START/END_SUPPRESSED_WARNING() with WARN()
> and WARN_ON(), both direct and through helper functions, as well
> as multiple warnings in a single block.
> - Direct functions: kunit_start/end_suppress_warning() with
> sequential independent suppression blocks and per-block counts.
>
> Furthermore, tests verify incremental warning counting, that
> kunit_has_active_suppress_warning() transitions correctly around
> suppression boundaries, and that suppression active in the test
> kthread does not leak to a separate kthread.
>
> If backtrace suppression does _not_ work, the unit tests will likely
> trigger unsuppressed backtraces, which should actually help to get
> the affected architectures / platforms fixed.
>
> Tested-by: Linux Kernel Functional Testing <lkft@linaro.org>
> Acked-by: Dan Carpenter <dan.carpenter@linaro.org>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Alessandro Carminati <acarmina@redhat.com>
> Reviewed-by: David Gow <david@davidgow.net>
> Signed-off-by: Albert Esteve <aesteve@redhat.com>
> ---
Looks good to me, thanks!
This is still:
Reviewed-by: David Gow <david@davidgow.net>
Cheers,
-- David
> lib/kunit/Makefile | 1 +
> lib/kunit/backtrace-suppression-test.c | 184 +++++++++++++++++++++++++++++++++
> 2 files changed, 185 insertions(+)
>
> diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
> index 4592f9d0aa8dd..2e8a6b71a2ab0 100644
> --- a/lib/kunit/Makefile
> +++ b/lib/kunit/Makefile
> @@ -22,6 +22,7 @@ obj-$(if $(CONFIG_KUNIT),y) += hooks.o
>
> obj-$(CONFIG_KUNIT_TEST) += kunit-test.o
> obj-$(CONFIG_KUNIT_TEST) += platform-test.o
> +obj-$(CONFIG_KUNIT_TEST) += backtrace-suppression-test.o
>
> # string-stream-test compiles built-in only.
> ifeq ($(CONFIG_KUNIT_TEST),y)
> diff --git a/lib/kunit/backtrace-suppression-test.c b/lib/kunit/backtrace-suppression-test.c
> new file mode 100644
> index 0000000000000..0e6fb685d2cbb
> --- /dev/null
> +++ b/lib/kunit/backtrace-suppression-test.c
> @@ -0,0 +1,184 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * KUnit test for suppressing warning tracebacks.
> + *
> + * Copyright (C) 2024, Guenter Roeck
> + * Author: Guenter Roeck <linux@roeck-us.net>
> + */
> +
> +#include <kunit/test.h>
> +#include <linux/bug.h>
> +#include <linux/completion.h>
> +#include <linux/kthread.h>
> +
> +static void backtrace_suppression_test_warn_direct(struct kunit *test)
> +{
> + kunit_warning_suppress(test) {
> + WARN(1, "This backtrace should be suppressed");
> + /*
> + * Count must be checked inside the scope; the handle
> + * is not accessible after the block exits.
> + */
> + KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> + }
> + KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
> +}
> +
> +static void trigger_backtrace_warn(void)
> +{
> + WARN(1, "This backtrace should be suppressed");
> +}
> +
> +static void backtrace_suppression_test_warn_indirect(struct kunit *test)
> +{
> + KUNIT_START_SUPPRESSED_WARNING(test);
> + trigger_backtrace_warn();
> + KUNIT_END_SUPPRESSED_WARNING(test);
> +
> + KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> +}
> +
> +static void backtrace_suppression_test_warn_multi(struct kunit *test)
> +{
> + KUNIT_START_SUPPRESSED_WARNING(test);
> + WARN(1, "This backtrace should be suppressed");
> + trigger_backtrace_warn();
> + KUNIT_END_SUPPRESSED_WARNING(test);
> +
> + KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 2);
> +}
> +
> +static void backtrace_suppression_test_warn_on_direct(struct kunit *test)
> +{
> + if (!IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE) && !IS_ENABLED(CONFIG_KALLSYMS))
> + kunit_skip(test, "requires CONFIG_DEBUG_BUGVERBOSE or CONFIG_KALLSYMS");
> +
> + KUNIT_START_SUPPRESSED_WARNING(test);
> + WARN_ON(1);
> + KUNIT_END_SUPPRESSED_WARNING(test);
> +
> + KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> +}
> +
> +static void trigger_backtrace_warn_on(void)
> +{
> + WARN_ON(1);
> +}
> +
> +static void backtrace_suppression_test_warn_on_indirect(struct kunit *test)
> +{
> + if (!IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE))
> + kunit_skip(test, "requires CONFIG_DEBUG_BUGVERBOSE");
> +
> + KUNIT_START_SUPPRESSED_WARNING(test);
> + trigger_backtrace_warn_on();
> + KUNIT_END_SUPPRESSED_WARNING(test);
> +
> + KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> +}
> +
> +static void backtrace_suppression_test_count(struct kunit *test)
> +{
> + KUNIT_START_SUPPRESSED_WARNING(test);
> +
> + KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 0);
> +
> + WARN(1, "suppressed");
> + KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> +
> + WARN(1, "suppressed again");
> + KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 2);
> +
> + KUNIT_END_SUPPRESSED_WARNING(test);
> +}
> +
> +static void backtrace_suppression_test_active_state(struct kunit *test)
> +{
> + KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
> +
> + KUNIT_START_SUPPRESSED_WARNING(test);
> + KUNIT_EXPECT_TRUE(test, kunit_has_active_suppress_warning());
> + KUNIT_END_SUPPRESSED_WARNING(test);
> +
> + KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
> +
> + kunit_warning_suppress(test) {
> + KUNIT_EXPECT_TRUE(test, kunit_has_active_suppress_warning());
> + }
> +
> + KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
> +}
> +
> +static void backtrace_suppression_test_multi_scope(struct kunit *test)
> +{
> + struct kunit_suppressed_warning *sw1, *sw2;
> +
> + if (!IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE))
> + kunit_skip(test, "requires CONFIG_DEBUG_BUGVERBOSE");
> +
> + sw1 = kunit_start_suppress_warning(test);
> + trigger_backtrace_warn_on();
> + WARN(1, "suppressed by sw1");
> + kunit_end_suppress_warning(test, sw1);
> +
> + sw2 = kunit_start_suppress_warning(test);
> + WARN(1, "suppressed by sw2");
> + kunit_end_suppress_warning(test, sw2);
> +
> + KUNIT_EXPECT_EQ(test, kunit_suppressed_warning_count(sw1), 2);
> + KUNIT_EXPECT_EQ(test, kunit_suppressed_warning_count(sw2), 1);
> +}
> +
> +struct cross_kthread_data {
> + bool was_active;
> + struct completion done;
> +};
> +
> +static int cross_kthread_fn(void *data)
> +{
> + struct cross_kthread_data *d = data;
> +
> + d->was_active = kunit_has_active_suppress_warning();
> + complete(&d->done);
> + return 0;
> +}
> +
> +static void backtrace_suppression_test_cross_kthread(struct kunit *test)
> +{
> + struct cross_kthread_data data;
> + struct task_struct *task;
> +
> + init_completion(&data.done);
> +
> + KUNIT_START_SUPPRESSED_WARNING(test);
> +
> + task = kthread_run(cross_kthread_fn, &data, "kunit-cross-test");
> + KUNIT_ASSERT_FALSE(test, IS_ERR(task));
> + wait_for_completion(&data.done);
> +
> + KUNIT_END_SUPPRESSED_WARNING(test);
> +
> + KUNIT_EXPECT_FALSE(test, data.was_active);
> +}
> +
> +static struct kunit_case backtrace_suppression_test_cases[] = {
> + KUNIT_CASE(backtrace_suppression_test_warn_direct),
> + KUNIT_CASE(backtrace_suppression_test_warn_indirect),
> + KUNIT_CASE(backtrace_suppression_test_warn_multi),
> + KUNIT_CASE(backtrace_suppression_test_warn_on_direct),
> + KUNIT_CASE(backtrace_suppression_test_warn_on_indirect),
> + KUNIT_CASE(backtrace_suppression_test_count),
> + KUNIT_CASE(backtrace_suppression_test_active_state),
> + KUNIT_CASE(backtrace_suppression_test_multi_scope),
> + KUNIT_CASE(backtrace_suppression_test_cross_kthread),
> + {}
> +};
> +
> +static struct kunit_suite backtrace_suppression_test_suite = {
> + .name = "backtrace-suppression-test",
> + .test_cases = backtrace_suppression_test_cases,
> +};
> +kunit_test_suites(&backtrace_suppression_test_suite);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("KUnit test to verify warning backtrace suppression");
>
^ permalink raw reply
* Re: [PATCH v8 3/4] drm: Suppress intentional warning backtraces in scaling unit tests
From: David Gow @ 2026-05-06 9:38 UTC (permalink / raw)
To: Albert Esteve, Arnd Bergmann, Brendan Higgins, Rae Moar,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jonathan Corbet, Shuah Khan, Andrew Morton,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
workflows, linux-riscv, linux-doc, peterz, Guenter Roeck,
Linux Kernel Functional Testing, Dan Carpenter, Maíra Canal,
Alessandro Carminati, Simona Vetter
In-Reply-To: <20260504-kunit_add_support-v8-3-3e5957cdd235@redhat.com>
Le 04/05/2026 à 3:41 PM, Albert Esteve a écrit :
> From: Guenter Roeck <linux@roeck-us.net>
>
> The drm_test_rect_calc_hscale and drm_test_rect_calc_vscale unit tests
> intentionally trigger warning backtraces by providing bad parameters to
> the tested functions. What is tested is the return value, not the existence
> of a warning backtrace. Suppress the backtraces to avoid clogging the
> kernel log and distraction from real problems.
>
> Tested-by: Linux Kernel Functional Testing <lkft@linaro.org>
> Acked-by: Dan Carpenter <dan.carpenter@linaro.org>
> Acked-by: Maíra Canal <mcanal@igalia.com>
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Cc: David Airlie <airlied@gmail.com>
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Alessandro Carminati <acarmina@redhat.com>
> Acked-by: David Gow <david@davidgow.net>
> Signed-off-by: Albert Esteve <aesteve@redhat.com>
> ---
I'm happy with this either with or without the extra check for the
warning count.
Acked-by: David Gow <david@davidgow.net>
We'll take this patch in the kunit tree along with the rest of the
series once everyone's happy.
Cheers,
-- David
> drivers/gpu/drm/tests/drm_rect_test.c | 23 +++++++++++++++++++----
> 1 file changed, 19 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/tests/drm_rect_test.c b/drivers/gpu/drm/tests/drm_rect_test.c
> index 17e1f34b76101..818e16e80c8f9 100644
> --- a/drivers/gpu/drm/tests/drm_rect_test.c
> +++ b/drivers/gpu/drm/tests/drm_rect_test.c
> @@ -409,8 +409,16 @@ static void drm_test_rect_calc_hscale(struct kunit *test)
> const struct drm_rect_scale_case *params = test->param_value;
> int scaling_factor;
>
> - scaling_factor = drm_rect_calc_hscale(¶ms->src, ¶ms->dst,
> - params->min_range, params->max_range);
> + /*
> + * drm_rect_calc_hscale() generates a warning backtrace whenever bad
> + * parameters are passed to it. This affects all unit tests with an
> + * error code in expected_scaling_factor.
> + */
> + kunit_warning_suppress(test) {
> + scaling_factor = drm_rect_calc_hscale(¶ms->src, ¶ms->dst,
> + params->min_range,
> + params->max_range);
> + }
>
> KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
> }
> @@ -420,8 +428,15 @@ static void drm_test_rect_calc_vscale(struct kunit *test)
> const struct drm_rect_scale_case *params = test->param_value;
> int scaling_factor;
>
> - scaling_factor = drm_rect_calc_vscale(¶ms->src, ¶ms->dst,
> - params->min_range, params->max_range);
> + /*
> + * drm_rect_calc_vscale() generates a warning backtrace whenever bad
> + * parameters are passed to it. This affects all unit tests with an
> + * error code in expected_scaling_factor.
> + */
> + kunit_warning_suppress(test) {
> + scaling_factor = drm_rect_calc_vscale(¶ms->src, ¶ms->dst,
> + params->min_range, params->max_range);
> + }
>
> KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
> }
>
^ permalink raw reply
* Re: [PATCH v8 4/4] kunit: Add documentation for warning backtrace suppression API
From: David Gow @ 2026-05-06 9:38 UTC (permalink / raw)
To: Albert Esteve, Arnd Bergmann, Brendan Higgins, Rae Moar,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jonathan Corbet, Shuah Khan, Andrew Morton,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
workflows, linux-riscv, linux-doc, peterz, Guenter Roeck,
Linux Kernel Functional Testing, Dan Carpenter,
Alessandro Carminati, Kees Cook
In-Reply-To: <20260504-kunit_add_support-v8-4-3e5957cdd235@redhat.com>
Le 04/05/2026 à 3:41 PM, Albert Esteve a écrit :
> From: Guenter Roeck <linux@roeck-us.net>
>
> Document API functions for suppressing warning backtraces.
>
> Tested-by: Linux Kernel Functional Testing <lkft@linaro.org>
> Acked-by: Dan Carpenter <dan.carpenter@linaro.org>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> Reviewed-by: David Gow <davidgow@google.com>
> Signed-off-by: Alessandro Carminati <acarmina@redhat.com>
> Reviewed-by: David Gow <david@davidgow.net>
> Signed-off-by: Albert Esteve <aesteve@redhat.com>
> ---
This is great, thanks!
Reviewed-by: David Gow <david@davidgow.net>
Cheers,
-- David
> Documentation/dev-tools/kunit/usage.rst | 63 ++++++++++++++++++++++++++++++++-
> 1 file changed, 62 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst
> index ebd06f5ea4550..25724f7e72969 100644
> --- a/Documentation/dev-tools/kunit/usage.rst
> +++ b/Documentation/dev-tools/kunit/usage.rst
> @@ -157,6 +157,67 @@ Alternatively, one can take full control over the error message by using
> if (some_setup_function())
> KUNIT_FAIL(test, "Failed to setup thing for testing");
>
> +Suppressing warning backtraces
> +------------------------------
> +
> +Some unit tests trigger warning backtraces either intentionally or as a side
> +effect. Such backtraces are normally undesirable since they distract from
> +the actual test and may result in the impression that there is a problem.
> +
> +Backtraces can be suppressed with **task-scoped suppression**: while
> +suppression is active on the current task, the backtrace and stack dump from
> +``WARN*()``, ``WARN_ON*()``, and related macros on that task are suppressed.
> +Three API forms are available, in order of convenience.
> +
> +- Scoped suppression is the simplest form. Wrap the code that triggers
> + warnings in a ``kunit_warning_suppress()`` block:
> +
> +.. code-block:: c
> +
> + static void some_test(struct kunit *test)
> + {
> + kunit_warning_suppress(test) {
> + trigger_backtrace();
> + KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> + }
> + }
> +
> +.. note::
> + The warning count must be checked inside the block; the suppression handle
> + is not accessible after the block exits.
> +
> +- Manual macros are useful when the suppressed region is large enough that
> + extra indentation is undesirable, or when the warning count needs to be
> + checked after suppression ends. ``KUNIT_START_SUPPRESSED_WARNING()`` must
> + appear before ``KUNIT_END_SUPPRESSED_WARNING()`` in the same scope.
> + Limited to one pair per scope.
> +
> +.. code-block:: c
> +
> + static void some_test(struct kunit *test)
> + {
> + KUNIT_START_SUPPRESSED_WARNING(test);
> + trigger_backtrace();
> + KUNIT_END_SUPPRESSED_WARNING(test);
> +
> + KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> + }
> +
> +- Direct functions return an explicit handle pointer. Use them when the handle
> + needs to be retained or passed across helper functions:
> +
> +.. code-block:: c
> +
> + static void some_test(struct kunit *test)
> + {
> + struct kunit_suppressed_warning *w;
> +
> + w = kunit_start_suppress_warning(test);
> + trigger_backtrace();
> + kunit_end_suppress_warning(test, w);
> +
> + KUNIT_EXPECT_EQ(test, kunit_suppressed_warning_count(w), 1);
> + }
>
> Test Suites
> ~~~~~~~~~~~
> @@ -1211,4 +1272,4 @@ For example:
> dev_managed_string = devm_kstrdup(fake_device, "Hello, World!");
>
> // Everything is cleaned up automatically when the test ends.
> - }
> \ No newline at end of file
> + }
>
^ permalink raw reply
* Re: [PATCH v8 3/4] drm: Suppress intentional warning backtraces in scaling unit tests
From: Maxime Ripard @ 2026-05-06 9:48 UTC (permalink / raw)
To: David Gow
Cc: Albert Esteve, Arnd Bergmann, Brendan Higgins, Rae Moar,
Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Andrew Morton, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, linux-kernel,
linux-arch, linux-kselftest, kunit-dev, dri-devel, workflows,
linux-riscv, linux-doc, peterz, Guenter Roeck,
Linux Kernel Functional Testing, Dan Carpenter, Maíra Canal,
Alessandro Carminati, Simona Vetter
In-Reply-To: <47d78cad-0839-4602-9cb3-d1f672739e7e@davidgow.net>
[-- Attachment #1: Type: text/plain, Size: 1464 bytes --]
On Wed, May 06, 2026 at 05:38:50PM +0800, David Gow wrote:
> Le 04/05/2026 à 3:41 PM, Albert Esteve a écrit :
> > From: Guenter Roeck <linux@roeck-us.net>
> >
> > The drm_test_rect_calc_hscale and drm_test_rect_calc_vscale unit tests
> > intentionally trigger warning backtraces by providing bad parameters to
> > the tested functions. What is tested is the return value, not the existence
> > of a warning backtrace. Suppress the backtraces to avoid clogging the
> > kernel log and distraction from real problems.
> >
> > Tested-by: Linux Kernel Functional Testing <lkft@linaro.org>
> > Acked-by: Dan Carpenter <dan.carpenter@linaro.org>
> > Acked-by: Maíra Canal <mcanal@igalia.com>
> > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > Cc: David Airlie <airlied@gmail.com>
> > Cc: Daniel Vetter <daniel@ffwll.ch>
> > Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> > Signed-off-by: Alessandro Carminati <acarmina@redhat.com>
> > Acked-by: David Gow <david@davidgow.net>
> > Signed-off-by: Albert Esteve <aesteve@redhat.com>
> > ---
>
> I'm happy with this either with or without the extra check for the warning
> count.
>
> Acked-by: David Gow <david@davidgow.net>
>
> We'll take this patch in the kunit tree along with the rest of the series
> once everyone's happy.
If there's no need for a new version, feel free to merge these patches,
I'm totally fine with it being addressed as a follow-up.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply
* Re: [PATCH v8 1/4] bug/kunit: Core support for suppressing warning backtraces
From: Albert Esteve @ 2026-05-06 10:11 UTC (permalink / raw)
To: David Gow
Cc: Arnd Bergmann, Brendan Higgins, Rae Moar, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Andrew Morton, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, linux-kernel,
linux-arch, linux-kselftest, kunit-dev, dri-devel, workflows,
linux-riscv, linux-doc, peterz, Alessandro Carminati,
Guenter Roeck, Kees Cook
In-Reply-To: <c5c28f16-3940-4960-84e6-33f5479a5450@davidgow.net>
On Wed, May 6, 2026 at 11:40 AM David Gow <david@davidgow.net> wrote:
>
> Le 04/05/2026 à 3:41 PM, Albert Esteve a écrit :
> > 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 suppress warning backtraces
> > originating from the current kthread while executing test code. Since
> > each KUnit test runs in its own kthread, this effectively scopes
> > suppression to the test that enabled it. Limit changes to generic code
> > to the absolute minimum.
> >
> > Implementation details:
> > Suppression is integrated into the existing KUnit hooks infrastructure
> > in test-bug.h, reusing the kunit_running static branch for zero
> > overhead when no tests are running.
> >
> > Suppression is checked at three points in the warning path:
> > - In warn_slowpath_fmt(), the check runs before any output, fully
> > suppressing both message and backtrace. This covers architectures
> > without __WARN_FLAGS.
> > - In __warn_printk(), the check suppresses the warning message text.
> > This covers architectures that define __WARN_FLAGS but not their own
> > __WARN_printf (arm64, loongarch, parisc, powerpc, riscv, sh), where
> > the message is printed before the trap enters __report_bug().
> > - In __report_bug(), the check runs before __warn() is called,
> > suppressing the backtrace and stack dump.
> >
> > To avoid double-counting on architectures where both __warn_printk()
> > and __report_bug() run for the same warning, kunit_is_suppressed_warning()
> > takes a bool parameter: true to increment the suppression counter
> > (used in warn_slowpath_fmt and __report_bug), false to check only
> > (used in __warn_printk).
> >
> > The suppression state is dynamically allocated via kunit_kzalloc() and
> > tied to the KUnit test lifecycle via kunit_add_action(), ensuring
> > automatic cleanup at test exit. Writer-side access to the global
> > suppression list is serialized with a spinlock; readers use RCU.
> >
> > Three API forms are provided:
> > - kunit_warning_suppress(test) { ... }: scoped, uses __cleanup for
> > automatic teardown on scope exit, kunit_add_action() as safety net
> > for abnormal exits (e.g. kthread_exit from failed assertions).
> > Suppression handle is only accessible inside the block.
> > - KUNIT_START/END_SUPPRESSED_WARNING(test): manual macros for larger
> > blocks or when warning counts need to be checked after suppression
> > ends. Limited to one pair per scope.
> > - kunit_start/end_suppress_warning(test): direct functions returning
> > an explicit handle, for retaining the handle within the test,
> > or for cross-function usage.
> >
> > 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>
> > ---
>
> This looks pretty good to me, thanks.
>
> Reviewed-by: David Gow <david@davidgow.net>
>
> It's maybe slightly over-the-top to now have three different ways of
> enabling warning suppression: I'd probably personally get rid of
> KUNIT_START/END_SUPPRESSED_WARNING() if we had to lose one. But if
> there's a real reason to prefer keeping all three, it's not actually a
> problem to do so.
Thanks for the review!
I think the three forms earn their keep: the scoped form is the go-to
for most cases, but the macros avoid indentation without requiring
users to manage a raw pointer. I initially removed the macros and
added them back later. Direct calls to the functions will be less
frequent, used only when you need the handle.
That said, if it becomes a maintenance burden, the macros are the
easiest to drop since they're thin wrappers. Let me know if you prefer
them to be dropped, and I will send a v9 with that and the
`KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT` additions to the drm test
patch.
BR,
Albert.
>
> Regardless, this series is looking pretty ready to me. Let me know if
> you're planning a v9, otherwise we'll take this when you're ready.
>
> Cheers,
> -- David
>
> > include/kunit/test-bug.h | 25 +++++++++
> > include/kunit/test.h | 138 +++++++++++++++++++++++++++++++++++++++++++++++
> > kernel/panic.c | 15 +++++-
> > lib/bug.c | 10 ++++
> > lib/kunit/Makefile | 3 +-
> > lib/kunit/bug.c | 115 +++++++++++++++++++++++++++++++++++++++
> > lib/kunit/hooks-impl.h | 2 +
> > 7 files changed, 305 insertions(+), 3 deletions(-)
> >
> > diff --git a/include/kunit/test-bug.h b/include/kunit/test-bug.h
> > index 47aa8f21ccce8..6237e48ceadfd 100644
> > --- a/include/kunit/test-bug.h
> > +++ b/include/kunit/test-bug.h
> > @@ -23,6 +23,7 @@ DECLARE_STATIC_KEY_FALSE(kunit_running);
> > extern struct kunit_hooks_table {
> > __printf(3, 4) void (*fail_current_test)(const char*, int, const char*, ...);
> > void *(*get_static_stub_address)(struct kunit *test, void *real_fn_addr);
> > + bool (*is_suppressed_warning)(bool count);
> > } kunit_hooks;
> >
> > /**
> > @@ -60,9 +61,33 @@ static inline struct kunit *kunit_get_current_test(void)
> > } \
> > } while (0)
> >
> > +/**
> > + * kunit_is_suppressed_warning() - Check if warnings are being suppressed
> > + * by the current KUnit test.
> > + * @count: if true, increment the suppression counter on match.
> > + *
> > + * Returns true if the current task has active warning suppression.
> > + * Uses the kunit_running static branch for zero overhead when no tests run.
> > + *
> > + * A single WARN*() may traverse multiple call sites in the warning path
> > + * (e.g., __warn_printk() and __report_bug()). Pass @count = true at the
> > + * primary suppression point to count each warning exactly once, and
> > + * @count = false at secondary points to suppress output without
> > + * inflating the count.
> > + */
> > +static inline bool kunit_is_suppressed_warning(bool count)
> > +{
> > + if (!static_branch_unlikely(&kunit_running))
> > + return false;
> > +
> > + return kunit_hooks.is_suppressed_warning &&
> > + kunit_hooks.is_suppressed_warning(count);
> > +}
> > +
> > #else
> >
> > static inline struct kunit *kunit_get_current_test(void) { return NULL; }
> > +static inline bool kunit_is_suppressed_warning(bool count) { return false; }
> >
> > #define kunit_fail_current_test(fmt, ...) do {} while (0)
> >
> > diff --git a/include/kunit/test.h b/include/kunit/test.h
> > index 9cd1594ab697d..f278ec028019c 100644
> > --- a/include/kunit/test.h
> > +++ b/include/kunit/test.h
> > @@ -1795,4 +1795,142 @@ do { \
> > // include resource.h themselves if they need it.
> > #include <kunit/resource.h>
> >
> > +/*
> > + * Warning backtrace suppression API.
> > + *
> > + * Suppresses WARN*() backtraces on the current task while active. Three forms
> > + * are provided, in order of convenience:
> > + *
> > + * - Scoped: kunit_warning_suppress(test) { ... }
> > + * Suppression is active for the duration of the block. On normal exit,
> > + * the for-loop increment deactivates suppression. On early exit (break,
> > + * return, goto), the __cleanup attribute fires. On kthread_exit() (e.g.,
> > + * a failed KUnit assertion), kunit_add_action() cleans up at test
> > + * teardown. The suppression handle is only accessible inside the block,
> > + * so warning counts must be checked before the block exits.
> > + *
> > + * - Manual macros: KUNIT_[START|END]_SUPPRESSED_WARNING(test)
> > + * Suppression spans an explicit range in the same scope. kunit_add_action()
> > + * guarantees cleanup even if KUNIT_END_SUPPRESSED_WARNING() is not reached.
> > + * Prefer this form when suppressing warnings across a large block where
> > + * extra indentation is undesirable, or when the warning count needs to be
> > + * checked after suppression ends. Limited to one pair per scope.
> > + *
> > + * - Direct: kunit_start_suppress_warning() / kunit_end_suppress_warning()
> > + * The underlying functions, returning an explicit handle pointer. Use
> > + * when the handle needs to be retained (e.g., for post-suppression
> > + * count checks) or passed across helper functions.
> > + */
> > +struct kunit_suppressed_warning;
> > +
> > +struct kunit_suppressed_warning *
> > +kunit_start_suppress_warning(struct kunit *test);
> > +void kunit_end_suppress_warning(struct kunit *test,
> > + struct kunit_suppressed_warning *w);
> > +int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w);
> > +void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp);
> > +bool kunit_has_active_suppress_warning(void);
> > +
> > +/**
> > + * kunit_warning_suppress() - Suppress WARN*() backtraces for the duration
> > + * of a block.
> > + * @test: The test context object.
> > + *
> > + * Scoped form of the suppression API. Suppression starts when the block is
> > + * entered and ends automatically when the block exits through any path. See
> > + * the section comment above for the cleanup guarantees on each exit path.
> > + * Fails the test if suppression is already active; nesting is not supported.
> > + *
> > + * The warning count can be checked inside the block via
> > + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(). The handle is not accessible
> > + * after the block exits.
> > + *
> > + * Example::
> > + *
> > + * kunit_warning_suppress(test) {
> > + * trigger_warning();
> > + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> > + * }
> > + */
> > +#define kunit_warning_suppress(test) \
> > + for (struct kunit_suppressed_warning *__kunit_suppress \
> > + __cleanup(__kunit_suppress_auto_cleanup) = \
> > + kunit_start_suppress_warning(test); \
> > + __kunit_suppress; \
> > + kunit_end_suppress_warning(test, __kunit_suppress), \
> > + __kunit_suppress = NULL)
> > +
> > +/**
> > + * KUNIT_START_SUPPRESSED_WARNING() - Begin suppressing WARN*() backtraces.
> > + * @test: The test context object.
> > + *
> > + * Manual form of the suppression API. Must be paired with
> > + * KUNIT_END_SUPPRESSED_WARNING() in the same scope. See the section comment
> > + * above for cleanup guarantees. Fails the test if suppression is already
> > + * active; nesting is not supported. Limited to one pair per scope; use
> > + * sequential kunit_warning_suppress() blocks or the direct function API
> > + * when more than one suppression region is needed.
> > + *
> > + * Example::
> > + *
> > + * KUNIT_START_SUPPRESSED_WARNING(test);
> > + * trigger_code_that_should_warn_once();
> > + * KUNIT_END_SUPPRESSED_WARNING(test);
> > + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> > + */
> > +#define KUNIT_START_SUPPRESSED_WARNING(test) \
> > + struct kunit_suppressed_warning *__kunit_suppress = \
> > + kunit_start_suppress_warning(test)
> > +
> > +/**
> > + * KUNIT_END_SUPPRESSED_WARNING() - End suppressing WARN*() backtraces.
> > + * @test: The test context object.
> > + *
> > + * Deactivates suppression started by KUNIT_START_SUPPRESSED_WARNING().
> > + * The warning count remains readable via KUNIT_SUPPRESSED_WARNING_COUNT()
> > + * after this call.
> > + */
> > +#define KUNIT_END_SUPPRESSED_WARNING(test) \
> > + kunit_end_suppress_warning(test, __kunit_suppress)
> > +
> > +/**
> > + * KUNIT_SUPPRESSED_WARNING_COUNT() - Returns the suppressed warning count.
> > + *
> > + * Returns the number of WARN*() calls suppressed since the current
> > + * suppression block started, or 0 if the handle is NULL. Usable inside a
> > + * kunit_warning_suppress() block or after KUNIT_END_SUPPRESSED_WARNING().
> > + */
> > +#define KUNIT_SUPPRESSED_WARNING_COUNT() \
> > + kunit_suppressed_warning_count(__kunit_suppress)
> > +
> > +/**
> > + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT() - Sets an expectation that the
> > + * suppressed warning count equals
> > + * @expected.
> > + * @test: The test context object.
> > + * @expected: an expression that evaluates to the expected warning count.
> > + *
> > + * Sets an expectation that the number of suppressed WARN*() calls equals
> > + * @expected. This is semantically equivalent to
> > + * KUNIT_EXPECT_EQ(@test, KUNIT_SUPPRESSED_WARNING_COUNT(), @expected).
> > + * See KUNIT_EXPECT_EQ() for more information.
> > + */
> > +#define KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, expected) \
> > + KUNIT_EXPECT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected)
> > +
> > +/**
> > + * KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT() - Sets an assertion that the
> > + * suppressed warning count equals
> > + * @expected.
> > + * @test: The test context object.
> > + * @expected: an expression that evaluates to the expected warning count.
> > + *
> > + * Sets an assertion that the number of suppressed WARN*() calls equals
> > + * @expected. This is the same as KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(),
> > + * except it causes an assertion failure (see KUNIT_ASSERT_TRUE()) when the
> > + * assertion is not met.
> > + */
> > +#define KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT(test, expected) \
> > + KUNIT_ASSERT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected)
> > +
> > #endif /* _KUNIT_TEST_H */
> > diff --git a/kernel/panic.c b/kernel/panic.c
> > index c78600212b6c1..697d8ca054bef 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/test-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(true))
> > + return;
> > +
> > + rcu = warn_rcu_enter();
> > +
> > pr_warn(CUT_HERE);
> >
> > if (!fmt) {
> > @@ -1102,9 +1108,14 @@ EXPORT_SYMBOL(warn_slowpath_fmt);
> > #else
> > void __warn_printk(const char *fmt, ...)
> > {
> > - bool rcu = warn_rcu_enter();
> > + bool rcu;
> > va_list args;
> >
> > + if (kunit_is_suppressed_warning(false))
> > + return;
> > +
> > + rcu = warn_rcu_enter();
> > +
> > pr_warn(CUT_HERE);
> >
> > va_start(args, fmt);
> > diff --git a/lib/bug.c b/lib/bug.c
> > index 623c467a8b76c..a5cebde554ed8 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/test-bug.h>
> >
> > extern struct bug_entry __start___bug_table[], __stop___bug_table[];
> >
> > @@ -223,6 +224,15 @@ 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;
> >
> > +#ifdef CONFIG_KUNIT
> > + /*
> > + * Before the once logic so suppressed warnings do not consume
> > + * the single-fire budget of WARN_ON_ONCE().
> > + */
> > + if (warning && kunit_is_suppressed_warning(true))
> > + return BUG_TRAP_TYPE_WARN;
> > +#endif
> > +
> > if (warning && once) {
> > if (done)
> > return BUG_TRAP_TYPE_WARN;
> > diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
> > index 656f1fa35abcc..4592f9d0aa8dd 100644
> > --- a/lib/kunit/Makefile
> > +++ b/lib/kunit/Makefile
> > @@ -10,7 +10,8 @@ kunit-objs += test.o \
> > executor.o \
> > attributes.o \
> > device.o \
> > - platform.o
> > + platform.o \
> > + bug.o
> >
> > ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
> > kunit-objs += debugfs.o
> > diff --git a/lib/kunit/bug.c b/lib/kunit/bug.c
> > new file mode 100644
> > index 0000000000000..b0b6778d7399a
> > --- /dev/null
> > +++ b/lib/kunit/bug.c
> > @@ -0,0 +1,115 @@
> > +// 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/resource.h>
> > +#include <linux/export.h>
> > +#include <linux/rculist.h>
> > +#include <linux/sched.h>
> > +#include <linux/spinlock.h>
> > +
> > +#include "hooks-impl.h"
> > +
> > +struct kunit_suppressed_warning {
> > + struct list_head node;
> > + struct task_struct *task;
> > + struct kunit *test;
> > + int counter;
> > +};
> > +
> > +static LIST_HEAD(suppressed_warnings);
> > +static DEFINE_SPINLOCK(suppressed_warnings_lock);
> > +
> > +static void kunit_suppress_warning_remove(struct kunit_suppressed_warning *w)
> > +{
> > + unsigned long flags;
> > +
> > + spin_lock_irqsave(&suppressed_warnings_lock, flags);
> > + list_del_rcu(&w->node);
> > + spin_unlock_irqrestore(&suppressed_warnings_lock, flags);
> > + synchronize_rcu(); /* Wait for readers to finish */
> > +}
> > +
> > +KUNIT_DEFINE_ACTION_WRAPPER(kunit_suppress_warning_cleanup,
> > + kunit_suppress_warning_remove,
> > + struct kunit_suppressed_warning *);
> > +
> > +bool kunit_has_active_suppress_warning(void)
> > +{
> > + return __kunit_is_suppressed_warning_impl(false);
> > +}
> > +EXPORT_SYMBOL_GPL(kunit_has_active_suppress_warning);
> > +
> > +struct kunit_suppressed_warning *
> > +kunit_start_suppress_warning(struct kunit *test)
> > +{
> > + struct kunit_suppressed_warning *w;
> > + unsigned long flags;
> > + int ret;
> > +
> > + if (kunit_has_active_suppress_warning()) {
> > + KUNIT_FAIL(test, "Another suppression block is already active");
> > + return NULL;
> > + }
> > +
> > + w = kunit_kzalloc(test, sizeof(*w), GFP_KERNEL);
> > + if (!w)
> > + return NULL;
> > +
> > + w->task = current;
> > + w->test = test;
> > +
> > + spin_lock_irqsave(&suppressed_warnings_lock, flags);
> > + list_add_rcu(&w->node, &suppressed_warnings);
> > + spin_unlock_irqrestore(&suppressed_warnings_lock, flags);
> > +
> > + ret = kunit_add_action_or_reset(test,
> > + kunit_suppress_warning_cleanup, w);
> > + if (ret)
> > + return NULL;
> > +
> > + return w;
> > +}
> > +EXPORT_SYMBOL_GPL(kunit_start_suppress_warning);
> > +
> > +void kunit_end_suppress_warning(struct kunit *test,
> > + struct kunit_suppressed_warning *w)
> > +{
> > + if (!w)
> > + return;
> > + kunit_release_action(test, kunit_suppress_warning_cleanup, w);
> > +}
> > +EXPORT_SYMBOL_GPL(kunit_end_suppress_warning);
> > +
> > +void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp)
> > +{
> > + if (*wp)
> > + kunit_end_suppress_warning((*wp)->test, *wp);
> > +}
> > +EXPORT_SYMBOL_GPL(__kunit_suppress_auto_cleanup);
> > +
> > +int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w)
> > +{
> > + return w ? w->counter : 0;
> > +}
> > +EXPORT_SYMBOL_GPL(kunit_suppressed_warning_count);
> > +
> > +bool __kunit_is_suppressed_warning_impl(bool count)
> > +{
> > + struct kunit_suppressed_warning *w;
> > +
> > + guard(rcu)();
> > + list_for_each_entry_rcu(w, &suppressed_warnings, node) {
> > + if (w->task == current) {
> > + if (count)
> > + w->counter++;
> > + return true;
> > + }
> > + }
> > +
> > + return false;
> > +}
> > diff --git a/lib/kunit/hooks-impl.h b/lib/kunit/hooks-impl.h
> > index 4e71b2d0143ba..d8720f2616925 100644
> > --- a/lib/kunit/hooks-impl.h
> > +++ b/lib/kunit/hooks-impl.h
> > @@ -19,6 +19,7 @@ void __printf(3, 4) __kunit_fail_current_test_impl(const char *file,
> > int line,
> > const char *fmt, ...);
> > void *__kunit_get_static_stub_address_impl(struct kunit *test, void *real_fn_addr);
> > +bool __kunit_is_suppressed_warning_impl(bool count);
> >
> > /* Code to set all of the function pointers. */
> > static inline void kunit_install_hooks(void)
> > @@ -26,6 +27,7 @@ static inline void kunit_install_hooks(void)
> > /* Install the KUnit hook functions. */
> > kunit_hooks.fail_current_test = __kunit_fail_current_test_impl;
> > kunit_hooks.get_static_stub_address = __kunit_get_static_stub_address_impl;
> > + kunit_hooks.is_suppressed_warning = __kunit_is_suppressed_warning_impl;
> > }
> >
> > #endif /* _KUNIT_HOOKS_IMPL_H */
> >
>
^ permalink raw reply
* Re: [PATCH v2 2/3] Documentation: security-bugs: explain what is and is not a security bug
From: Linus Torvalds @ 2026-05-06 15:46 UTC (permalink / raw)
To: Willy Tarreau
Cc: greg, leon, security, Jonathan Corbet, skhan, workflows,
linux-doc, linux-kernel, Greg KH
In-Reply-To: <20260503113506.5710-3-w@1wt.eu>
[ Coming back to this after a week of trying to clean up the disaster
that is my inbox after the merge window ]
On Sun, 3 May 2026 at 04:35, Willy Tarreau <w@1wt.eu> wrote:
>
> The use of automated tools to find bugs in random locations of the kernel
> induces a raise of security reports even if most of them should just be
> reported as regular bugs. This patch is an attempt at drawing a line
> between what qualifies as a security bug and what does not, hoping to
> improve the situation and ease decision on the reporter's side.
I actually think we may want to go further than this.
I think we should simply make it a rule that "a 'security' bug that is
found by AI is public".
Now, I may be influenced by that "my inbox is a disaster during the
merge window" thing, but I do think this is pretty fundamental: if
somebody finds a bug with more or less standard AI tools (ie we're not
talking magical special hardware and nation-state level efforts), then
that bug pretty much by definition IS NOT SECRET.
So why should be consider it special and have it be on the security list?
Yes, yes, I know - some people think that "security bugs are special".
And I've been on the record before calling that opinion special - in
the short bus sense.
Bugs are bugs. And not having them in public only makes them harder to
deal with.
Do we want to make bugs with potential security impact harder to deal
with? No. No, we really don't.
So I claim that the only reason for a security list is the non-public
nature of the bug and the whole "responsible disclosure" argument.
But that argument is complete and utter garbage in the face of some
mostly automated AI discovery (now, that argument is mostly a fiction
in the first place, but I am not going to argue with people who have
vested interest in making their special patches "security bugs").
To recap - I think this "document the scope of security bugs" is good,
but I think we should go even further, and just document the fact that
anything found by regular AI tools should just always go to public
lists and is simply not special.
Linus
^ permalink raw reply
* Re: [PATCH v2 2/3] Documentation: security-bugs: explain what is and is not a security bug
From: Willy Tarreau @ 2026-05-06 16:02 UTC (permalink / raw)
To: Linus Torvalds
Cc: greg, leon, security, Jonathan Corbet, skhan, workflows,
linux-doc, linux-kernel, Greg KH
In-Reply-To: <CAHk-=wi6z5BGUUT2p+=qrJg+obom8VnCo3MqB=7xp3Gw+UMMkg@mail.gmail.com>
Hi Linus,
On Wed, May 06, 2026 at 08:46:07AM -0700, Linus Torvalds wrote:
> [ Coming back to this after a week of trying to clean up the disaster
> that is my inbox after the merge window ]
>
> On Sun, 3 May 2026 at 04:35, Willy Tarreau <w@1wt.eu> wrote:
> >
> > The use of automated tools to find bugs in random locations of the kernel
> > induces a raise of security reports even if most of them should just be
> > reported as regular bugs. This patch is an attempt at drawing a line
> > between what qualifies as a security bug and what does not, hoping to
> > improve the situation and ease decision on the reporter's side.
>
> I actually think we may want to go further than this.
>
> I think we should simply make it a rule that "a 'security' bug that is
> found by AI is public".
This would definitely help us a lot on sec@k.o, but...
> Now, I may be influenced by that "my inbox is a disaster during the
> merge window" thing, but I do think this is pretty fundamental: if
> somebody finds a bug with more or less standard AI tools (ie we're not
> talking magical special hardware and nation-state level efforts), then
> that bug pretty much by definition IS NOT SECRET.
I think it's only 99.9% true. I mean, I've used such tools myself to
find bugs that were not found otherwise and I know that:
- interactions with the tools count a lot
- luck counts even more
There remains a faint possibility that the reporter has worked a lot
with their tool to be able to find the problem. I.e. the user helped
the LLM and not the opposite. In this case it might be possible that
it's not public. But clearly from what we've seen over the last few
weeks, the number of duplicates has exploded, with up to 3 reports
for the same issue within 2 days, so it's clear that they're not in
the category I mention above.
Maybe we should leave some rope for "if you are fairly confident that
the work you did is unlikely to have been replicated by anyone else,
the you can report it here" but I think we'll both agree that for now
most reporters really think they did something exceptional while we all
saw it was not the case (or they all do the same exceptional thing).
Thus I'm embarrassed with that.
> So why should be consider it special and have it be on the security list?
>
> Yes, yes, I know - some people think that "security bugs are special".
> And I've been on the record before calling that opinion special - in
> the short bus sense.
>
> Bugs are bugs. And not having them in public only makes them harder to
> deal with.
>
> Do we want to make bugs with potential security impact harder to deal
> with? No. No, we really don't.
>
> So I claim that the only reason for a security list is the non-public
> nature of the bug and the whole "responsible disclosure" argument.
As you probably guess, I totally agree with these points. I'm just
trying to leave the door open for the rare exceptions without having
to accept all the flood.
> But that argument is complete and utter garbage in the face of some
> mostly automated AI discovery (now, that argument is mostly a fiction
> in the first place, but I am not going to argue with people who have
> vested interest in making their special patches "security bugs").
>
> To recap - I think this "document the scope of security bugs" is good,
Thanks for the feedback.
> but I think we should go even further, and just document the fact that
> anything found by regular AI tools should just always go to public
> lists and is simply not special.
I'm fine with that but I'd like to add "except..." though I don't know
how to phrase it. If you have any idea, we can write something for a
start and see how it goes. It looks like these tools are pretty good
at swallowing our doc updates to help reporters so the good thing is
that we can now write instructions that are mostly followed in process
docs ;-)
Willy
^ permalink raw reply
* Re: [PATCH v2 2/3] Documentation: security-bugs: explain what is and is not a security bug
From: Willy Tarreau @ 2026-05-07 4:18 UTC (permalink / raw)
To: Linus Torvalds
Cc: greg, leon, security, Jonathan Corbet, skhan, workflows,
linux-doc, linux-kernel, Greg KH
In-Reply-To: <aftmB435XJ8FP3V_@1wt.eu>
On Wed, May 06, 2026 at 06:02:15PM +0200, Willy Tarreau wrote:
> Hi Linus,
>
> On Wed, May 06, 2026 at 08:46:07AM -0700, Linus Torvalds wrote:
> > [ Coming back to this after a week of trying to clean up the disaster
> > that is my inbox after the merge window ]
> >
> > On Sun, 3 May 2026 at 04:35, Willy Tarreau <w@1wt.eu> wrote:
> > >
> > > The use of automated tools to find bugs in random locations of the kernel
> > > induces a raise of security reports even if most of them should just be
> > > reported as regular bugs. This patch is an attempt at drawing a line
> > > between what qualifies as a security bug and what does not, hoping to
> > > improve the situation and ease decision on the reporter's side.
> >
> > I actually think we may want to go further than this.
> >
> > I think we should simply make it a rule that "a 'security' bug that is
> > found by AI is public".
>
> This would definitely help us a lot on sec@k.o, but...
>
> > Now, I may be influenced by that "my inbox is a disaster during the
> > merge window" thing, but I do think this is pretty fundamental: if
> > somebody finds a bug with more or less standard AI tools (ie we're not
> > talking magical special hardware and nation-state level efforts), then
> > that bug pretty much by definition IS NOT SECRET.
>
> I think it's only 99.9% true. I mean, I've used such tools myself to
> find bugs that were not found otherwise and I know that:
> - interactions with the tools count a lot
> - luck counts even more
Thinking more about it, there's still something that won't go round:
- people have always been looking for vulnerabilities, sometimes for
fun, and often to proudly show a CVE on their resume ; we've been
dealing with that for many years.
- now they can do the same using AI and making much less effort, but
their approach still stems from actively searching a vulnerability
- when they find something, they're certain it's a vulnerability
because it's what they asked for (hence the threat model addition).
- if we tell them "don't report this to s@k.o" they will simply send
them directly to the maintainers, who are even less accustomed to
the process and will not benefit from the security team's experience
in triaging nor support in saying "no". And we all know how stressful
a vulnerability report can be for a developer who instantly has to
stop doing everything and start to look at it just in case it would
be valid.
For these reasons I'd rather propose that we say something around these
lines:
Note that the security team will generally consider AI-assisted
findings as public and will often ask you to repost your report
to public lists.
Another point is that for many vulns there are two types of adversaries:
- criminals
- script kiddies
The former must be assumed to also have discovered the same vuln, possibly
earlier, and to be actively exploiting it. The latter however, is just
going to use whatever published exploit to say "look mum, I'm root".
Public reports containing too many details will speed up usability for
this group and that's not good for users.
And we *know* that some reports contain working PoC that need very little
modification. Passing them through s@k.o for triaging feels safer than
directing them to public lists with no early validation.
So in short, I think that:
- AI reports should be considered public, but not necessarily well known
yet
- AI reports often contain repros that shouldn't be posted publicly
- AI reports wording can be intimidating to developers not used to
receiving these things
-> the security team should remain the first filtering layer for this
for new reporters even if it means continuing to see some noise.
I think that instead it's the 3rd patch about the threat model that
should help us receive less noise by explaining what is not a
vulnerability.
I can rework that part a bit to reflect this.
Willy
^ permalink raw reply
* Re: [PATCH v2 2/3] Documentation: security-bugs: explain what is and is not a security bug
From: Peter Zijlstra @ 2026-05-07 7:07 UTC (permalink / raw)
To: Willy Tarreau
Cc: Linus Torvalds, greg, leon, security, Jonathan Corbet, skhan,
workflows, linux-doc, linux-kernel, Greg KH
In-Reply-To: <aftmB435XJ8FP3V_@1wt.eu>
On Wed, May 06, 2026 at 06:02:15PM +0200, Willy Tarreau wrote:
> Hi Linus,
>
> On Wed, May 06, 2026 at 08:46:07AM -0700, Linus Torvalds wrote:
> > [ Coming back to this after a week of trying to clean up the disaster
> > that is my inbox after the merge window ]
> >
> > On Sun, 3 May 2026 at 04:35, Willy Tarreau <w@1wt.eu> wrote:
> > >
> > > The use of automated tools to find bugs in random locations of the kernel
> > > induces a raise of security reports even if most of them should just be
> > > reported as regular bugs. This patch is an attempt at drawing a line
> > > between what qualifies as a security bug and what does not, hoping to
> > > improve the situation and ease decision on the reporter's side.
> >
> > I actually think we may want to go further than this.
> >
> > I think we should simply make it a rule that "a 'security' bug that is
> > found by AI is public".
>
> This would definitely help us a lot on sec@k.o, but...
>
> > Now, I may be influenced by that "my inbox is a disaster during the
> > merge window" thing, but I do think this is pretty fundamental: if
> > somebody finds a bug with more or less standard AI tools (ie we're not
> > talking magical special hardware and nation-state level efforts), then
> > that bug pretty much by definition IS NOT SECRET.
>
> I think it's only 99.9% true. I mean, I've used such tools myself to
> find bugs that were not found otherwise and I know that:
> - interactions with the tools count a lot
> - luck counts even more
Perhaps also note that including a reproducer for a crash in public is
fine, including a full blown exploit is not.
So perhaps that can serve as a guide; if they went and put in the effort
of making a full exploit (with or without LLM aid), keep it on security,
otherwise do the public thing.
And yes, I realize this too might be a very thin/short rope.
^ permalink raw reply
* Re: [PATCH v2 2/3] Documentation: security-bugs: explain what is and is not a security bug
From: Peter Zijlstra @ 2026-05-07 7:14 UTC (permalink / raw)
To: Willy Tarreau
Cc: Linus Torvalds, greg, leon, security, Jonathan Corbet, skhan,
workflows, linux-doc, linux-kernel, Greg KH
In-Reply-To: <afwSk3BC8mewPfPp@1wt.eu>
On Thu, May 07, 2026 at 06:18:27AM +0200, Willy Tarreau wrote:
> Another point is that for many vulns there are two types of adversaries:
> - criminals
> - script kiddies
>
> The former must be assumed to also have discovered the same vuln, possibly
> earlier, and to be actively exploiting it. The latter however, is just
> going to use whatever published exploit to say "look mum, I'm root".
> Public reports containing too many details will speed up usability for
> this group and that's not good for users.
>
> And we *know* that some reports contain working PoC that need very little
> modification. Passing them through s@k.o for triaging feels safer than
> directing them to public lists with no early validation.
>
> So in short, I think that:
> - AI reports should be considered public, but not necessarily well known
> yet
> - AI reports often contain repros that shouldn't be posted publicly
So, I think a targeted repro that exposes just the initial bug is in
most cases useful and shouldn't be held back. Full blown exploits on the
other hand should definitely be kept from the public list.
Most times, it still takes skill to get from the former to the latter,
although I suppose with LLMs this gap is shrinking too.
> - AI reports wording can be intimidating to developers not used to
> receiving these things
>
> -> the security team should remain the first filtering layer for this
> for new reporters even if it means continuing to see some noise.
> I think that instead it's the 3rd patch about the threat model that
> should help us receive less noise by explaining what is not a
> vulnerability.
>
> I can rework that part a bit to reflect this.
Yes, I think that covers my earlier point well. And yes AI babble should
be sanitized, both for brevity and for explaining how to do the rest of
the exploit :-)
^ permalink raw reply
* Re: [PATCH v2 2/3] Documentation: security-bugs: explain what is and is not a security bug
From: Linus Torvalds @ 2026-05-07 15:37 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Willy Tarreau, greg, leon, security, Jonathan Corbet, skhan,
workflows, linux-doc, linux-kernel, Greg KH
In-Reply-To: <20260507070720.GG3126523@noisy.programming.kicks-ass.net>
On Thu, 7 May 2026 at 00:07, Peter Zijlstra <peterz@infradead.org> wrote:
>
> Perhaps also note that including a reproducer for a crash in public is
> fine, including a full blown exploit is not.
>
> So perhaps that can serve as a guide
That would be a good rule, I think - and I like how it has the
advantage of being very explicit and black-and-white, rather than some
"I think my bug is so important that it should be sent to the speshul
super-sikret list".
Because we all think we are special. Our mothers told us so, and even
the AI bots are typically explicitly told to act as experts. So they
think they are special too.
Linus
^ permalink raw reply
* Re: [PATCH v2 2/3] Documentation: security-bugs: explain what is and is not a security bug
From: Willy Tarreau @ 2026-05-07 15:48 UTC (permalink / raw)
To: Linus Torvalds
Cc: Peter Zijlstra, greg, leon, security, Jonathan Corbet, skhan,
workflows, linux-doc, linux-kernel, Greg KH
In-Reply-To: <CAHk-=whE=rLLbBRsFuQKVX49NgN2UUdUE=Druf3fiSZ9Ou8c3Q@mail.gmail.com>
On Thu, May 07, 2026 at 08:37:29AM -0700, Linus Torvalds wrote:
> On Thu, 7 May 2026 at 00:07, Peter Zijlstra <peterz@infradead.org> wrote:
> >
> > Perhaps also note that including a reproducer for a crash in public is
> > fine, including a full blown exploit is not.
> >
> > So perhaps that can serve as a guide
>
> That would be a good rule, I think - and I like how it has the
> advantage of being very explicit and black-and-white, rather than some
> "I think my bug is so important that it should be sent to the speshul
> super-sikret list".
>
> Because we all think we are special. Our mothers told us so, and even
> the AI bots are typically explicitly told to act as experts. So they
> think they are special too.
These points correspond to what I mentioned in my second message a few
hours ago, but I want to protect maintainers against the flood of crap
they're not necessarily used to. I think that the balance I proposed
could work as it more or less covers this. When you have a time to look
at it I'd be glad to have your opinion/criticism (sorry if it's a bit
long but the topic is far from being trivial).
willy
^ permalink raw reply
* Re: [PATCH v8 1/4] bug/kunit: Core support for suppressing warning backtraces
From: Albert Esteve @ 2026-05-08 6:52 UTC (permalink / raw)
To: David Gow
Cc: Arnd Bergmann, Brendan Higgins, Rae Moar, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Andrew Morton, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, linux-kernel,
linux-arch, linux-kselftest, kunit-dev, dri-devel, workflows,
linux-riscv, linux-doc, peterz, Alessandro Carminati,
Guenter Roeck, Kees Cook
In-Reply-To: <CADSE00KLhyUpRD031-YveOv+o71jJ-NojX6VteSyF+SqxG0n4g@mail.gmail.com>
On Wed, May 6, 2026 at 12:11 PM Albert Esteve <aesteve@redhat.com> wrote:
>
> On Wed, May 6, 2026 at 11:40 AM David Gow <david@davidgow.net> wrote:
> >
> > Le 04/05/2026 à 3:41 PM, Albert Esteve a écrit :
> > > 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 suppress warning backtraces
> > > originating from the current kthread while executing test code. Since
> > > each KUnit test runs in its own kthread, this effectively scopes
> > > suppression to the test that enabled it. Limit changes to generic code
> > > to the absolute minimum.
> > >
> > > Implementation details:
> > > Suppression is integrated into the existing KUnit hooks infrastructure
> > > in test-bug.h, reusing the kunit_running static branch for zero
> > > overhead when no tests are running.
> > >
> > > Suppression is checked at three points in the warning path:
> > > - In warn_slowpath_fmt(), the check runs before any output, fully
> > > suppressing both message and backtrace. This covers architectures
> > > without __WARN_FLAGS.
> > > - In __warn_printk(), the check suppresses the warning message text.
> > > This covers architectures that define __WARN_FLAGS but not their own
> > > __WARN_printf (arm64, loongarch, parisc, powerpc, riscv, sh), where
> > > the message is printed before the trap enters __report_bug().
> > > - In __report_bug(), the check runs before __warn() is called,
> > > suppressing the backtrace and stack dump.
> > >
> > > To avoid double-counting on architectures where both __warn_printk()
> > > and __report_bug() run for the same warning, kunit_is_suppressed_warning()
> > > takes a bool parameter: true to increment the suppression counter
> > > (used in warn_slowpath_fmt and __report_bug), false to check only
> > > (used in __warn_printk).
> > >
> > > The suppression state is dynamically allocated via kunit_kzalloc() and
> > > tied to the KUnit test lifecycle via kunit_add_action(), ensuring
> > > automatic cleanup at test exit. Writer-side access to the global
> > > suppression list is serialized with a spinlock; readers use RCU.
> > >
> > > Three API forms are provided:
> > > - kunit_warning_suppress(test) { ... }: scoped, uses __cleanup for
> > > automatic teardown on scope exit, kunit_add_action() as safety net
> > > for abnormal exits (e.g. kthread_exit from failed assertions).
> > > Suppression handle is only accessible inside the block.
> > > - KUNIT_START/END_SUPPRESSED_WARNING(test): manual macros for larger
> > > blocks or when warning counts need to be checked after suppression
> > > ends. Limited to one pair per scope.
> > > - kunit_start/end_suppress_warning(test): direct functions returning
> > > an explicit handle, for retaining the handle within the test,
> > > or for cross-function usage.
> > >
> > > 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>
> > > ---
> >
> > This looks pretty good to me, thanks.
> >
> > Reviewed-by: David Gow <david@davidgow.net>
> >
> > It's maybe slightly over-the-top to now have three different ways of
> > enabling warning suppression: I'd probably personally get rid of
> > KUNIT_START/END_SUPPRESSED_WARNING() if we had to lose one. But if
> > there's a real reason to prefer keeping all three, it's not actually a
> > problem to do so.
>
> Thanks for the review!
>
> I think the three forms earn their keep: the scoped form is the go-to
> for most cases, but the macros avoid indentation without requiring
> users to manage a raw pointer. I initially removed the macros and
> added them back later. Direct calls to the functions will be less
> frequent, used only when you need the handle.
>
> That said, if it becomes a maintenance burden, the macros are the
> easiest to drop since they're thin wrappers. Let me know if you prefer
> them to be dropped, and I will send a v9 with that and the
> `KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT` additions to the drm test
> patch.
>
> BR,
> Albert.
>
> >
> > Regardless, this series is looking pretty ready to me. Let me know if
> > you're planning a v9, otherwise we'll take this when you're ready.
I have been thinking, and despite my last response arguing against it,
I think I will send that v9 and remove
KUNIT_START/END_SUPPRESSED_WARNING(). Since the scoped approach with a
reduced extent should be the default style for most cases, the direct
calls can cover any other use cases without needing macros. Plus,
since macros set the handler name for you, it seems odd not to be able
to use them more than once per test.
I hope that's ok. After that I think it should be ready (at least from my side).
BR,
Albert
> >
> > Cheers,
> > -- David
> >
> > > include/kunit/test-bug.h | 25 +++++++++
> > > include/kunit/test.h | 138 +++++++++++++++++++++++++++++++++++++++++++++++
> > > kernel/panic.c | 15 +++++-
> > > lib/bug.c | 10 ++++
> > > lib/kunit/Makefile | 3 +-
> > > lib/kunit/bug.c | 115 +++++++++++++++++++++++++++++++++++++++
> > > lib/kunit/hooks-impl.h | 2 +
> > > 7 files changed, 305 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/include/kunit/test-bug.h b/include/kunit/test-bug.h
> > > index 47aa8f21ccce8..6237e48ceadfd 100644
> > > --- a/include/kunit/test-bug.h
> > > +++ b/include/kunit/test-bug.h
> > > @@ -23,6 +23,7 @@ DECLARE_STATIC_KEY_FALSE(kunit_running);
> > > extern struct kunit_hooks_table {
> > > __printf(3, 4) void (*fail_current_test)(const char*, int, const char*, ...);
> > > void *(*get_static_stub_address)(struct kunit *test, void *real_fn_addr);
> > > + bool (*is_suppressed_warning)(bool count);
> > > } kunit_hooks;
> > >
> > > /**
> > > @@ -60,9 +61,33 @@ static inline struct kunit *kunit_get_current_test(void)
> > > } \
> > > } while (0)
> > >
> > > +/**
> > > + * kunit_is_suppressed_warning() - Check if warnings are being suppressed
> > > + * by the current KUnit test.
> > > + * @count: if true, increment the suppression counter on match.
> > > + *
> > > + * Returns true if the current task has active warning suppression.
> > > + * Uses the kunit_running static branch for zero overhead when no tests run.
> > > + *
> > > + * A single WARN*() may traverse multiple call sites in the warning path
> > > + * (e.g., __warn_printk() and __report_bug()). Pass @count = true at the
> > > + * primary suppression point to count each warning exactly once, and
> > > + * @count = false at secondary points to suppress output without
> > > + * inflating the count.
> > > + */
> > > +static inline bool kunit_is_suppressed_warning(bool count)
> > > +{
> > > + if (!static_branch_unlikely(&kunit_running))
> > > + return false;
> > > +
> > > + return kunit_hooks.is_suppressed_warning &&
> > > + kunit_hooks.is_suppressed_warning(count);
> > > +}
> > > +
> > > #else
> > >
> > > static inline struct kunit *kunit_get_current_test(void) { return NULL; }
> > > +static inline bool kunit_is_suppressed_warning(bool count) { return false; }
> > >
> > > #define kunit_fail_current_test(fmt, ...) do {} while (0)
> > >
> > > diff --git a/include/kunit/test.h b/include/kunit/test.h
> > > index 9cd1594ab697d..f278ec028019c 100644
> > > --- a/include/kunit/test.h
> > > +++ b/include/kunit/test.h
> > > @@ -1795,4 +1795,142 @@ do { \
> > > // include resource.h themselves if they need it.
> > > #include <kunit/resource.h>
> > >
> > > +/*
> > > + * Warning backtrace suppression API.
> > > + *
> > > + * Suppresses WARN*() backtraces on the current task while active. Three forms
> > > + * are provided, in order of convenience:
> > > + *
> > > + * - Scoped: kunit_warning_suppress(test) { ... }
> > > + * Suppression is active for the duration of the block. On normal exit,
> > > + * the for-loop increment deactivates suppression. On early exit (break,
> > > + * return, goto), the __cleanup attribute fires. On kthread_exit() (e.g.,
> > > + * a failed KUnit assertion), kunit_add_action() cleans up at test
> > > + * teardown. The suppression handle is only accessible inside the block,
> > > + * so warning counts must be checked before the block exits.
> > > + *
> > > + * - Manual macros: KUNIT_[START|END]_SUPPRESSED_WARNING(test)
> > > + * Suppression spans an explicit range in the same scope. kunit_add_action()
> > > + * guarantees cleanup even if KUNIT_END_SUPPRESSED_WARNING() is not reached.
> > > + * Prefer this form when suppressing warnings across a large block where
> > > + * extra indentation is undesirable, or when the warning count needs to be
> > > + * checked after suppression ends. Limited to one pair per scope.
> > > + *
> > > + * - Direct: kunit_start_suppress_warning() / kunit_end_suppress_warning()
> > > + * The underlying functions, returning an explicit handle pointer. Use
> > > + * when the handle needs to be retained (e.g., for post-suppression
> > > + * count checks) or passed across helper functions.
> > > + */
> > > +struct kunit_suppressed_warning;
> > > +
> > > +struct kunit_suppressed_warning *
> > > +kunit_start_suppress_warning(struct kunit *test);
> > > +void kunit_end_suppress_warning(struct kunit *test,
> > > + struct kunit_suppressed_warning *w);
> > > +int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w);
> > > +void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp);
> > > +bool kunit_has_active_suppress_warning(void);
> > > +
> > > +/**
> > > + * kunit_warning_suppress() - Suppress WARN*() backtraces for the duration
> > > + * of a block.
> > > + * @test: The test context object.
> > > + *
> > > + * Scoped form of the suppression API. Suppression starts when the block is
> > > + * entered and ends automatically when the block exits through any path. See
> > > + * the section comment above for the cleanup guarantees on each exit path.
> > > + * Fails the test if suppression is already active; nesting is not supported.
> > > + *
> > > + * The warning count can be checked inside the block via
> > > + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(). The handle is not accessible
> > > + * after the block exits.
> > > + *
> > > + * Example::
> > > + *
> > > + * kunit_warning_suppress(test) {
> > > + * trigger_warning();
> > > + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> > > + * }
> > > + */
> > > +#define kunit_warning_suppress(test) \
> > > + for (struct kunit_suppressed_warning *__kunit_suppress \
> > > + __cleanup(__kunit_suppress_auto_cleanup) = \
> > > + kunit_start_suppress_warning(test); \
> > > + __kunit_suppress; \
> > > + kunit_end_suppress_warning(test, __kunit_suppress), \
> > > + __kunit_suppress = NULL)
> > > +
> > > +/**
> > > + * KUNIT_START_SUPPRESSED_WARNING() - Begin suppressing WARN*() backtraces.
> > > + * @test: The test context object.
> > > + *
> > > + * Manual form of the suppression API. Must be paired with
> > > + * KUNIT_END_SUPPRESSED_WARNING() in the same scope. See the section comment
> > > + * above for cleanup guarantees. Fails the test if suppression is already
> > > + * active; nesting is not supported. Limited to one pair per scope; use
> > > + * sequential kunit_warning_suppress() blocks or the direct function API
> > > + * when more than one suppression region is needed.
> > > + *
> > > + * Example::
> > > + *
> > > + * KUNIT_START_SUPPRESSED_WARNING(test);
> > > + * trigger_code_that_should_warn_once();
> > > + * KUNIT_END_SUPPRESSED_WARNING(test);
> > > + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> > > + */
> > > +#define KUNIT_START_SUPPRESSED_WARNING(test) \
> > > + struct kunit_suppressed_warning *__kunit_suppress = \
> > > + kunit_start_suppress_warning(test)
> > > +
> > > +/**
> > > + * KUNIT_END_SUPPRESSED_WARNING() - End suppressing WARN*() backtraces.
> > > + * @test: The test context object.
> > > + *
> > > + * Deactivates suppression started by KUNIT_START_SUPPRESSED_WARNING().
> > > + * The warning count remains readable via KUNIT_SUPPRESSED_WARNING_COUNT()
> > > + * after this call.
> > > + */
> > > +#define KUNIT_END_SUPPRESSED_WARNING(test) \
> > > + kunit_end_suppress_warning(test, __kunit_suppress)
> > > +
> > > +/**
> > > + * KUNIT_SUPPRESSED_WARNING_COUNT() - Returns the suppressed warning count.
> > > + *
> > > + * Returns the number of WARN*() calls suppressed since the current
> > > + * suppression block started, or 0 if the handle is NULL. Usable inside a
> > > + * kunit_warning_suppress() block or after KUNIT_END_SUPPRESSED_WARNING().
> > > + */
> > > +#define KUNIT_SUPPRESSED_WARNING_COUNT() \
> > > + kunit_suppressed_warning_count(__kunit_suppress)
> > > +
> > > +/**
> > > + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT() - Sets an expectation that the
> > > + * suppressed warning count equals
> > > + * @expected.
> > > + * @test: The test context object.
> > > + * @expected: an expression that evaluates to the expected warning count.
> > > + *
> > > + * Sets an expectation that the number of suppressed WARN*() calls equals
> > > + * @expected. This is semantically equivalent to
> > > + * KUNIT_EXPECT_EQ(@test, KUNIT_SUPPRESSED_WARNING_COUNT(), @expected).
> > > + * See KUNIT_EXPECT_EQ() for more information.
> > > + */
> > > +#define KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, expected) \
> > > + KUNIT_EXPECT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected)
> > > +
> > > +/**
> > > + * KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT() - Sets an assertion that the
> > > + * suppressed warning count equals
> > > + * @expected.
> > > + * @test: The test context object.
> > > + * @expected: an expression that evaluates to the expected warning count.
> > > + *
> > > + * Sets an assertion that the number of suppressed WARN*() calls equals
> > > + * @expected. This is the same as KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(),
> > > + * except it causes an assertion failure (see KUNIT_ASSERT_TRUE()) when the
> > > + * assertion is not met.
> > > + */
> > > +#define KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT(test, expected) \
> > > + KUNIT_ASSERT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected)
> > > +
> > > #endif /* _KUNIT_TEST_H */
> > > diff --git a/kernel/panic.c b/kernel/panic.c
> > > index c78600212b6c1..697d8ca054bef 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/test-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(true))
> > > + return;
> > > +
> > > + rcu = warn_rcu_enter();
> > > +
> > > pr_warn(CUT_HERE);
> > >
> > > if (!fmt) {
> > > @@ -1102,9 +1108,14 @@ EXPORT_SYMBOL(warn_slowpath_fmt);
> > > #else
> > > void __warn_printk(const char *fmt, ...)
> > > {
> > > - bool rcu = warn_rcu_enter();
> > > + bool rcu;
> > > va_list args;
> > >
> > > + if (kunit_is_suppressed_warning(false))
> > > + return;
> > > +
> > > + rcu = warn_rcu_enter();
> > > +
> > > pr_warn(CUT_HERE);
> > >
> > > va_start(args, fmt);
> > > diff --git a/lib/bug.c b/lib/bug.c
> > > index 623c467a8b76c..a5cebde554ed8 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/test-bug.h>
> > >
> > > extern struct bug_entry __start___bug_table[], __stop___bug_table[];
> > >
> > > @@ -223,6 +224,15 @@ 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;
> > >
> > > +#ifdef CONFIG_KUNIT
> > > + /*
> > > + * Before the once logic so suppressed warnings do not consume
> > > + * the single-fire budget of WARN_ON_ONCE().
> > > + */
> > > + if (warning && kunit_is_suppressed_warning(true))
> > > + return BUG_TRAP_TYPE_WARN;
> > > +#endif
> > > +
> > > if (warning && once) {
> > > if (done)
> > > return BUG_TRAP_TYPE_WARN;
> > > diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
> > > index 656f1fa35abcc..4592f9d0aa8dd 100644
> > > --- a/lib/kunit/Makefile
> > > +++ b/lib/kunit/Makefile
> > > @@ -10,7 +10,8 @@ kunit-objs += test.o \
> > > executor.o \
> > > attributes.o \
> > > device.o \
> > > - platform.o
> > > + platform.o \
> > > + bug.o
> > >
> > > ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
> > > kunit-objs += debugfs.o
> > > diff --git a/lib/kunit/bug.c b/lib/kunit/bug.c
> > > new file mode 100644
> > > index 0000000000000..b0b6778d7399a
> > > --- /dev/null
> > > +++ b/lib/kunit/bug.c
> > > @@ -0,0 +1,115 @@
> > > +// 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/resource.h>
> > > +#include <linux/export.h>
> > > +#include <linux/rculist.h>
> > > +#include <linux/sched.h>
> > > +#include <linux/spinlock.h>
> > > +
> > > +#include "hooks-impl.h"
> > > +
> > > +struct kunit_suppressed_warning {
> > > + struct list_head node;
> > > + struct task_struct *task;
> > > + struct kunit *test;
> > > + int counter;
> > > +};
> > > +
> > > +static LIST_HEAD(suppressed_warnings);
> > > +static DEFINE_SPINLOCK(suppressed_warnings_lock);
> > > +
> > > +static void kunit_suppress_warning_remove(struct kunit_suppressed_warning *w)
> > > +{
> > > + unsigned long flags;
> > > +
> > > + spin_lock_irqsave(&suppressed_warnings_lock, flags);
> > > + list_del_rcu(&w->node);
> > > + spin_unlock_irqrestore(&suppressed_warnings_lock, flags);
> > > + synchronize_rcu(); /* Wait for readers to finish */
> > > +}
> > > +
> > > +KUNIT_DEFINE_ACTION_WRAPPER(kunit_suppress_warning_cleanup,
> > > + kunit_suppress_warning_remove,
> > > + struct kunit_suppressed_warning *);
> > > +
> > > +bool kunit_has_active_suppress_warning(void)
> > > +{
> > > + return __kunit_is_suppressed_warning_impl(false);
> > > +}
> > > +EXPORT_SYMBOL_GPL(kunit_has_active_suppress_warning);
> > > +
> > > +struct kunit_suppressed_warning *
> > > +kunit_start_suppress_warning(struct kunit *test)
> > > +{
> > > + struct kunit_suppressed_warning *w;
> > > + unsigned long flags;
> > > + int ret;
> > > +
> > > + if (kunit_has_active_suppress_warning()) {
> > > + KUNIT_FAIL(test, "Another suppression block is already active");
> > > + return NULL;
> > > + }
> > > +
> > > + w = kunit_kzalloc(test, sizeof(*w), GFP_KERNEL);
> > > + if (!w)
> > > + return NULL;
> > > +
> > > + w->task = current;
> > > + w->test = test;
> > > +
> > > + spin_lock_irqsave(&suppressed_warnings_lock, flags);
> > > + list_add_rcu(&w->node, &suppressed_warnings);
> > > + spin_unlock_irqrestore(&suppressed_warnings_lock, flags);
> > > +
> > > + ret = kunit_add_action_or_reset(test,
> > > + kunit_suppress_warning_cleanup, w);
> > > + if (ret)
> > > + return NULL;
> > > +
> > > + return w;
> > > +}
> > > +EXPORT_SYMBOL_GPL(kunit_start_suppress_warning);
> > > +
> > > +void kunit_end_suppress_warning(struct kunit *test,
> > > + struct kunit_suppressed_warning *w)
> > > +{
> > > + if (!w)
> > > + return;
> > > + kunit_release_action(test, kunit_suppress_warning_cleanup, w);
> > > +}
> > > +EXPORT_SYMBOL_GPL(kunit_end_suppress_warning);
> > > +
> > > +void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp)
> > > +{
> > > + if (*wp)
> > > + kunit_end_suppress_warning((*wp)->test, *wp);
> > > +}
> > > +EXPORT_SYMBOL_GPL(__kunit_suppress_auto_cleanup);
> > > +
> > > +int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w)
> > > +{
> > > + return w ? w->counter : 0;
> > > +}
> > > +EXPORT_SYMBOL_GPL(kunit_suppressed_warning_count);
> > > +
> > > +bool __kunit_is_suppressed_warning_impl(bool count)
> > > +{
> > > + struct kunit_suppressed_warning *w;
> > > +
> > > + guard(rcu)();
> > > + list_for_each_entry_rcu(w, &suppressed_warnings, node) {
> > > + if (w->task == current) {
> > > + if (count)
> > > + w->counter++;
> > > + return true;
> > > + }
> > > + }
> > > +
> > > + return false;
> > > +}
> > > diff --git a/lib/kunit/hooks-impl.h b/lib/kunit/hooks-impl.h
> > > index 4e71b2d0143ba..d8720f2616925 100644
> > > --- a/lib/kunit/hooks-impl.h
> > > +++ b/lib/kunit/hooks-impl.h
> > > @@ -19,6 +19,7 @@ void __printf(3, 4) __kunit_fail_current_test_impl(const char *file,
> > > int line,
> > > const char *fmt, ...);
> > > void *__kunit_get_static_stub_address_impl(struct kunit *test, void *real_fn_addr);
> > > +bool __kunit_is_suppressed_warning_impl(bool count);
> > >
> > > /* Code to set all of the function pointers. */
> > > static inline void kunit_install_hooks(void)
> > > @@ -26,6 +27,7 @@ static inline void kunit_install_hooks(void)
> > > /* Install the KUnit hook functions. */
> > > kunit_hooks.fail_current_test = __kunit_fail_current_test_impl;
> > > kunit_hooks.get_static_stub_address = __kunit_get_static_stub_address_impl;
> > > + kunit_hooks.is_suppressed_warning = __kunit_is_suppressed_warning_impl;
> > > }
> > >
> > > #endif /* _KUNIT_HOOKS_IMPL_H */
> > >
> >
^ permalink raw reply
* Re: [PATCH v8 1/4] bug/kunit: Core support for suppressing warning backtraces
From: David Gow @ 2026-05-08 10:10 UTC (permalink / raw)
To: Albert Esteve
Cc: Arnd Bergmann, Brendan Higgins, Rae Moar, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Andrew Morton, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, linux-kernel,
linux-arch, linux-kselftest, kunit-dev, dri-devel, workflows,
linux-riscv, linux-doc, peterz, Alessandro Carminati,
Guenter Roeck, Kees Cook
In-Reply-To: <CADSE00L5OCSNH_XsUHSvi_wAwZWiC2=bUGmiXVAu-LZ=XtvDjQ@mail.gmail.com>
Le 08/05/2026 à 14:52, Albert Esteve a écrit :
> On Wed, May 6, 2026 at 12:11 PM Albert Esteve <aesteve@redhat.com> wrote:
>>
>> On Wed, May 6, 2026 at 11:40 AM David Gow <david@davidgow.net> wrote:
>>>
>>> Le 04/05/2026 à 3:41 PM, Albert Esteve a écrit :
>>>> 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 suppress warning backtraces
>>>> originating from the current kthread while executing test code. Since
>>>> each KUnit test runs in its own kthread, this effectively scopes
>>>> suppression to the test that enabled it. Limit changes to generic code
>>>> to the absolute minimum.
>>>>
>>>> Implementation details:
>>>> Suppression is integrated into the existing KUnit hooks infrastructure
>>>> in test-bug.h, reusing the kunit_running static branch for zero
>>>> overhead when no tests are running.
>>>>
>>>> Suppression is checked at three points in the warning path:
>>>> - In warn_slowpath_fmt(), the check runs before any output, fully
>>>> suppressing both message and backtrace. This covers architectures
>>>> without __WARN_FLAGS.
>>>> - In __warn_printk(), the check suppresses the warning message text.
>>>> This covers architectures that define __WARN_FLAGS but not their own
>>>> __WARN_printf (arm64, loongarch, parisc, powerpc, riscv, sh), where
>>>> the message is printed before the trap enters __report_bug().
>>>> - In __report_bug(), the check runs before __warn() is called,
>>>> suppressing the backtrace and stack dump.
>>>>
>>>> To avoid double-counting on architectures where both __warn_printk()
>>>> and __report_bug() run for the same warning, kunit_is_suppressed_warning()
>>>> takes a bool parameter: true to increment the suppression counter
>>>> (used in warn_slowpath_fmt and __report_bug), false to check only
>>>> (used in __warn_printk).
>>>>
>>>> The suppression state is dynamically allocated via kunit_kzalloc() and
>>>> tied to the KUnit test lifecycle via kunit_add_action(), ensuring
>>>> automatic cleanup at test exit. Writer-side access to the global
>>>> suppression list is serialized with a spinlock; readers use RCU.
>>>>
>>>> Three API forms are provided:
>>>> - kunit_warning_suppress(test) { ... }: scoped, uses __cleanup for
>>>> automatic teardown on scope exit, kunit_add_action() as safety net
>>>> for abnormal exits (e.g. kthread_exit from failed assertions).
>>>> Suppression handle is only accessible inside the block.
>>>> - KUNIT_START/END_SUPPRESSED_WARNING(test): manual macros for larger
>>>> blocks or when warning counts need to be checked after suppression
>>>> ends. Limited to one pair per scope.
>>>> - kunit_start/end_suppress_warning(test): direct functions returning
>>>> an explicit handle, for retaining the handle within the test,
>>>> or for cross-function usage.
>>>>
>>>> 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>
>>>> ---
>>>
>>> This looks pretty good to me, thanks.
>>>
>>> Reviewed-by: David Gow <david@davidgow.net>
>>>
>>> It's maybe slightly over-the-top to now have three different ways of
>>> enabling warning suppression: I'd probably personally get rid of
>>> KUNIT_START/END_SUPPRESSED_WARNING() if we had to lose one. But if
>>> there's a real reason to prefer keeping all three, it's not actually a
>>> problem to do so.
>>
>> Thanks for the review!
>>
>> I think the three forms earn their keep: the scoped form is the go-to
>> for most cases, but the macros avoid indentation without requiring
>> users to manage a raw pointer. I initially removed the macros and
>> added them back later. Direct calls to the functions will be less
>> frequent, used only when you need the handle.
>>
>> That said, if it becomes a maintenance burden, the macros are the
>> easiest to drop since they're thin wrappers. Let me know if you prefer
>> them to be dropped, and I will send a v9 with that and the
>> `KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT` additions to the drm test
>> patch.
>>
>> BR,
>> Albert.
>>
>>>
>>> Regardless, this series is looking pretty ready to me. Let me know if
>>> you're planning a v9, otherwise we'll take this when you're ready.
>
> I have been thinking, and despite my last response arguing against it,
> I think I will send that v9 and remove
> KUNIT_START/END_SUPPRESSED_WARNING(). Since the scoped approach with a
> reduced extent should be the default style for most cases, the direct
> calls can cover any other use cases without needing macros. Plus,
> since macros set the handler name for you, it seems odd not to be able
> to use them more than once per test.
Yeah, that was a part of my thought: all of the possible uses of
KUNIT_START/END_SUPPRESSED_WARNING() can be replaced with the scoped
version except for the one case where you want to check the number of
warnings specifically after the scope. I'm not sure the latter would be
common, and in the few places it's useful, the direct calls are not
_that_ much more difficult to use.
> I hope that's ok. After that I think it should be ready (at least from my side).
>
Sounds good: assuming no last-minute disasters, we'll take v9 then.
Cheers,
-- David
^ permalink raw reply
* [PATCH v9 0/4] kunit: Add support for suppressing warning backtraces
From: Albert Esteve @ 2026-05-08 15:02 UTC (permalink / raw)
To: Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jonathan Corbet, Shuah Khan, Andrew Morton,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
workflows, linux-riscv, linux-doc, peterz, Alessandro Carminati,
Guenter Roeck, Kees Cook, Albert Esteve,
Linux Kernel Functional Testing, Maíra Canal, Dan Carpenter,
Kees Cook, Simona Vetter
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.
One option to address the problem would be to add messages such as
"expected warning backtraces start/end here" to the kernel log.
However, that would again require filter scripts, might result in
missing real problematic warning backtraces triggered while the test
is running, and the irrelevant backtrace(s) would still clog the
kernel log.
Solve the problem by providing a means to suppress warning backtraces
originating from the current kthread while executing test code.
Since each KUnit test runs in its own kthread, this effectively scopes
suppression to the test that enabled it, without requiring any
architecture-specific code.
Overview:
Patch#1 Introduces the suppression infrastructure integrated into
KUnit's hook mechanism.
Patch#2 Adds selftests to validate the functionality.
Patch#3 Demonstrates real-world usage in the DRM subsystem.
Patch#4 Documents the new API and usage guidelines.
Design Notes:
Suppression is integrated into the existing KUnit hooks infrastructure,
reusing the kunit_running static branch for zero overhead
when no tests are running. The implementation lives entirely in the
kunit module; only a static-inline wrapper and a function pointer
slot are added to built-in code.
Suppression is checked at three points in the warning path:
- In `warn_slowpath_fmt()` (kernel/panic.c), for architectures without
__WARN_FLAGS. The check runs before any output, fully suppressing
both message and backtrace.
- In `__warn_printk()` (kernel/panic.c), for architectures that define
__WARN_FLAGS but not their own __WARN_printf (arm64, loongarch,
parisc, powerpc, riscv, sh). The check suppresses the warning message
text that is printed before the trap enters __report_bug().
- In `__report_bug()` (lib/bug.c), for architectures that define
__WARN_FLAGS. The check runs before `__warn()` is called, suppressing
the backtrace and stack dump.
To avoid double-counting on architectures where both `__warn_printk()`
and `__report_bug()` run for the same warning, the hook takes a bool
parameter: true to increment the suppression counter, false to suppress
without counting.
The suppression state is dynamically allocated via kunit_kzalloc() and
tied to the KUnit test lifecycle via `kunit_add_action()`, ensuring
automatic cleanup at test exit. Writer-side access to the global
suppression list is serialized with a spinlock; readers use RCU.
Two API forms are provided:
- kunit_warning_suppress(test) { ... }: scoped blocks with automatic
cleanup. The suppression handle is not accessible outside the block,
so warning counts (if needed) must be checked inside. Multiple
suppression blocks are allowed.
- kunit_start/end_suppress_warning(test): direct functions that return
an explicit handle. Use when the handle needs to be retained, or passed
across helpers. Multiple suppression blocks are allowed.
This series is based on the RFC patch and subsequent discussion at
https://patchwork.kernel.org/project/linux-kselftest/patch/02546e59-1afe-4b08-ba81-d94f3b691c9a@moroto.mountain/
and offers a more comprehensive solution of the problem discussed there.
Changes since RFC:
- Introduced CONFIG_KUNIT_SUPPRESS_BACKTRACE
- Minor cleanups and bug fixes
- Added support for all affected architectures
- Added support for counting suppressed warnings
- Added unit tests using those counters
- Added patch to suppress warning backtraces in dev_addr_lists tests
Changes since v1:
- Rebased to v6.9-rc1
- Added Tested-by:, Acked-by:, and Reviewed-by: tags
[I retained those tags since there have been no functional changes]
- Introduced KUNIT_SUPPRESS_BACKTRACE configuration option, enabled by
default.
Changes since v2:
- Rebased to v6.9-rc2
- Added comments to drm warning suppression explaining why it is needed.
- Added patch to move conditional code in arch/sh/include/asm/bug.h
to avoid kerneldoc warning
- Added architecture maintainers to Cc: for architecture specific patches
- No functional changes
Changes since v3:
- Rebased to v6.14-rc6
- Dropped net: "kunit: Suppress lock warning noise at end of dev_addr_lists tests"
since 3db3b62955cd6d73afde05a17d7e8e106695c3b9
- Added __kunit_ and KUNIT_ prefixes.
- Tested on interessed architectures.
Changes since v4:
- Rebased to v6.15-rc7
- Dropped all code in __report_bug()
- Moved all checks in WARN*() macros.
- Dropped all architecture specific code.
- Made __kunit_is_suppressed_warning nice to noinstr functions.
Changes since v5:
- Rebased to v7.0-rc3
- Added RCU protection for the suppressed warnings list.
- Added static key and branching optimization.
- Removed custom `strcmp` implementation and reworked
__kunit_is_suppressed_warning() entrypoint function.
Changes since v6:
- Moved suppression checks from WARN*() macros to warn_slowpath_fmt()
and __report_bug().
- Replaced stack-allocated suppression struct with kunit_kzalloc() heap
allocation tied to the KUnit test lifecycle.
- Changed suppression strategy from function-name matching to task-scoped:
all warnings on the current task are suppressed between START and END,
rather than only warnings originating from a specific named function.
- Simplified macro API: removed KUNIT_DECLARE_SUPPRESSED_WARNING(),
the START macro now takes (test) and handles allocation internally.
- Removed static key and branching optiomization, as by the time it
was executed, callers are already in warn slowpaths.
- Link to v6: https://lore.kernel.org/r/20260317-kunit_add_support-v6-0-dd22aeb3fe5d@redhat.com
Changes since v7:
- Integrated suppression into existing KUnit hooks infrastructure
- Removed CONFIG_KUNIT_SUPPRESS_BACKTRACE
- Added suppression check in __warn_printk()
- Added spinlock for writer-side RCU protection
- Replaced explicit rcu_read_lock/unlock with guard(rcu)()
- Added scoped API (kunit_warning_suppress) using __cleanup attribute
- Updated DRM patch to use scoped API
- Expanded self-tests: incremental counting, cross-kthread isolation
- Rewrote documentation covering all three API forms with examples
- Link to v7: https://lore.kernel.org/r/20260420-kunit_add_support-v7-0-e8bc6e0f70de@redhat.com
Changes since v8:
- Rebased to v7.1-rc2
- Remove KUNIT_START/END_SUPPRESSED_WARNING() macros
- Add KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT checks to drm tests
- Link to v8: https://lore.kernel.org/r/20260504-kunit_add_support-v8-0-3e5957cdd235@redhat.com
--
2.34.1
---
Alessandro Carminati (1):
bug/kunit: Core support for suppressing warning backtraces
Guenter Roeck (3):
kunit: Add backtrace suppression self-tests
drm: Suppress intentional warning backtraces in scaling unit tests
kunit: Add documentation for warning backtrace suppression API
Documentation/dev-tools/kunit/usage.rst | 46 ++++++++-
drivers/gpu/drm/tests/drm_rect_test.c | 27 ++++-
include/kunit/test-bug.h | 25 +++++
include/kunit/test.h | 98 ++++++++++++++++++
kernel/panic.c | 15 ++-
lib/bug.c | 10 ++
lib/kunit/Makefile | 4 +-
lib/kunit/backtrace-suppression-test.c | 176 ++++++++++++++++++++++++++++++++
lib/kunit/bug.c | 115 +++++++++++++++++++++
lib/kunit/hooks-impl.h | 2 +
10 files changed, 510 insertions(+), 8 deletions(-)
---
base-commit: 74fe02ce122a6103f207d29fafc8b3a53de6abaf
change-id: 20260312-kunit_add_support-2f35806b19dd
Best regards,
--
Albert Esteve <aesteve@redhat.com>
^ permalink raw reply
* [PATCH v9 1/4] bug/kunit: Core support for suppressing warning backtraces
From: Albert Esteve @ 2026-05-08 15:02 UTC (permalink / raw)
To: Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jonathan Corbet, Shuah Khan, Andrew Morton,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
workflows, linux-riscv, linux-doc, peterz, Alessandro Carminati,
Guenter Roeck, Kees Cook, Albert Esteve
In-Reply-To: <20260508-kunit_add_support-v9-0-99df7aa880f6@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 suppress warning backtraces
originating from the current kthread while executing test code. Since
each KUnit test runs in its own kthread, this effectively scopes
suppression to the test that enabled it. Limit changes to generic code
to the absolute minimum.
Implementation details:
Suppression is integrated into the existing KUnit hooks infrastructure
in test-bug.h, reusing the kunit_running static branch for zero
overhead when no tests are running.
Suppression is checked at three points in the warning path:
- In warn_slowpath_fmt(), the check runs before any output, fully
suppressing both message and backtrace. This covers architectures
without __WARN_FLAGS.
- In __warn_printk(), the check suppresses the warning message text.
This covers architectures that define __WARN_FLAGS but not their own
__WARN_printf (arm64, loongarch, parisc, powerpc, riscv, sh), where
the message is printed before the trap enters __report_bug().
- In __report_bug(), the check runs before __warn() is called,
suppressing the backtrace and stack dump.
To avoid double-counting on architectures where both __warn_printk()
and __report_bug() run for the same warning, kunit_is_suppressed_warning()
takes a bool parameter: true to increment the suppression counter
(used in warn_slowpath_fmt and __report_bug), false to check only
(used in __warn_printk).
The suppression state is dynamically allocated via kunit_kzalloc() and
tied to the KUnit test lifecycle via kunit_add_action(), ensuring
automatic cleanup at test exit. Writer-side access to the global
suppression list is serialized with a spinlock; readers use RCU.
Two API forms are provided:
- kunit_warning_suppress(test) { ... }: scoped, uses __cleanup for
automatic teardown on scope exit, kunit_add_action() as safety net
for abnormal exits (e.g. kthread_exit from failed assertions).
Suppression handle is only accessible inside the block.
- kunit_start/end_suppress_warning(test): direct functions returning
an explicit handle, for retaining the handle within the test,
or for cross-function usage.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Alessandro Carminati <acarmina@redhat.com>
Reviewed-by: Kees Cook <kees@kernel.org>
Reviewed-by: David Gow <david@davidgow.net>
Signed-off-by: Albert Esteve <aesteve@redhat.com>
---
include/kunit/test-bug.h | 25 +++++++++++
include/kunit/test.h | 98 ++++++++++++++++++++++++++++++++++++++++
kernel/panic.c | 15 ++++++-
lib/bug.c | 10 +++++
lib/kunit/Makefile | 3 +-
lib/kunit/bug.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++
lib/kunit/hooks-impl.h | 2 +
7 files changed, 265 insertions(+), 3 deletions(-)
diff --git a/include/kunit/test-bug.h b/include/kunit/test-bug.h
index 47aa8f21ccce8..6237e48ceadfd 100644
--- a/include/kunit/test-bug.h
+++ b/include/kunit/test-bug.h
@@ -23,6 +23,7 @@ DECLARE_STATIC_KEY_FALSE(kunit_running);
extern struct kunit_hooks_table {
__printf(3, 4) void (*fail_current_test)(const char*, int, const char*, ...);
void *(*get_static_stub_address)(struct kunit *test, void *real_fn_addr);
+ bool (*is_suppressed_warning)(bool count);
} kunit_hooks;
/**
@@ -60,9 +61,33 @@ static inline struct kunit *kunit_get_current_test(void)
} \
} while (0)
+/**
+ * kunit_is_suppressed_warning() - Check if warnings are being suppressed
+ * by the current KUnit test.
+ * @count: if true, increment the suppression counter on match.
+ *
+ * Returns true if the current task has active warning suppression.
+ * Uses the kunit_running static branch for zero overhead when no tests run.
+ *
+ * A single WARN*() may traverse multiple call sites in the warning path
+ * (e.g., __warn_printk() and __report_bug()). Pass @count = true at the
+ * primary suppression point to count each warning exactly once, and
+ * @count = false at secondary points to suppress output without
+ * inflating the count.
+ */
+static inline bool kunit_is_suppressed_warning(bool count)
+{
+ if (!static_branch_unlikely(&kunit_running))
+ return false;
+
+ return kunit_hooks.is_suppressed_warning &&
+ kunit_hooks.is_suppressed_warning(count);
+}
+
#else
static inline struct kunit *kunit_get_current_test(void) { return NULL; }
+static inline bool kunit_is_suppressed_warning(bool count) { return false; }
#define kunit_fail_current_test(fmt, ...) do {} while (0)
diff --git a/include/kunit/test.h b/include/kunit/test.h
index 9cd1594ab697d..be71612f61655 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -1795,4 +1795,102 @@ do { \
// include resource.h themselves if they need it.
#include <kunit/resource.h>
+/*
+ * Warning backtrace suppression API.
+ *
+ * Suppresses WARN*() backtraces on the current task while active. Two forms
+ * are provided:
+ *
+ * - Scoped: kunit_warning_suppress(test) { ... }
+ * Suppression is active for the duration of the block. On normal exit,
+ * the for-loop increment deactivates suppression. On early exit (break,
+ * return, goto), the __cleanup attribute fires. On kthread_exit() (e.g.,
+ * a failed KUnit assertion), kunit_add_action() cleans up at test
+ * teardown. The suppression handle is only accessible inside the block,
+ * so warning counts must be checked before the block exits.
+ *
+ * - Direct: kunit_start_suppress_warning() / kunit_end_suppress_warning()
+ * The underlying functions, returning an explicit handle pointer. Use
+ * when the handle needs to be retained (e.g., for post-suppression
+ * count checks) or passed across helper functions.
+ */
+struct kunit_suppressed_warning;
+
+struct kunit_suppressed_warning *
+kunit_start_suppress_warning(struct kunit *test);
+void kunit_end_suppress_warning(struct kunit *test,
+ struct kunit_suppressed_warning *w);
+int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w);
+void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp);
+bool kunit_has_active_suppress_warning(void);
+
+/**
+ * kunit_warning_suppress() - Suppress WARN*() backtraces for the duration
+ * of a block.
+ * @test: The test context object.
+ *
+ * Scoped form of the suppression API. Suppression starts when the block is
+ * entered and ends automatically when the block exits through any path. See
+ * the section comment above for the cleanup guarantees on each exit path.
+ * Fails the test if suppression is already active; nesting is not supported.
+ *
+ * The warning count can be checked inside the block via
+ * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(). The handle is not accessible
+ * after the block exits.
+ *
+ * Example::
+ *
+ * kunit_warning_suppress(test) {
+ * trigger_warning();
+ * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
+ * }
+ */
+#define kunit_warning_suppress(test) \
+ for (struct kunit_suppressed_warning *__kunit_suppress \
+ __cleanup(__kunit_suppress_auto_cleanup) = \
+ kunit_start_suppress_warning(test); \
+ __kunit_suppress; \
+ kunit_end_suppress_warning(test, __kunit_suppress), \
+ __kunit_suppress = NULL)
+
+/**
+ * KUNIT_SUPPRESSED_WARNING_COUNT() - Returns the suppressed warning count.
+ *
+ * Returns the number of WARN*() calls suppressed since the current
+ * suppression block started, or 0 if the handle is NULL. Usable inside a
+ * kunit_warning_suppress() block.
+ */
+#define KUNIT_SUPPRESSED_WARNING_COUNT() \
+ kunit_suppressed_warning_count(__kunit_suppress)
+
+/**
+ * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT() - Sets an expectation that the
+ * suppressed warning count equals
+ * @expected.
+ * @test: The test context object.
+ * @expected: an expression that evaluates to the expected warning count.
+ *
+ * Sets an expectation that the number of suppressed WARN*() calls equals
+ * @expected. This is semantically equivalent to
+ * KUNIT_EXPECT_EQ(@test, KUNIT_SUPPRESSED_WARNING_COUNT(), @expected).
+ * See KUNIT_EXPECT_EQ() for more information.
+ */
+#define KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, expected) \
+ KUNIT_EXPECT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected)
+
+/**
+ * KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT() - Sets an assertion that the
+ * suppressed warning count equals
+ * @expected.
+ * @test: The test context object.
+ * @expected: an expression that evaluates to the expected warning count.
+ *
+ * Sets an assertion that the number of suppressed WARN*() calls equals
+ * @expected. This is the same as KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(),
+ * except it causes an assertion failure (see KUNIT_ASSERT_TRUE()) when the
+ * assertion is not met.
+ */
+#define KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT(test, expected) \
+ KUNIT_ASSERT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected)
+
#endif /* _KUNIT_TEST_H */
diff --git a/kernel/panic.c b/kernel/panic.c
index 20feada5319d4..41c530d60efbf 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/test-bug.h>
#define PANIC_TIMER_STEP 100
#define PANIC_BLINK_SPD 18
@@ -1121,9 +1122,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(true))
+ return;
+
+ rcu = warn_rcu_enter();
+
pr_warn(CUT_HERE);
if (!fmt) {
@@ -1143,9 +1149,14 @@ EXPORT_SYMBOL(warn_slowpath_fmt);
#else
void __warn_printk(const char *fmt, ...)
{
- bool rcu = warn_rcu_enter();
+ bool rcu;
va_list args;
+ if (kunit_is_suppressed_warning(false))
+ return;
+
+ rcu = warn_rcu_enter();
+
pr_warn(CUT_HERE);
va_start(args, fmt);
diff --git a/lib/bug.c b/lib/bug.c
index 224f4cfa4aa31..255530284502a 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/test-bug.h>
extern struct bug_entry __start___bug_table[], __stop___bug_table[];
@@ -220,6 +221,15 @@ 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;
+#ifdef CONFIG_KUNIT
+ /*
+ * Before the once logic so suppressed warnings do not consume
+ * the single-fire budget of WARN_ON_ONCE().
+ */
+ if (warning && kunit_is_suppressed_warning(true))
+ return BUG_TRAP_TYPE_WARN;
+#endif
+
if (warning && once) {
if (done)
return BUG_TRAP_TYPE_WARN;
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 656f1fa35abcc..4592f9d0aa8dd 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -10,7 +10,8 @@ kunit-objs += test.o \
executor.o \
attributes.o \
device.o \
- platform.o
+ platform.o \
+ bug.o
ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
kunit-objs += debugfs.o
diff --git a/lib/kunit/bug.c b/lib/kunit/bug.c
new file mode 100644
index 0000000000000..b0b6778d7399a
--- /dev/null
+++ b/lib/kunit/bug.c
@@ -0,0 +1,115 @@
+// 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/resource.h>
+#include <linux/export.h>
+#include <linux/rculist.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+
+#include "hooks-impl.h"
+
+struct kunit_suppressed_warning {
+ struct list_head node;
+ struct task_struct *task;
+ struct kunit *test;
+ int counter;
+};
+
+static LIST_HEAD(suppressed_warnings);
+static DEFINE_SPINLOCK(suppressed_warnings_lock);
+
+static void kunit_suppress_warning_remove(struct kunit_suppressed_warning *w)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&suppressed_warnings_lock, flags);
+ list_del_rcu(&w->node);
+ spin_unlock_irqrestore(&suppressed_warnings_lock, flags);
+ synchronize_rcu(); /* Wait for readers to finish */
+}
+
+KUNIT_DEFINE_ACTION_WRAPPER(kunit_suppress_warning_cleanup,
+ kunit_suppress_warning_remove,
+ struct kunit_suppressed_warning *);
+
+bool kunit_has_active_suppress_warning(void)
+{
+ return __kunit_is_suppressed_warning_impl(false);
+}
+EXPORT_SYMBOL_GPL(kunit_has_active_suppress_warning);
+
+struct kunit_suppressed_warning *
+kunit_start_suppress_warning(struct kunit *test)
+{
+ struct kunit_suppressed_warning *w;
+ unsigned long flags;
+ int ret;
+
+ if (kunit_has_active_suppress_warning()) {
+ KUNIT_FAIL(test, "Another suppression block is already active");
+ return NULL;
+ }
+
+ w = kunit_kzalloc(test, sizeof(*w), GFP_KERNEL);
+ if (!w)
+ return NULL;
+
+ w->task = current;
+ w->test = test;
+
+ spin_lock_irqsave(&suppressed_warnings_lock, flags);
+ list_add_rcu(&w->node, &suppressed_warnings);
+ spin_unlock_irqrestore(&suppressed_warnings_lock, flags);
+
+ ret = kunit_add_action_or_reset(test,
+ kunit_suppress_warning_cleanup, w);
+ if (ret)
+ return NULL;
+
+ return w;
+}
+EXPORT_SYMBOL_GPL(kunit_start_suppress_warning);
+
+void kunit_end_suppress_warning(struct kunit *test,
+ struct kunit_suppressed_warning *w)
+{
+ if (!w)
+ return;
+ kunit_release_action(test, kunit_suppress_warning_cleanup, w);
+}
+EXPORT_SYMBOL_GPL(kunit_end_suppress_warning);
+
+void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp)
+{
+ if (*wp)
+ kunit_end_suppress_warning((*wp)->test, *wp);
+}
+EXPORT_SYMBOL_GPL(__kunit_suppress_auto_cleanup);
+
+int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w)
+{
+ return w ? w->counter : 0;
+}
+EXPORT_SYMBOL_GPL(kunit_suppressed_warning_count);
+
+bool __kunit_is_suppressed_warning_impl(bool count)
+{
+ struct kunit_suppressed_warning *w;
+
+ guard(rcu)();
+ list_for_each_entry_rcu(w, &suppressed_warnings, node) {
+ if (w->task == current) {
+ if (count)
+ w->counter++;
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/lib/kunit/hooks-impl.h b/lib/kunit/hooks-impl.h
index 4e71b2d0143ba..d8720f2616925 100644
--- a/lib/kunit/hooks-impl.h
+++ b/lib/kunit/hooks-impl.h
@@ -19,6 +19,7 @@ void __printf(3, 4) __kunit_fail_current_test_impl(const char *file,
int line,
const char *fmt, ...);
void *__kunit_get_static_stub_address_impl(struct kunit *test, void *real_fn_addr);
+bool __kunit_is_suppressed_warning_impl(bool count);
/* Code to set all of the function pointers. */
static inline void kunit_install_hooks(void)
@@ -26,6 +27,7 @@ static inline void kunit_install_hooks(void)
/* Install the KUnit hook functions. */
kunit_hooks.fail_current_test = __kunit_fail_current_test_impl;
kunit_hooks.get_static_stub_address = __kunit_get_static_stub_address_impl;
+ kunit_hooks.is_suppressed_warning = __kunit_is_suppressed_warning_impl;
}
#endif /* _KUNIT_HOOKS_IMPL_H */
--
2.53.0
^ permalink raw reply related
* [PATCH v9 2/4] kunit: Add backtrace suppression self-tests
From: Albert Esteve @ 2026-05-08 15:02 UTC (permalink / raw)
To: Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jonathan Corbet, Shuah Khan, Andrew Morton,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
workflows, linux-riscv, linux-doc, peterz, Guenter Roeck,
Linux Kernel Functional Testing, Alessandro Carminati,
Albert Esteve, Dan Carpenter, Kees Cook
In-Reply-To: <20260508-kunit_add_support-v9-0-99df7aa880f6@redhat.com>
From: Guenter Roeck <linux@roeck-us.net>
Add unit tests to verify that warning backtrace suppression works.
Tests cover both API forms:
- Scoped: kunit_warning_suppress() with in-block count verification
and post-block inactivity check.
- Direct functions: kunit_start/end_suppress_warning() with
sequential independent suppression blocks and per-block counts.
Furthermore, tests verify incremental warning counting, that
kunit_has_active_suppress_warning() transitions correctly around
suppression boundaries, and that suppression active in the test
kthread does not leak to a separate kthread.
If backtrace suppression does _not_ work, the unit tests will likely
trigger unsuppressed backtraces, which should actually help to get
the affected architectures / platforms fixed.
Tested-by: Linux Kernel Functional Testing <lkft@linaro.org>
Acked-by: Dan Carpenter <dan.carpenter@linaro.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Alessandro Carminati <acarmina@redhat.com>
Reviewed-by: David Gow <david@davidgow.net>
Signed-off-by: Albert Esteve <aesteve@redhat.com>
---
lib/kunit/Makefile | 1 +
lib/kunit/backtrace-suppression-test.c | 176 +++++++++++++++++++++++++++++++++
2 files changed, 177 insertions(+)
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 4592f9d0aa8dd..2e8a6b71a2ab0 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -22,6 +22,7 @@ obj-$(if $(CONFIG_KUNIT),y) += hooks.o
obj-$(CONFIG_KUNIT_TEST) += kunit-test.o
obj-$(CONFIG_KUNIT_TEST) += platform-test.o
+obj-$(CONFIG_KUNIT_TEST) += backtrace-suppression-test.o
# string-stream-test compiles built-in only.
ifeq ($(CONFIG_KUNIT_TEST),y)
diff --git a/lib/kunit/backtrace-suppression-test.c b/lib/kunit/backtrace-suppression-test.c
new file mode 100644
index 0000000000000..3f0b2ae83312f
--- /dev/null
+++ b/lib/kunit/backtrace-suppression-test.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit test for suppressing warning tracebacks.
+ *
+ * Copyright (C) 2024, Guenter Roeck
+ * Author: Guenter Roeck <linux@roeck-us.net>
+ */
+
+#include <kunit/test.h>
+#include <linux/bug.h>
+#include <linux/completion.h>
+#include <linux/kthread.h>
+
+static void backtrace_suppression_test_warn_direct(struct kunit *test)
+{
+ kunit_warning_suppress(test) {
+ WARN(1, "This backtrace should be suppressed");
+ /*
+ * Count must be checked inside the scope; the handle
+ * is not accessible after the block exits.
+ */
+ KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
+ }
+ KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
+}
+
+static void trigger_backtrace_warn(void)
+{
+ WARN(1, "This backtrace should be suppressed");
+}
+
+static void backtrace_suppression_test_warn_indirect(struct kunit *test)
+{
+ kunit_warning_suppress(test) {
+ trigger_backtrace_warn();
+ KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
+ }
+}
+
+static void backtrace_suppression_test_warn_multi(struct kunit *test)
+{
+ kunit_warning_suppress(test) {
+ WARN(1, "This backtrace should be suppressed");
+ trigger_backtrace_warn();
+ KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 2);
+ }
+}
+
+static void backtrace_suppression_test_warn_on_direct(struct kunit *test)
+{
+ if (!IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE) && !IS_ENABLED(CONFIG_KALLSYMS))
+ kunit_skip(test, "requires CONFIG_DEBUG_BUGVERBOSE or CONFIG_KALLSYMS");
+
+ kunit_warning_suppress(test) {
+ WARN_ON(1);
+ KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
+ }
+}
+
+static void trigger_backtrace_warn_on(void)
+{
+ WARN_ON(1);
+}
+
+static void backtrace_suppression_test_warn_on_indirect(struct kunit *test)
+{
+ if (!IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE))
+ kunit_skip(test, "requires CONFIG_DEBUG_BUGVERBOSE");
+
+ kunit_warning_suppress(test) {
+ trigger_backtrace_warn_on();
+ KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
+ }
+}
+
+static void backtrace_suppression_test_count(struct kunit *test)
+{
+ kunit_warning_suppress(test) {
+ KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 0);
+
+ WARN(1, "suppressed");
+ KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
+
+ WARN(1, "suppressed again");
+ KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 2);
+ }
+}
+
+static void backtrace_suppression_test_active_state(struct kunit *test)
+{
+ KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
+
+ kunit_warning_suppress(test) {
+ KUNIT_EXPECT_TRUE(test, kunit_has_active_suppress_warning());
+ }
+
+ KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
+
+ kunit_warning_suppress(test) {
+ KUNIT_EXPECT_TRUE(test, kunit_has_active_suppress_warning());
+ }
+
+ KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
+}
+
+static void backtrace_suppression_test_multi_scope(struct kunit *test)
+{
+ struct kunit_suppressed_warning *sw1, *sw2;
+
+ if (!IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE))
+ kunit_skip(test, "requires CONFIG_DEBUG_BUGVERBOSE");
+
+ sw1 = kunit_start_suppress_warning(test);
+ trigger_backtrace_warn_on();
+ WARN(1, "suppressed by sw1");
+ kunit_end_suppress_warning(test, sw1);
+
+ sw2 = kunit_start_suppress_warning(test);
+ WARN(1, "suppressed by sw2");
+ kunit_end_suppress_warning(test, sw2);
+
+ KUNIT_EXPECT_EQ(test, kunit_suppressed_warning_count(sw1), 2);
+ KUNIT_EXPECT_EQ(test, kunit_suppressed_warning_count(sw2), 1);
+}
+
+struct cross_kthread_data {
+ bool was_active;
+ struct completion done;
+};
+
+static int cross_kthread_fn(void *data)
+{
+ struct cross_kthread_data *d = data;
+
+ d->was_active = kunit_has_active_suppress_warning();
+ complete(&d->done);
+ return 0;
+}
+
+static void backtrace_suppression_test_cross_kthread(struct kunit *test)
+{
+ struct cross_kthread_data data;
+ struct task_struct *task;
+
+ init_completion(&data.done);
+
+ kunit_warning_suppress(test) {
+ task = kthread_run(cross_kthread_fn, &data, "kunit-cross-test");
+ KUNIT_ASSERT_FALSE(test, IS_ERR(task));
+ wait_for_completion(&data.done);
+ }
+
+ KUNIT_EXPECT_FALSE(test, data.was_active);
+}
+
+static struct kunit_case backtrace_suppression_test_cases[] = {
+ KUNIT_CASE(backtrace_suppression_test_warn_direct),
+ KUNIT_CASE(backtrace_suppression_test_warn_indirect),
+ KUNIT_CASE(backtrace_suppression_test_warn_multi),
+ KUNIT_CASE(backtrace_suppression_test_warn_on_direct),
+ KUNIT_CASE(backtrace_suppression_test_warn_on_indirect),
+ KUNIT_CASE(backtrace_suppression_test_count),
+ KUNIT_CASE(backtrace_suppression_test_active_state),
+ KUNIT_CASE(backtrace_suppression_test_multi_scope),
+ KUNIT_CASE(backtrace_suppression_test_cross_kthread),
+ {}
+};
+
+static struct kunit_suite backtrace_suppression_test_suite = {
+ .name = "backtrace-suppression-test",
+ .test_cases = backtrace_suppression_test_cases,
+};
+kunit_test_suites(&backtrace_suppression_test_suite);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("KUnit test to verify warning backtrace suppression");
--
2.53.0
^ permalink raw reply related
* [PATCH v9 3/4] drm: Suppress intentional warning backtraces in scaling unit tests
From: Albert Esteve @ 2026-05-08 15:02 UTC (permalink / raw)
To: Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jonathan Corbet, Shuah Khan, Andrew Morton,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
workflows, linux-riscv, linux-doc, peterz, Guenter Roeck,
Linux Kernel Functional Testing, Maíra Canal,
Alessandro Carminati, Albert Esteve, Dan Carpenter, Simona Vetter
In-Reply-To: <20260508-kunit_add_support-v9-0-99df7aa880f6@redhat.com>
From: Guenter Roeck <linux@roeck-us.net>
The drm_test_rect_calc_hscale and drm_test_rect_calc_vscale unit tests
intentionally trigger warning backtraces by providing bad parameters to
the tested functions. What is tested is the return value, not the existence
of a warning backtrace. Suppress the backtraces to avoid clogging the
kernel log and distraction from real problems. Additionally, the
suppression API allows to actually ensure a warning was triggered,
without parsing any kernel logs and keeping them clean.
Tested-by: Linux Kernel Functional Testing <lkft@linaro.org>
Acked-by: Dan Carpenter <dan.carpenter@linaro.org>
Acked-by: Maíra Canal <mcanal@igalia.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: David Airlie <airlied@gmail.com>
Cc: Daniel Vetter <daniel@ffwll.ch>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Alessandro Carminati <acarmina@redhat.com>
Acked-by: David Gow <david@davidgow.net>
Signed-off-by: Albert Esteve <aesteve@redhat.com>
---
drivers/gpu/drm/tests/drm_rect_test.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_rect_test.c b/drivers/gpu/drm/tests/drm_rect_test.c
index 17e1f34b76101..809e73cb74498 100644
--- a/drivers/gpu/drm/tests/drm_rect_test.c
+++ b/drivers/gpu/drm/tests/drm_rect_test.c
@@ -407,10 +407,20 @@ KUNIT_ARRAY_PARAM(drm_rect_scale, drm_rect_scale_cases, drm_rect_scale_case_desc
static void drm_test_rect_calc_hscale(struct kunit *test)
{
const struct drm_rect_scale_case *params = test->param_value;
+ int expected_warnings = params->expected_scaling_factor == -EINVAL;
int scaling_factor;
- scaling_factor = drm_rect_calc_hscale(¶ms->src, ¶ms->dst,
- params->min_range, params->max_range);
+ /*
+ * drm_rect_calc_hscale() generates a warning backtrace whenever bad
+ * parameters are passed to it. This affects unit tests with -EINVAL
+ * error code in expected_scaling_factor.
+ */
+ kunit_warning_suppress(test) {
+ scaling_factor = drm_rect_calc_hscale(¶ms->src, ¶ms->dst,
+ params->min_range,
+ params->max_range);
+ KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, expected_warnings);
+ }
KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
}
@@ -418,10 +428,19 @@ static void drm_test_rect_calc_hscale(struct kunit *test)
static void drm_test_rect_calc_vscale(struct kunit *test)
{
const struct drm_rect_scale_case *params = test->param_value;
+ int expected_warnings = params->expected_scaling_factor == -EINVAL;
int scaling_factor;
- scaling_factor = drm_rect_calc_vscale(¶ms->src, ¶ms->dst,
- params->min_range, params->max_range);
+ /*
+ * drm_rect_calc_vscale() generates a warning backtrace whenever bad
+ * parameters are passed to it. This affects unit tests with -EINVAL
+ * error code in expected_scaling_factor.
+ */
+ kunit_warning_suppress(test) {
+ scaling_factor = drm_rect_calc_vscale(¶ms->src, ¶ms->dst,
+ params->min_range, params->max_range);
+ KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, expected_warnings);
+ }
KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
}
--
2.53.0
^ permalink raw reply related
* [PATCH v9 4/4] kunit: Add documentation for warning backtrace suppression API
From: Albert Esteve @ 2026-05-08 15:02 UTC (permalink / raw)
To: Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jonathan Corbet, Shuah Khan, Andrew Morton,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
workflows, linux-riscv, linux-doc, peterz, Guenter Roeck,
Linux Kernel Functional Testing, Alessandro Carminati,
Albert Esteve, Dan Carpenter, Kees Cook
In-Reply-To: <20260508-kunit_add_support-v9-0-99df7aa880f6@redhat.com>
From: Guenter Roeck <linux@roeck-us.net>
Document API functions for suppressing warning backtraces.
Tested-by: Linux Kernel Functional Testing <lkft@linaro.org>
Acked-by: Dan Carpenter <dan.carpenter@linaro.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Alessandro Carminati <acarmina@redhat.com>
Reviewed-by: David Gow <david@davidgow.net>
Signed-off-by: Albert Esteve <aesteve@redhat.com>
---
Documentation/dev-tools/kunit/usage.rst | 46 ++++++++++++++++++++++++++++++++-
1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst
index ebd06f5ea4550..1c78dfff94e8a 100644
--- a/Documentation/dev-tools/kunit/usage.rst
+++ b/Documentation/dev-tools/kunit/usage.rst
@@ -157,6 +157,50 @@ Alternatively, one can take full control over the error message by using
if (some_setup_function())
KUNIT_FAIL(test, "Failed to setup thing for testing");
+Suppressing warning backtraces
+------------------------------
+
+Some unit tests trigger warning backtraces either intentionally or as a side
+effect. Such backtraces are normally undesirable since they distract from
+the actual test and may result in the impression that there is a problem.
+
+Backtraces can be suppressed with **task-scoped suppression**: while
+suppression is active on the current task, the backtrace and stack dump from
+``WARN*()``, ``WARN_ON*()``, and related macros on that task are suppressed.
+Two API forms are available.
+
+- Scoped suppression is the simplest form. Wrap the code that triggers
+ warnings in a ``kunit_warning_suppress()`` block:
+
+.. code-block:: c
+
+ static void some_test(struct kunit *test)
+ {
+ kunit_warning_suppress(test) {
+ trigger_backtrace();
+ KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
+ }
+ }
+
+.. note::
+ The warning count must be checked inside the block; the suppression handle
+ is not accessible after the block exits.
+
+- Direct functions return an explicit handle pointer. Use them when the handle
+ needs to be retained or passed across helper functions:
+
+.. code-block:: c
+
+ static void some_test(struct kunit *test)
+ {
+ struct kunit_suppressed_warning *w;
+
+ w = kunit_start_suppress_warning(test);
+ trigger_backtrace();
+ kunit_end_suppress_warning(test, w);
+
+ KUNIT_EXPECT_EQ(test, kunit_suppressed_warning_count(w), 1);
+ }
Test Suites
~~~~~~~~~~~
@@ -1211,4 +1255,4 @@ For example:
dev_managed_string = devm_kstrdup(fake_device, "Hello, World!");
// Everything is cleaned up automatically when the test ends.
- }
\ No newline at end of file
+ }
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox