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.

Reply via email to