On Wed, Mar 18, 2026 at 10:25:00AM +0100, Albert Esteve wrote:
> So back to my test on this. Alessandro detailed two strategies in the
> last version, one of them (storing the function name in `struct
> bug_entry`) was already used and discarded in older iterations of this
> series. So let's focus on the other strategy, using 'kallsyms`. Let's
> assume we still store the function name when registering a new symbol
> to suppress. Otherwise, we might need to check address ranges to
> ensure bugaddr is within the function's scope, which sounds trickier?
> With `kallsyms` we can infer the originating functionid. But this
> approach works unreliably with compiler-induced transformations (e.g.,
> inlining, cloning, code fragmentation). And we still cannot prevent
> all output.
> Additionally, we would need to prevent prints in
> `warn_slowpath_fmt()`. There may be other `printk`s embedded in the
> macros, but let's focus on suppressing all warnings as a best effort.
> It would already improve the quality of life for testers.
warn_slowpath_fmt() should be completely unused on x86, s390 and
possibly others. But sure.
> Considering these remaining issues, I managed to create a centralised
> proposal. Please find the main changes at the bottom of this message.
>
> But again, even with these, the solution remains unreliable. We can
> mitigate this by registering the test name on the suppression list (at
> least, I can make the new test in this series pass with that). Not
> ideal, but we could mention it in the documentation. Something like
> "Suppression is matched by the function where the warning is reported.
> If the warning is triggered from a helper (or the compiler inlines it
> into the test), that function name may differ. In that case, register
> and start suppression for both the test and the helper so the test
> passes regardless of inlining."
>
> Would that be a more acceptable solution? Is there a better option I
> am not seeing?
Yes, definitely. This is the sort of thing I was aiming for.
Other option would be the __FILE__ and __LINE__ data, you can match
uniquely against that and not worry about the compiler transforms.
Perhaps less user friendly as a function identifier, but meh, this isn't
aimed at users anyway, but kernel devs.
The kunit userspace could even scrape the __FILE__ and __LINE__ from the
kernel it was compiled against if it so wants. It should be simple
enough to write a tool that takes the source and a function name and
outputs the relevant __FILE__ and __LINE__ thingies. All you need is a
very rudimentary C parser and we've got a ton of those around.
> diff --git a/kernel/panic.c b/kernel/panic.c
> index c78600212b6c1..3cb004a7803f4 100644
> --- a/kernel/panic.c
> +++ b/kernel/panic.c
> @@ -39,6 +39,7 @@
> #include <linux/sys_info.h>
> #include <trace/events/error_report.h>
> #include <asm/sections.h>
> +#include <kunit/bug.h>
>
> #define PANIC_TIMER_STEP 100
> #define PANIC_BLINK_SPD 18
> @@ -1080,9 +1081,14 @@ void __warn(const char *file, int line, void
> *caller, unsigned taint,
> void warn_slowpath_fmt(const char *file, int line, unsigned taint,
> const char *fmt, ...)
> {
> - bool rcu = warn_rcu_enter();
> + bool rcu;
> struct warn_args args;
>
> + if (__kunit_is_suppressed_warning_at((unsigned
> long)__builtin_return_address(0)))
> + return;
> +
> + rcu = warn_rcu_enter();
> +
> pr_warn(CUT_HERE);
>
> if (!fmt) {
>
> diff --git a/lib/bug.c b/lib/bug.c
> index 623c467a8b76c..e90b038d9225e 100644
> --- a/lib/bug.c
> +++ b/lib/bug.c
> @@ -48,6 +48,7 @@
> #include <linux/rculist.h>
> #include <linux/ftrace.h>
> #include <linux/context_tracking.h>
> +#include <kunit/bug.h>
>
> extern struct bug_entry __start___bug_table[], __stop___bug_table[];
>
> @@ -223,6 +224,9 @@ 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;
>
> + if (warning && __kunit_is_suppressed_warning_at(bugaddr))
> + return BUG_TRAP_TYPE_WARN;
> +
I suppose there's a question here if a suppressed warn counts towards
the once logic below.
> if (warning && once) {
> if (done)
> return BUG_TRAP_TYPE_WARN;
>
> diff --git a/lib/kunit/bug.c b/lib/kunit/bug.c
> index 9c2c4ee013d92..13ffddb044636 100644
> --- a/lib/kunit/bug.c
> +++ b/lib/kunit/bug.c
> @@ -11,6 +11,7 @@
> #include <linux/export.h>
> #include <linux/instrumentation.h>
> #include <linux/jump_label.h>
> +#include <linux/kallsyms.h>
> #include <linux/rculist.h>
> #include <linux/string.h>
>
> @@ -68,4 +69,16 @@ noinstr bool __kunit_is_suppressed_warning(const
> char *function)
> }
> EXPORT_SYMBOL_GPL(__kunit_is_suppressed_warning);
>
> +bool __kunit_is_suppressed_warning_at(unsigned long addr)
> +{
> + char buf[KSYM_SYMBOL_LEN];
> +
> + if (!static_branch_unlikely(&kunit_suppress_warnings_key))
> + return false;
At this point you don't need this to be a static_branch either, both
callers are already in warn slowpaths and nobody cares.
> + if (sprint_symbol_no_offset(buf, addr) <= 0)
> + return false;
> + return __kunit_check_suppress(buf);
> +}
> +EXPORT_SYMBOL_GPL(__kunit_is_suppressed_warning_at);
I don't think you need this export, both callers are definitely
in-kernel.