Maintainer workflows discussions
 help / color / mirror / Atom feed
* 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 v3 1/9] kernel/api: introduce kernel API specification framework
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: <afI1LMB_vNMWYU7o@levanger>

On Wed, Apr 29, 2026 at 06:43:24PM +0200, Nicolas Schier wrote:
> On Fri, Apr 24, 2026 at 12:51:21PM -0400, Sasha Levin wrote:
> > diff --git a/kernel/api/Makefile b/kernel/api/Makefile
> > new file mode 100644
> > index 0000000000000..c0a13fc590e4a
> > --- /dev/null
> > +++ b/kernel/api/Makefile
> > @@ -0,0 +1,14 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +#
> > +# Makefile for the Kernel API Specification Framework
> > +#
> > +
> > +# Core API specification framework
> > +obj-$(CONFIG_KAPI_SPEC)		+= kernel_api_spec.o
>
> Bike-shedding: I'd use 'obj-y' here, to state clearly that
> kernel_api_spec.c is the core part in the kernel/api/ subdir.  If
> CONFIG_KAPI_SPEC is unset, the subfir will not be entered at all.

Agreed, switched to "obj-y" in v4. The subdir gate moves up to
kernel/Makefile and the entry inside kernel/api/Makefile becomes
unconditional. The other two entries (KAPI_SPEC_DEBUGFS,
KAPI_KUNIT_TEST) keep their own conditional guards since they are
optional sub-features.

--
Thanks,
Sasha

^ permalink raw reply

* Re: [PATCH v3 1/9] kernel/api: introduce kernel API specification framework
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: <afIykLLPj7m0fcsX@levanger>

On Wed, Apr 29, 2026 at 06:32:16PM +0200, Nicolas Schier wrote:
> On Sun, Apr 26, 2026 at 11:37:45PM -0400, Nathan Chancellor wrote:
> > On Fri, 24 Apr 2026 12:51:21 -0400, Sasha Levin <sashal@kernel.org> wrote:
> > > diff --git a/kernel/Makefile b/kernel/Makefile
> > > [...]
> > > +obj-$(CONFIG_KAPI_SPEC) += api/
> > > +# Ensure api/ is always cleaned even when CONFIG_KAPI_SPEC is not set
> > > +obj- += api/
> >
> > If $(CONFIG_KAPI_SPEC) is not set, shouldn't
> >
> >   obj-$(CONFIG_KAPI_SPEC) += api/
> >
> > evaluate to
> >
> >   obj- += api/
> >
> > anyways? Why the duplication? This is the only place in the kernel where
> > this would be needed?
>
> yes, this is definitely not needed, as obj- is always evaluated during
> 'make clean', cp. scripts/Makefile.clean [1].
>
> Kind regards
> Nicolas
>
> [1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/scripts/Makefile.clean?h=v7.1-rc1#n30

Thanks for the pointer!

The redundant "obj- += api/" and the accompanying comment are dropped in v4.

--
Thanks,
Sasha

^ permalink raw reply

* Re: [PATCH v3 1/9] kernel/api: introduce kernel API specification framework
From: Sasha Levin @ 2026-05-05  7:45 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: Sasha Levin, Nicolas Schier, 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: <177726106581.2478607.12645653803520391071.b4-review@b4>

On Sun, Apr 26, 2026 at 11:37:45PM -0400, Nathan Chancellor wrote:
> On Fri, 24 Apr 2026 12:51:21 -0400, Sasha Levin <sashal@kernel.org> wrote:
> > diff --git a/kernel/Makefile b/kernel/Makefile
> > index 6785982013dc..564315153643 100644
> > --- a/kernel/Makefile
> > +++ b/kernel/Makefile
> > @@ -59,6 +59,9 @@ obj-y += dma/
> >  obj-y += entry/
> >  obj-y += unwind/
> >  obj-$(CONFIG_MODULES) += module/
> > +obj-$(CONFIG_KAPI_SPEC) += api/
> > +# Ensure api/ is always cleaned even when CONFIG_KAPI_SPEC is not set
> > +obj- += api/
>
> If $(CONFIG_KAPI_SPEC) is not set, shouldn't
>
>   obj-$(CONFIG_KAPI_SPEC) += api/
>
> evaluate to
>
>   obj- += api/
>
> anyways? Why the duplication? This is the only place in the kernel where
> this would be needed?

You are right, the explicit "obj- += api/" is redundant. Nicolas pointed
to scripts/Makefile.clean which already evaluates obj- during
'make clean', so the conditional gate alone is sufficient. Dropped in
v4.

> > diff --git a/kernel/api/.gitignore b/kernel/api/.gitignore
> > new file mode 100644
> > index 000000000000..ca2f632621cf
> > --- /dev/null
> > +++ b/kernel/api/.gitignore
> > @@ -0,0 +1,2 @@
> > +# SPDX-License-Identifier: GPL-2.0-only
> > +/generated_api_specs.c
>
> This appears unused?

Correct, leftover from an earlier prototype that generated a single
combined .c file. Nothing in the current series produces
generated_api_specs.c, so the .gitignore is removed entirely in v4.

> > diff --git a/kernel/api/Kconfig b/kernel/api/Kconfig
> > new file mode 100644
> > index 000000000000..d1072728742a
> > --- /dev/null
> > +++ b/kernel/api/Kconfig
> > @@ -0,0 +1,77 @@
> > +# SPDX-License-Identifier: GPL-2.0-only
> > +#
> > +# Kernel API Specification Framework Configuration
> > +#
> > +
> > +config KAPI_SPEC
> > +	bool "Kernel API Specification Framework"
> > +	default n
>
> I think 'default n' is tautological since 'n' is the default for all
> bool symbols. Consider dropping it on all symbols throughtout this file.

Dropped from KAPI_SPEC, KAPI_RUNTIME_CHECKS, and KAPI_SPEC_DEBUGFS in
v4. KAPI_KUNIT_TEST already uses "default KUNIT_ALL_TESTS" and is left
unchanged.

Thanks for the review!

--
Thanks,
Sasha

^ permalink raw reply

* Re: [PATCH] docs: kselftest: Document the FORCE_TARGETS build variable
From: Shuah Khan @ 2026-05-04 20:58 UTC (permalink / raw)
  To: Ricardo B. Marlière, Shuah Khan, Jonathan Corbet
  Cc: linux-kselftest, workflows, linux-doc, linux-kernel, Shuah Khan
In-Reply-To: <20260417-selftests-docs-v1-1-32e4a78214eb@suse.com>

On 4/17/26 11:36, Ricardo B. Marlière wrote:
> FORCE_TARGETS has been part of the kselftest build system for
> some time but is absent from the developer documentation. Without
> an entry here, users relying on kselftest in CI pipelines would
> have to read the selftests Makefile directly to discover the
> option.
> 
> A build that exits zero despite some targets failing can mask
> real breakage and mislead automated systems into reporting
> success. Add a dedicated section so that CI authors can easily
> find and adopt FORCE_TARGETS=1 to turn such silent partial
> failures into hard errors.
> 
> Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
> ---
>
Thanks Ricardo. I applied it to linux-kselftest next branch.

thanks,
-- Shuah

^ permalink raw reply

* Re: [PATCH v4 00/10] Auto-generate maintainer profile entries
From: Mauro Carvalho Chehab @ 2026-05-04 14:39 UTC (permalink / raw)
  To: Jonathan Corbet
  Cc: Albert Ou, Mauro Carvalho Chehab, Palmer Dabbelt, Paul Walmsley,
	linux-doc, linux-kernel, linux-riscv, workflows, Alexandre Ghiti,
	Shuah Khan, Randy Dunlap, Dan Williams
In-Reply-To: <20260504090041.243520a8@foz.lan>

On Mon, 4 May 2026 09:00:41 +0200
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> On Sun, 03 May 2026 09:49:41 -0600
> Jonathan Corbet <corbet@lwn.net> wrote:
> 
> > Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> > 
> > > Hi Jon,
> > >
> > > This is basically the same patch series I sent during the merge
> > > window, rebased on the top of post 7.1-rc1 docs-next branch.
> > > It is tested both with and without O=DOCS.
> > >
> > > It contains just one extra trivial patch adding a missing SPDX
> > > header, and, on v4, I dropped two patches touching MAINTAINERS,
> > > as those aren't needed anymore.
> > >
> > > This patch series change the way maintainer entry profile links
> > > are added to the documentation. Instead of having an entry for
> > > each of them at an ReST file, get them from MAINTAINERS content.
> > >
> > > That should likely make easier to maintain, as there will be a single
> > > point to place all such profiles.
> > >
> > > The output is a per-subsystem sorted (*) series of links shown as a
> > > list like this:
> > >
> > >     - Arm And Arm64 Soc Sub-Architectures (Common Parts)
> > >     - Arm/Samsung S3C, S5P And Exynos Arm Architectures
> > >     - Arm/Tesla Fsd Soc Support
> > >     ...
> > >     - Xfs Filesystem
> > >
> > > Please notice that the series is doing one logical change per patch.
> > > I could have merged some changes altogether, but I opted doing it
> > > in small steps to help reviews. If you prefer, feel free to merge
> > > maintainers_include changes on merge.
> > >
> > > There is one interesting side effect of this series: there is no
> > > need to add rst files containing profiles inside a TOC tree: Just
> > > creating the file anywhere inside Documentation and adding a P entry
> > > is enough. Adding them to a TOC won't hurt.  
> > 
> > One thing I kind of dislike about these magic mechanisms is that we end
> > up with a single, essentially unsorted list of stuff that readers have
> > to go digging their way through. 

Heh, perhaps you're referring to the TOC tree. You'll see it
unsorted on diffs because the TOC tree there is hidden. As it is
a set, currently it will output a different result on each run.

Not a problem for users, but it makes harder to check differences
after patches, so I'm planning to submit a patch to keep it sorted
just for the sake of doing:

	diff -u before/ after/

Thanks,
Mauro

^ permalink raw reply

* Re: [PATCH v8 3/4] drm: Suppress intentional warning backtraces in scaling unit tests
From: Maxime Ripard @ 2026-05-04 10:03 UTC (permalink / raw)
  To: Albert Esteve
  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-kunit_add_support-v8-3-3e5957cdd235@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 3011 bytes --]

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(&params->src, &params->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(&params->src, &params->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(&params->src, &params->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(&params->src, &params->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?

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]

^ permalink raw reply

* [PATCH v6 11/11] kunit: uapi: Validate usability of /proc
From: Thomas Weißschuh @ 2026-05-04  9:33 UTC (permalink / raw)
  To: Nathan Chancellor, Andrew Morton, Willy Tarreau,
	Thomas Weißschuh, Brendan Higgins, Shuah Khan,
	Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro,
	Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain,
	David Gow, Rae Moar
  Cc: linux-kbuild, linux-kernel, linux-kselftest, kunit-dev, linux-doc,
	workflows, linux-mm, linux-fsdevel, Thomas Weißschuh,
	Christophe Leroy, Nicolas Schier
In-Reply-To: <20260504-kunit-kselftests-v6-0-712d3d526d97@linutronix.de>

Show that the selftests are executed from a fairly "normal"
userspace context.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 MAINTAINERS                 |  1 +
 lib/kunit/Makefile          |  9 ++++++++
 lib/kunit/kunit-test-uapi.c | 51 +++++++++++++++++++++++++++++++++++++++++++++
 lib/kunit/kunit-test.c      | 24 ++++++++++++++++++++-
 4 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 4e8cf9fa7aa9..693aafe4d3f9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14400,6 +14400,7 @@ M:	Thomas Weißschuh <thomas.weissschuh@linutronix.de>
 S:	Maintained
 F:	include/kunit/uapi.h
 F:	lib/kunit/kunit-example-uapi.c
+F:	lib/kunit/kunit-test-uapi.c
 F:	lib/kunit/kunit-uapi.c
 F:	lib/kunit/uapi-preinit.c
 
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 05991d69aa70..1a4af6b66524 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -29,6 +29,15 @@ endif
 obj-$(if $(CONFIG_KUNIT),y) +=		hooks.o
 
 obj-$(CONFIG_KUNIT_TEST) +=		kunit-test.o
+
+userprogs +=				kunit-test-uapi
+kunit-test-uapi-userccflags :=		-static $(NOLIBC_USERCFLAGS)
+
+ifdef CONFIG_KUNIT_UAPI
+CFLAGS_kunit-test.o :=			-Wa,-I$(obj)
+$(obj)/kunit-test.o: $(obj)/kunit-test-uapi
+endif
+
 obj-$(CONFIG_KUNIT_TEST) +=		platform-test.o
 
 # string-stream-test compiles built-in only.
diff --git a/lib/kunit/kunit-test-uapi.c b/lib/kunit/kunit-test-uapi.c
new file mode 100644
index 000000000000..2e75e57865e3
--- /dev/null
+++ b/lib/kunit/kunit-test-uapi.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace selftest.
+ *
+ * Copyright (C) 2026, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
+ *
+ * This is *userspace* code.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "../../tools/testing/selftests/kselftest.h"
+
+static void test_procfs(void)
+{
+	char buf[256];
+	ssize_t r;
+	int fd;
+
+	fd = open("/proc/self/comm", O_RDONLY);
+	if (fd == -1) {
+		ksft_test_result_fail("procfs: open() failed: %s\n", strerror(errno));
+		return;
+	}
+
+	r = read(fd, buf, sizeof(buf));
+	close(fd);
+
+	if (r == -1) {
+		ksft_test_result_fail("procfs: read() failed: %s\n", strerror(errno));
+		return;
+	}
+
+	if (r != 16 || strncmp("kunit-test-uapi\n", buf, 16) != 0) {
+		ksft_test_result_fail("procfs: incorrect comm\n");
+		return;
+	}
+
+	ksft_test_result_pass("procfs\n");
+}
+
+int main(void)
+{
+	ksft_print_header();
+	ksft_set_plan(1);
+	test_procfs();
+	ksft_finished();
+}
diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c
index 126e30879dad..b62e24fb9c55 100644
--- a/lib/kunit/kunit-test.c
+++ b/lib/kunit/kunit-test.c
@@ -9,6 +9,7 @@
 #include <kunit/test.h>
 #include <kunit/test-bug.h>
 #include <kunit/static_stub.h>
+#include <kunit/uapi.h>
 
 #include <linux/device.h>
 #include <kunit/device.h>
@@ -914,10 +915,31 @@ static struct kunit_suite kunit_stub_test_suite = {
 	.test_cases = kunit_stub_test_cases,
 };
 
+static void kunit_uapi_test(struct kunit *test)
+{
+	KUNIT_UAPI_EMBED_BLOB(kunit_test_uapi, "kunit-test-uapi");
+
+	if (IS_ENABLED(CONFIG_KUNIT_UAPI))
+		kunit_uapi_run_kselftest(test, &kunit_test_uapi);
+	else
+		kunit_skip(test, "CONFIG_KUNIT_UAPI is not enabled");
+}
+
+static struct kunit_case kunit_uapi_test_cases[] = {
+	KUNIT_CASE(kunit_uapi_test),
+	{}
+};
+
+static struct kunit_suite kunit_uapi_test_suite = {
+	.name = "kunit_uapi",
+	.test_cases = kunit_uapi_test_cases,
+};
+
 kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite,
 		  &kunit_log_test_suite, &kunit_status_test_suite,
 		  &kunit_current_test_suite, &kunit_device_test_suite,
-		  &kunit_fault_test_suite, &kunit_stub_test_suite);
+		  &kunit_fault_test_suite, &kunit_stub_test_suite,
+		  &kunit_uapi_test_suite);
 
 MODULE_DESCRIPTION("KUnit test for core test infrastructure");
 MODULE_LICENSE("GPL v2");

-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 10/11] kunit: uapi: Introduce preinit executable
From: Thomas Weißschuh @ 2026-05-04  9:33 UTC (permalink / raw)
  To: Nathan Chancellor, Andrew Morton, Willy Tarreau,
	Thomas Weißschuh, Brendan Higgins, Shuah Khan,
	Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro,
	Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain,
	David Gow, Rae Moar
  Cc: linux-kbuild, linux-kernel, linux-kselftest, kunit-dev, linux-doc,
	workflows, linux-mm, linux-fsdevel, Thomas Weißschuh,
	Christophe Leroy, Nicolas Schier
In-Reply-To: <20260504-kunit-kselftests-v6-0-712d3d526d97@linutronix.de>

UAPI selftests may expect a "normal" userspace environment.
For example the normal kernel API pseudo-filesystems should be mounted.
This could be done from kernel code but it is non-idiomatic.

Add a preinit userspace executable which performs these setup steps
before running the final test executable.
This preinit executable is only ever run from the kernel.
Give it access to autoconf.h and kconfig.h to adapt itself to the
tested kernel.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Reviewed-by: David Gow <davidgow@google.com>
---
 MAINTAINERS              |  1 +
 lib/kunit/Makefile       |  5 ++++
 lib/kunit/kunit-uapi.c   | 11 +++++---
 lib/kunit/uapi-preinit.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 82 insertions(+), 3 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index b7358d89df70..4e8cf9fa7aa9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14401,6 +14401,7 @@ S:	Maintained
 F:	include/kunit/uapi.h
 F:	lib/kunit/kunit-example-uapi.c
 F:	lib/kunit/kunit-uapi.c
+F:	lib/kunit/uapi-preinit.c
 
 KVM PARAVIRT (KVM/paravirt)
 M:	Paolo Bonzini <pbonzini@redhat.com>
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 2434470e9985..05991d69aa70 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -14,8 +14,13 @@ kunit-objs +=				test.o \
 					device.o \
 					platform.o
 
+userprogs +=				uapi-preinit
+uapi-preinit-userccflags +=		-static $(NOLIBC_USERCFLAGS)
 obj-$(CONFIG_KUNIT_UAPI) +=		kunit-uapi.o
 
+CFLAGS_kunit-uapi.o :=			-Wa,-I$(obj)
+$(obj)/kunit-uapi.o: $(obj)/uapi-preinit
+
 ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
 kunit-objs +=				debugfs.o
 endif
diff --git a/lib/kunit/kunit-uapi.c b/lib/kunit/kunit-uapi.c
index 7f0309a827a5..702d26878ccd 100644
--- a/lib/kunit/kunit-uapi.c
+++ b/lib/kunit/kunit-uapi.c
@@ -33,6 +33,8 @@ enum {
 	KSFT_SKIP	= 4,
 };
 
+KUNIT_UAPI_EMBED_BLOB(kunit_uapi_preinit, "uapi-preinit");
+
 static struct vfsmount *kunit_uapi_mount_fs(const char *name)
 {
 	struct file_system_type *type;
@@ -158,18 +160,17 @@ static int kunit_uapi_run_executable_in_mount(struct kunit *test,
 					      const struct kunit_uapi_blob *executable,
 					      struct vfsmount *mnt)
 {
-	const char *executable_target = kunit_uapi_executable_target(executable);
 	struct kunit_uapi_usermodehelper_ctx ctx = {
 		.test	= test,
 		.mnt	= mnt,
 	};
 	struct subprocess_info *info;
 	const char *const argv[] = {
-		executable_target,
+		kunit_uapi_executable_target(executable),
 		NULL
 	};
 
-	info = call_usermodehelper_setup(AT_FDCWD, executable_target, (char **)argv, NULL,
+	info = call_usermodehelper_setup(AT_FDCWD, kunit_uapi_preinit.path, (char **)argv, NULL,
 					 GFP_KERNEL, kunit_uapi_usermodehelper_init, NULL, &ctx);
 	if (!info)
 		return -ENOMEM;
@@ -192,6 +193,10 @@ static int kunit_uapi_run_executable(struct kunit *test, const struct kunit_uapi
 	if (err)
 		return err;
 
+	err = kunit_uapi_write_executable(mnt, &kunit_uapi_preinit);
+	if (err)
+		return err;
+
 	err = kunit_uapi_run_executable_in_mount(test, executable, mnt);
 	if (err)
 		return err;
diff --git a/lib/kunit/uapi-preinit.c b/lib/kunit/uapi-preinit.c
new file mode 100644
index 000000000000..686737ea3c76
--- /dev/null
+++ b/lib/kunit/uapi-preinit.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace environment setup.
+ *
+ * Copyright (C) 2026, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
+ *
+ * This is *userspace* code.
+ */
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include "../../tools/testing/selftests/kselftest.h"
+
+#define KUNIT_UAPI_CHDIR_FD 3
+
+static int setup_api_mount(const char *target, const char *fstype)
+{
+	int ret;
+
+	ret = mkdir(target, 0755);
+	if (ret && errno != EEXIST)
+		return -errno;
+
+	ret = mount("none", target, fstype, 0, NULL);
+	if (ret && errno != EBUSY)
+		return -errno;
+
+	return 0;
+}
+
+static void exit_failure(const char *stage, int err)
+{
+	/* If preinit fails synthesize a failed test report. */
+	ksft_print_header();
+	ksft_set_plan(1);
+	ksft_test_result_fail("Failed during test setup: %s: %s\n", stage, strerror(-err));
+	ksft_finished();
+}
+
+int main(int argc, char **argv, char **envp)
+{
+	int ret;
+
+	ret = fchdir(KUNIT_UAPI_CHDIR_FD);
+	close(KUNIT_UAPI_CHDIR_FD);
+	if (ret)
+		exit_failure("fchdir", ret);
+
+	ret = setup_api_mount("/proc", "proc");
+	if (ret)
+		exit_failure("mount /proc", ret);
+
+	ret = setup_api_mount("/sys", "sysfs");
+	if (ret)
+		exit_failure("mount /sys", ret);
+
+	ret = setup_api_mount("/dev", "devtmpfs");
+	if (ret)
+		exit_failure("mount /dev", ret);
+
+	ret = execve(argv[0], argv, envp);
+	if (ret)
+		exit_failure("execve", ret);
+
+	return 0;
+}

-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 09/11] kunit: uapi: Add example for UAPI tests
From: Thomas Weißschuh @ 2026-05-04  9:33 UTC (permalink / raw)
  To: Nathan Chancellor, Andrew Morton, Willy Tarreau,
	Thomas Weißschuh, Brendan Higgins, Shuah Khan,
	Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro,
	Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain,
	David Gow, Rae Moar
  Cc: linux-kbuild, linux-kernel, linux-kselftest, kunit-dev, linux-doc,
	workflows, linux-mm, linux-fsdevel, Thomas Weißschuh,
	Christophe Leroy, Nicolas Schier
In-Reply-To: <20260504-kunit-kselftests-v6-0-712d3d526d97@linutronix.de>

Extend the example to show how to run a userspace executable.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Reviewed-by: David Gow <davidgow@google.com>
---
 MAINTAINERS                    |  1 +
 lib/kunit/Makefile             | 10 ++++++++++
 lib/kunit/kunit-example-test.c | 15 +++++++++++++++
 lib/kunit/kunit-example-uapi.c | 22 ++++++++++++++++++++++
 4 files changed, 48 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index e29ca56f7334..b7358d89df70 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14399,6 +14399,7 @@ KUNIT UAPI TESTING FRAMEWORK (in addition to KERNEL UNIT TESTING FRAMEWORK)
 M:	Thomas Weißschuh <thomas.weissschuh@linutronix.de>
 S:	Maintained
 F:	include/kunit/uapi.h
+F:	lib/kunit/kunit-example-uapi.c
 F:	lib/kunit/kunit-uapi.c
 
 KVM PARAVIRT (KVM/paravirt)
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 6059621a2d32..2434470e9985 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -1,3 +1,5 @@
+include $(srctree)/init/Makefile.nolibc
+
 obj-$(CONFIG_KUNIT) +=			kunit.o
 
 kunit-objs +=				test.o \
@@ -31,3 +33,11 @@ obj-$(CONFIG_KUNIT_TEST) +=		assert_test.o
 endif
 
 obj-$(CONFIG_KUNIT_EXAMPLE_TEST) +=	kunit-example-test.o
+
+userprogs +=				kunit-example-uapi
+kunit-example-uapi-userccflags :=	-static $(NOLIBC_USERCFLAGS)
+
+ifdef CONFIG_KUNIT_UAPI
+CFLAGS_kunit-example-test.o :=		-Wa,-I$(obj)
+$(obj)/kunit-example-test.o: $(obj)/kunit-example-uapi
+endif
diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c
index 0bae7b7ca0b0..febabc995405 100644
--- a/lib/kunit/kunit-example-test.c
+++ b/lib/kunit/kunit-example-test.c
@@ -8,6 +8,7 @@
 
 #include <kunit/test.h>
 #include <kunit/static_stub.h>
+#include <kunit/uapi.h>
 
 /*
  * This is the most fundamental element of KUnit, the test case. A test case
@@ -489,6 +490,19 @@ static void example_params_test_with_init_dynamic_arr(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, param_val - param_val, 0);
 }
 
+/*
+ * This test shows the usage of UAPI tests.
+ */
+static void example_uapi_test(struct kunit *test)
+{
+	KUNIT_UAPI_EMBED_BLOB(kunit_example_uapi, "kunit-example-uapi");
+
+	if (IS_ENABLED(CONFIG_KUNIT_UAPI))
+		kunit_uapi_run_kselftest(test, &kunit_example_uapi);
+	else
+		kunit_skip(test, "CONFIG_KUNIT_UAPI is not enabled");
+}
+
 /*
  * Here we make a list of all the test cases we want to add to the test suite
  * below.
@@ -514,6 +528,7 @@ static struct kunit_case example_test_cases[] = {
 				   kunit_array_gen_params, example_param_init_dynamic_arr,
 				   example_param_exit_dynamic_arr),
 	KUNIT_CASE_SLOW(example_slow_test),
+	KUNIT_CASE(example_uapi_test),
 	{}
 };
 
diff --git a/lib/kunit/kunit-example-uapi.c b/lib/kunit/kunit-example-uapi.c
new file mode 100644
index 000000000000..5875b0d680d4
--- /dev/null
+++ b/lib/kunit/kunit-example-uapi.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace example test.
+ *
+ * Copyright (C) 2026, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
+ *
+ * This is *userspace* code.
+ */
+
+#include "../../tools/testing/selftests/kselftest.h"
+
+int main(void)
+{
+	ksft_print_header();
+	ksft_set_plan(4);
+	ksft_test_result_pass("userspace test 1\n");
+	ksft_test_result_pass("userspace test 2\n");
+	ksft_test_result_skip("userspace test 3: some reason\n");
+	ksft_test_result_pass("userspace test 4\n");
+	ksft_finished();
+}

-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 07/11] kunit: Introduce UAPI testing framework
From: Thomas Weißschuh @ 2026-05-04  9:33 UTC (permalink / raw)
  To: Nathan Chancellor, Andrew Morton, Willy Tarreau,
	Thomas Weißschuh, Brendan Higgins, Shuah Khan,
	Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro,
	Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain,
	David Gow, Rae Moar
  Cc: linux-kbuild, linux-kernel, linux-kselftest, kunit-dev, linux-doc,
	workflows, linux-mm, linux-fsdevel, Thomas Weißschuh,
	Christophe Leroy, Nicolas Schier
In-Reply-To: <20260504-kunit-kselftests-v6-0-712d3d526d97@linutronix.de>

Enable running UAPI tests as part of kunit.
The selftests are embedded into the kernel image and their output is
forwarded to kunit for unified reporting.

The implementation reuses parts of usermode drivers and usermode
helpers. However these frameworks are not used directly as they make it
impossible to retrieve a thread's exit code.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 Documentation/dev-tools/kunit/api/index.rst |   5 +
 Documentation/dev-tools/kunit/api/uapi.rst  |  14 ++
 MAINTAINERS                                 |   6 +
 include/kunit/uapi.h                        |  77 +++++++++++
 lib/kunit/Kconfig                           |  16 +++
 lib/kunit/Makefile                          |   2 +
 lib/kunit/kunit-uapi.c                      | 193 ++++++++++++++++++++++++++++
 7 files changed, 313 insertions(+)

diff --git a/Documentation/dev-tools/kunit/api/index.rst b/Documentation/dev-tools/kunit/api/index.rst
index 5cdb552a0808..34d8fee9a970 100644
--- a/Documentation/dev-tools/kunit/api/index.rst
+++ b/Documentation/dev-tools/kunit/api/index.rst
@@ -9,6 +9,7 @@ API Reference
 	test
 	resource
 	functionredirection
+	uapi
 	clk
 	of
 	platformdevice
@@ -32,6 +33,10 @@ Documentation/dev-tools/kunit/api/functionredirection.rst
 
  - Documents the KUnit Function Redirection API
 
+Documentation/dev-tools/kunit/api/uapi.rst
+
+ - Documents the KUnit Userspace testing API
+
 Driver KUnit API
 ================
 
diff --git a/Documentation/dev-tools/kunit/api/uapi.rst b/Documentation/dev-tools/kunit/api/uapi.rst
new file mode 100644
index 000000000000..1f01b5c6c9db
--- /dev/null
+++ b/Documentation/dev-tools/kunit/api/uapi.rst
@@ -0,0 +1,14 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==================
+Userspace Test API
+==================
+
+This file documents all of the userspace testing API.
+Userspace tests are built as :ref:`kbuild userprogs <kbuild_userprogs>`,
+linked statically and without any external dependencies.
+
+For the widest platform compatibility they should use nolibc, as provided by `init/Makefile.nolibc`.
+
+.. kernel-doc:: include/kunit/uapi.h
+   :internal:
diff --git a/MAINTAINERS b/MAINTAINERS
index be4f6242b3fc..e29ca56f7334 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14395,6 +14395,12 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/leds/backlight/kinetic,ktz8866.yaml
 F:	drivers/video/backlight/ktz8866.c
 
+KUNIT UAPI TESTING FRAMEWORK (in addition to KERNEL UNIT TESTING FRAMEWORK)
+M:	Thomas Weißschuh <thomas.weissschuh@linutronix.de>
+S:	Maintained
+F:	include/kunit/uapi.h
+F:	lib/kunit/kunit-uapi.c
+
 KVM PARAVIRT (KVM/paravirt)
 M:	Paolo Bonzini <pbonzini@redhat.com>
 R:	Vitaly Kuznetsov <vkuznets@redhat.com>
diff --git a/include/kunit/uapi.h b/include/kunit/uapi.h
new file mode 100644
index 000000000000..1e0585355124
--- /dev/null
+++ b/include/kunit/uapi.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * KUnit Userspace testing API.
+ *
+ * Copyright (C) 2026, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
+ */
+
+#ifndef _KUNIT_UAPI_H
+#define _KUNIT_UAPI_H
+
+#include <linux/types.h>
+
+struct kunit;
+
+/**
+ * struct kunit_uapi_blob - Blob embedded build artifact
+ * @path: Path of the embedded artifact.
+ * @data: Start of the embedded data in memory.
+ * @end: End of the embedded data in memory.
+ */
+struct kunit_uapi_blob {
+	const char *const path;
+	const u8 *data;
+	const u8 *end;
+};
+
+#if IS_ENABLED(CONFIG_KUNIT_UAPI)
+
+/**
+ * KUNIT_UAPI_EMBED_BLOB() - Embed another build artifact into the kernel
+ * @_name: The name of symbol under which the artifact is embedded.
+ * @_path: Path to the artifact on disk.
+ *
+ * Embeds a build artifact like a userspace executable into the kernel or current module.
+ * The build artifact is read from disk and needs to be already built.
+ */
+#define KUNIT_UAPI_EMBED_BLOB(_name, _path)					\
+	asm (									\
+	"	.pushsection .rodata, \"a\"				\n"	\
+	"	.global " __stringify(CONCATENATE(_name, _data)) "	\n"	\
+	__stringify(CONCATENATE(_name, _data)) ":			\n"	\
+	"	.incbin " __stringify(_path) "				\n"	\
+	"	.size " __stringify(CONCATENATE(_name, _data)) ", "		\
+			". - " __stringify(CONCATENATE(_name, _data)) "	\n"	\
+	"	.global " __stringify(CONCATENATE(_name, _end)) "	\n"	\
+	__stringify(CONCATENATE(_name, _end)) ":			\n"	\
+	"	.popsection						\n"	\
+	);									\
+										\
+	extern const char CONCATENATE(_name, _data)[];				\
+	extern const char CONCATENATE(_name, _end)[];				\
+										\
+	static const struct kunit_uapi_blob _name = {				\
+		.path	= _path,						\
+		.data	= CONCATENATE(_name, _data),				\
+		.end	= CONCATENATE(_name, _end),				\
+	}									\
+
+#else /* !CONFIG_KUNIT_UAPI */
+
+/* Unresolved external reference, to be optimized away */
+#define KUNIT_UAPI_EMBED_BLOB(_name, _path)					\
+	extern const struct kunit_uapi_blob _name
+
+#endif /* CONFIG_KUNIT_UAPI */
+
+/**
+ * kunit_uapi_run_kselftest() - Run a userspace kselftest as part of kunit
+ * @test: The test context object.
+ * @executable: kselftest executable to run
+ *
+ * Runs the kselftest and forwards its TAP output and exit status to kunit.
+ */
+void kunit_uapi_run_kselftest(struct kunit *test, const struct kunit_uapi_blob *executable);
+
+#endif /* _KUNIT_UAPI_H */
diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig
index 498cc51e493d..f3dc9fac811a 100644
--- a/lib/kunit/Kconfig
+++ b/lib/kunit/Kconfig
@@ -141,4 +141,20 @@ config KUNIT_UML_PCI
 
 	  If unsure, say N.
 
+config KUNIT_UAPI
+	tristate "KUnit UAPI testing framework"
+	depends on KUNIT
+	depends on ARCH_HAS_NOLIBC
+	depends on !STATIC_USERMODEHELPER
+	depends on !LTO_CLANG # https://github.com/llvm/llvm-project/issues/112920
+	select HEADERS_INSTALL
+	select DEVTMPFS
+	default KUNIT
+	help
+	  Enables support for building and running userspace selftests as part of kunit.
+	  These tests should be statically linked and use kselftest.h or kselftest_harness.h
+	  for status reporting.
+
+	  In most cases this should be left as its default.
+
 endif # KUNIT
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 656f1fa35abc..6059621a2d32 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -12,6 +12,8 @@ kunit-objs +=				test.o \
 					device.o \
 					platform.o
 
+obj-$(CONFIG_KUNIT_UAPI) +=		kunit-uapi.o
+
 ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
 kunit-objs +=				debugfs.o
 endif
diff --git a/lib/kunit/kunit-uapi.c b/lib/kunit/kunit-uapi.c
new file mode 100644
index 000000000000..485b79fd193d
--- /dev/null
+++ b/lib/kunit/kunit-uapi.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace testing API.
+ *
+ * Copyright (C) 2026, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
+ */
+
+#include <linux/binfmts.h>
+#include <linux/export.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/fs_struct.h>
+#include <linux/pid.h>
+#include <linux/pipe_fs_i.h>
+#include <linux/sched/task.h>
+#include <linux/seq_buf.h>
+#include <linux/types.h>
+#include <linux/umh.h>
+
+#include <kunit/test-bug.h>
+#include <kunit/test.h>
+#include <kunit/uapi.h>
+
+enum {
+	KSFT_PASS	= 0,
+	KSFT_FAIL	= 1,
+	KSFT_XFAIL	= 2,
+	KSFT_XPASS	= 3,
+	KSFT_SKIP	= 4,
+};
+
+static struct vfsmount *kunit_uapi_mount_fs(const char *name)
+{
+	struct file_system_type *type;
+
+	type = get_fs_type(name);
+	if (!type)
+		return ERR_PTR(-ENODEV);
+
+	return kern_mount(type);
+}
+
+static int kunit_uapi_write_file(struct vfsmount *mnt, const char *name, mode_t mode,
+				 const u8 *data, size_t size)
+{
+	struct file *file;
+	ssize_t written;
+
+	file = file_open_root_mnt(mnt, name, O_CREAT | O_WRONLY, mode);
+	if (IS_ERR(file))
+		return PTR_ERR(file);
+
+	written = kernel_write(file, data, size, NULL);
+	filp_close(file, NULL);
+	if (written != size) {
+		if (written >= 0)
+			return -ENOMEM;
+		return written;
+	}
+
+	return 0;
+}
+
+static const char *kunit_uapi_executable_target(const struct kunit_uapi_blob *executable)
+{
+	return kbasename(executable->path);
+}
+
+static int kunit_uapi_write_executable(struct vfsmount *mnt,
+				       const struct kunit_uapi_blob *executable)
+{
+	return kunit_uapi_write_file(mnt, kunit_uapi_executable_target(executable), 0755,
+				     executable->data, executable->end - executable->data);
+}
+
+struct kunit_uapi_usermodehelper_ctx {
+	struct vfsmount *mnt;
+	struct kunit *test;
+};
+
+static int kunit_uapi_get_cwd(struct vfsmount *mnt)
+{
+	CLASS(get_unused_fd, fd)(O_RDONLY);
+	if (fd < 0)
+		return fd;
+
+	struct file *file __free(fput) = file_open_root_mnt(mnt, "/", O_DIRECTORY, 0);
+	if (IS_ERR(file))
+		return PTR_ERR(file);
+
+	fd_install(fd, no_free_ptr(file));
+
+	return take_fd(fd);
+}
+
+static int kunit_uapi_usermodehelper_init(struct subprocess_info *info, struct cred *new)
+{
+	struct kunit_uapi_usermodehelper_ctx *ctx = info->data;
+	int dirfd;
+
+	dirfd = kunit_uapi_get_cwd(ctx->mnt);
+	if (dirfd < 0)
+		return dirfd;
+
+	kernel_sigaction(SIGKILL, SIG_DFL);
+	kernel_sigaction(SIGABRT, SIG_DFL);
+
+	current->kunit_test = ctx->test;
+
+	info->dirfd = dirfd;
+
+	return 0;
+}
+
+static int kunit_uapi_run_executable_in_mount(struct kunit *test,
+					      const struct kunit_uapi_blob *executable,
+					      struct vfsmount *mnt)
+{
+	const char *executable_target = kunit_uapi_executable_target(executable);
+	struct kunit_uapi_usermodehelper_ctx ctx = {
+		.test	= test,
+		.mnt	= mnt,
+	};
+	struct subprocess_info *info;
+	const char *const argv[] = {
+		executable_target,
+		NULL
+	};
+
+	info = call_usermodehelper_setup(AT_FDCWD, executable_target, (char **)argv, NULL,
+					 GFP_KERNEL, kunit_uapi_usermodehelper_init, NULL, &ctx);
+	if (!info)
+		return -ENOMEM;
+
+	/* Flush delayed fput so exec can open the file read-only */
+	flush_delayed_fput();
+
+	return call_usermodehelper_exec(info, UMH_WAIT_PROC);
+}
+
+static int kunit_uapi_run_executable(struct kunit *test, const struct kunit_uapi_blob *executable)
+{
+	int err;
+
+	struct vfsmount *mnt __free(kern_unmount) = kunit_uapi_mount_fs("ramfs");
+	if (IS_ERR(mnt))
+		return PTR_ERR(mnt);
+
+	err = kunit_uapi_write_executable(mnt, executable);
+	if (err)
+		return err;
+
+	err = kunit_uapi_run_executable_in_mount(test, executable, mnt);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+void kunit_uapi_run_kselftest(struct kunit *test, const struct kunit_uapi_blob *executable)
+{
+	u8 exit_code, exit_signal;
+	int err;
+
+	err = kunit_uapi_run_executable(test, executable);
+	if (err < 0)
+		KUNIT_FAIL_AND_ABORT(test, "Could not run test executable: %pe\n", ERR_PTR(err));
+
+	exit_code = err >> 8;
+	exit_signal = err & 0xff;
+
+	if (exit_signal)
+		KUNIT_FAIL_AND_ABORT(test, "kselftest exited with signal: %d\n", exit_signal);
+	else if (exit_code == KSFT_PASS)
+		; /* Noop */
+	else if (exit_code == KSFT_FAIL)
+		KUNIT_FAIL_AND_ABORT(test, "kselftest exited with code KSFT_FAIL\n");
+	else if (exit_code == KSFT_XPASS)
+		KUNIT_FAIL_AND_ABORT(test, "kselftest exited with code KSFT_XPASS\n");
+	else if (exit_code == KSFT_XFAIL)
+		; /* Noop */
+	else if (exit_code == KSFT_SKIP)
+		kunit_mark_skipped(test, "kselftest exited with code KSFT_SKIP\n");
+	else
+		KUNIT_FAIL_AND_ABORT(test, "kselftest exited with unknown exit code: %d\n",
+				     exit_code);
+}
+EXPORT_SYMBOL_GPL(kunit_uapi_run_kselftest);
+
+MODULE_DESCRIPTION("KUnit UAPI testing framework");
+MODULE_AUTHOR("Thomas Weißschuh <thomas.weissschuh@linutronix.de");
+MODULE_LICENSE("GPL");

-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 08/11] kunit: uapi: Forward test executable output to KUnit log
From: Thomas Weißschuh @ 2026-05-04  9:33 UTC (permalink / raw)
  To: Nathan Chancellor, Andrew Morton, Willy Tarreau,
	Thomas Weißschuh, Brendan Higgins, Shuah Khan,
	Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro,
	Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain,
	David Gow, Rae Moar
  Cc: linux-kbuild, linux-kernel, linux-kselftest, kunit-dev, linux-doc,
	workflows, linux-mm, linux-fsdevel, Thomas Weißschuh,
	Christophe Leroy, Nicolas Schier
In-Reply-To: <20260504-kunit-kselftests-v6-0-712d3d526d97@linutronix.de>

The output of the test executable should be grouped together with the
regular KUnit output and also be available in debugfs.
Install a custom miscdevice as stdout and stderr which forwards the
written data to the KUnit log.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 lib/kunit/kunit-uapi.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 154 insertions(+), 1 deletion(-)

diff --git a/lib/kunit/kunit-uapi.c b/lib/kunit/kunit-uapi.c
index 485b79fd193d..7f0309a827a5 100644
--- a/lib/kunit/kunit-uapi.c
+++ b/lib/kunit/kunit-uapi.c
@@ -11,6 +11,7 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/fs_struct.h>
+#include <linux/miscdevice.h>
 #include <linux/pid.h>
 #include <linux/pipe_fs_i.h>
 #include <linux/sched/task.h>
@@ -22,6 +23,8 @@
 #include <kunit/test.h>
 #include <kunit/uapi.h>
 
+#define KUNIT_LOG_DEVICE "kunit-log"
+
 enum {
 	KSFT_PASS	= 0,
 	KSFT_FAIL	= 1,
@@ -94,10 +97,48 @@ static int kunit_uapi_get_cwd(struct vfsmount *mnt)
 	return take_fd(fd);
 }
 
+static int kunit_uapi_open_standard_streams(void)
+{
+	struct vfsmount *devtmpfs __free(kern_unmount) = kunit_uapi_mount_fs("devtmpfs");
+	if (IS_ERR(devtmpfs))
+		return PTR_ERR(devtmpfs);
+
+	CLASS(get_unused_fd, stdin_fd)(O_RDONLY);
+	if (stdin_fd < 0)
+		return stdin_fd;
+
+	CLASS(get_unused_fd, stdout_fd)(O_WRONLY);
+	if (stdout_fd < 0)
+		return stdout_fd;
+
+	CLASS(get_unused_fd, stderr_fd)(O_WRONLY);
+	if (stderr_fd < 0)
+		return stderr_fd;
+
+	struct file *logfile __free(fput) = file_open_root_mnt(devtmpfs, KUNIT_LOG_DEVICE,
+							       O_RDWR, 0);
+	if (IS_ERR(logfile))
+		return PTR_ERR(logfile);
+
+	fd_install(stdin_fd, no_free_ptr(logfile));
+	fd_install(stdout_fd, fget(stdin_fd));
+	fd_install(stderr_fd, fget(stdin_fd));
+
+	take_fd(stdin_fd);
+	take_fd(stdout_fd);
+	take_fd(stderr_fd);
+
+	return 0;
+}
+
 static int kunit_uapi_usermodehelper_init(struct subprocess_info *info, struct cred *new)
 {
 	struct kunit_uapi_usermodehelper_ctx *ctx = info->data;
-	int dirfd;
+	int ret, dirfd;
+
+	ret = kunit_uapi_open_standard_streams();
+	if (ret)
+		return ret;
 
 	dirfd = kunit_uapi_get_cwd(ctx->mnt);
 	if (dirfd < 0)
@@ -188,6 +229,118 @@ void kunit_uapi_run_kselftest(struct kunit *test, const struct kunit_uapi_blob *
 }
 EXPORT_SYMBOL_GPL(kunit_uapi_run_kselftest);
 
+struct kunit_uapi_log_private {
+	struct mutex mutex;
+	struct seq_buf buf;
+	char data[4096];
+};
+
+static int kunit_uapi_log_open(struct inode *ino, struct file *file)
+{
+	struct kunit_uapi_log_private *priv;
+
+	priv = kmalloc_obj(*priv);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->mutex);
+	seq_buf_init(&priv->buf, priv->data, sizeof(priv->data));
+
+	file->private_data = priv;
+
+	return 0;
+}
+
+static void kunit_uapi_log_str(struct kunit *test, const char *str, size_t len)
+{
+	kunit_log(KERN_INFO, test, KUNIT_SUBSUBTEST_INDENT "%.*s", (int)len, str);
+}
+
+static void kunit_uapi_print_buf_to_log(struct kunit *test, struct seq_buf *s)
+{
+	const char *start, *lf;
+
+	if (s->size == 0 || s->len == 0)
+		return;
+
+	start = seq_buf_str(s);
+	while ((lf = strchr(start, '\n'))) {
+		kunit_uapi_log_str(test, start, lf - start + 1);
+		start = ++lf;
+	}
+
+	/* Remove printed data from buffer */
+	memmove(s->buffer, start, start - s->buffer);
+	s->len -= start - s->buffer;
+}
+
+static ssize_t kunit_uapi_log_write(struct file *file, const char __user *ubuf, size_t count,
+				    loff_t *off)
+{
+	struct kunit_uapi_log_private *priv = file->private_data;
+	struct seq_buf *buf = &priv->buf;
+	struct kunit *test;
+
+	test = kunit_get_current_test();
+	if (!test)
+		return -ENODEV;
+
+	guard(mutex)(&priv->mutex);
+
+	if (seq_buf_has_overflowed(buf))
+		return -E2BIG;
+
+	if (buf->size < buf->len + count) {
+		seq_buf_set_overflow(buf);
+		kunit_warn(test, "KUnit UAPI line buffer has overflowed\n");
+		return -E2BIG;
+	}
+
+	if (copy_from_user(buf->buffer + buf->len, ubuf, count))
+		return -EFAULT;
+
+	buf->len += count;
+
+	kunit_uapi_print_buf_to_log(test, &priv->buf);
+
+	return count;
+}
+
+static int kunit_uapi_log_release(struct inode *ino, struct file *file)
+{
+	struct kunit_uapi_log_private *priv = file->private_data;
+	struct kunit *test;
+
+	mutex_destroy(&priv->mutex);
+
+	test = kunit_get_current_test();
+	if (!test) {
+		kfree(priv);
+		return -ENODEV;
+	}
+
+	/* Flush last partial line */
+	kunit_uapi_log_str(test, priv->buf.buffer, priv->buf.len);
+	kunit_uapi_log_str(test, "\n", 1);
+
+	kfree(priv);
+	return 0;
+}
+
+static const struct file_operations kunit_uapi_log_fops = {
+	.owner		= THIS_MODULE,
+	.open		= kunit_uapi_log_open,
+	.release	= kunit_uapi_log_release,
+	.write		= kunit_uapi_log_write,
+};
+
+static struct miscdevice kunit_uapi_log = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= KUNIT_LOG_DEVICE,
+	.fops	= &kunit_uapi_log_fops,
+};
+module_misc_device(kunit_uapi_log);
+
 MODULE_DESCRIPTION("KUnit UAPI testing framework");
 MODULE_AUTHOR("Thomas Weißschuh <thomas.weissschuh@linutronix.de");
 MODULE_LICENSE("GPL");

-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 06/11] kunit: qemu_configs: loongarch: Enable LSX/LSAX
From: Thomas Weißschuh @ 2026-05-04  9:33 UTC (permalink / raw)
  To: Nathan Chancellor, Andrew Morton, Willy Tarreau,
	Thomas Weißschuh, Brendan Higgins, Shuah Khan,
	Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro,
	Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain,
	David Gow, Rae Moar
  Cc: linux-kbuild, linux-kernel, linux-kselftest, kunit-dev, linux-doc,
	workflows, linux-mm, linux-fsdevel, Thomas Weißschuh,
	Christophe Leroy, Nicolas Schier
In-Reply-To: <20260504-kunit-kselftests-v6-0-712d3d526d97@linutronix.de>

The upcoming kunit UAPI framework will run userspace executables as part of
kunit. These may use the LSX or LASX instructions.

Make sure the kunit kernel can handle these instructions.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Reviewed-by: David Gow <davidgow@google.com>
---
 tools/testing/kunit/qemu_configs/loongarch.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tools/testing/kunit/qemu_configs/loongarch.py b/tools/testing/kunit/qemu_configs/loongarch.py
index a92422967d1d..1dba755284f1 100644
--- a/tools/testing/kunit/qemu_configs/loongarch.py
+++ b/tools/testing/kunit/qemu_configs/loongarch.py
@@ -11,6 +11,8 @@ CONFIG_PVPANIC_PCI=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_CPU_HAS_LSX=y
+CONFIG_CPU_HAS_LASX=y
 ''',
 			   qemu_arch='loongarch64',
 			   kernel_path='arch/loongarch/boot/vmlinux.elf',

-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 05/11] init: add nolibc build support
From: Thomas Weißschuh @ 2026-05-04  9:33 UTC (permalink / raw)
  To: Nathan Chancellor, Andrew Morton, Willy Tarreau,
	Thomas Weißschuh, Brendan Higgins, Shuah Khan,
	Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro,
	Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain,
	David Gow, Rae Moar
  Cc: linux-kbuild, linux-kernel, linux-kselftest, kunit-dev, linux-doc,
	workflows, linux-mm, linux-fsdevel, Thomas Weißschuh,
	Christophe Leroy, Nicolas Schier
In-Reply-To: <20260504-kunit-kselftests-v6-0-712d3d526d97@linutronix.de>

Building userspace applications through the kbuild "userprogs" framework
requires a libc. Kernel toolchains often do not contain a libc.
In this case it is useful to use the nolibc library from the kernel tree.
Nolibc does not support all architectures and requires compiler flags.

Add a kconfig option, so users can know where it is available and provide a
variable for common options.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Reviewed-by: Nicolas Schier <n.schier@avm.de>
---
 MAINTAINERS          |  2 ++
 init/Kconfig         |  2 ++
 init/Kconfig.nolibc  | 16 ++++++++++++++++
 init/Makefile.nolibc | 13 +++++++++++++
 4 files changed, 33 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd16..be4f6242b3fc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18960,6 +18960,8 @@ M:	Willy Tarreau <w@1wt.eu>
 M:	Thomas Weißschuh <linux@weissschuh.net>
 S:	Maintained
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/nolibc/linux-nolibc.git
+F:	init/Kconfig.nolibc
+F:	init/Makefile.nolibc
 F:	tools/include/nolibc/
 F:	tools/testing/selftests/nolibc/
 
diff --git a/init/Kconfig b/init/Kconfig
index 3bb92a3f6cc1..c37d9227ba72 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -106,6 +106,8 @@ config CC_CAN_LINK
 	default $(cc_can_link_user,$(m64-flag)) if 64BIT
 	default $(cc_can_link_user,$(m32-flag))
 
+source "init/Kconfig.nolibc"
+
 # Fixed in GCC 14, 13.3, 12.4 and 11.5
 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921
 config GCC_ASM_GOTO_OUTPUT_BROKEN
diff --git a/init/Kconfig.nolibc b/init/Kconfig.nolibc
new file mode 100644
index 000000000000..07488ef18f4f
--- /dev/null
+++ b/init/Kconfig.nolibc
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config ARCH_HAS_NOLIBC
+	bool
+	default y if ARM
+	default y if ARM64
+	default y if LOONGARCH
+	default y if M68K
+	default y if MIPS
+	default y if PPC
+	default y if RISCV
+	default y if S390
+	default y if SPARC
+	default y if SUPERH
+	default y if UML_X86
+	default y if X86
diff --git a/init/Makefile.nolibc b/init/Makefile.nolibc
new file mode 100644
index 000000000000..dacc78ab4c81
--- /dev/null
+++ b/init/Makefile.nolibc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+# Compiler flags, which are necessary to build userspace applications with the
+# in-kernel libc "nolibc".
+
+ifeq ($(and $(CONFIG_ARCH_HAS_NOLIBC),$(CONFIG_HEADERS_INSTALL)),y)
+
+NOLIBC_USERCFLAGS := -nostdlib -nostdinc -static -ffreestanding \
+		     -fno-asynchronous-unwind-tables -fno-stack-protector \
+		     -I$(objtree)/usr/include -I$(srctree)/tools/include/nolibc/
+
+NOLIBC_USERLDFLAGS := -nostdlib -nostdinc -static
+
+endif # CONFIG_ARCH_HAS_NOLIBC && CONFIG_HEADERS_INSTALL

-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 04/11] mount: add support for __free(kern_unmount)
From: Thomas Weißschuh @ 2026-05-04  9:33 UTC (permalink / raw)
  To: Nathan Chancellor, Andrew Morton, Willy Tarreau,
	Thomas Weißschuh, Brendan Higgins, Shuah Khan,
	Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro,
	Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain,
	David Gow, Rae Moar
  Cc: linux-kbuild, linux-kernel, linux-kselftest, kunit-dev, linux-doc,
	workflows, linux-mm, linux-fsdevel, Thomas Weißschuh,
	Christophe Leroy, Nicolas Schier
In-Reply-To: <20260504-kunit-kselftests-v6-0-712d3d526d97@linutronix.de>

Allow usage of kern_unmount from the automatic __free cleanup logic.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 include/linux/mount.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/mount.h b/include/linux/mount.h
index acfe7ef86a1b..d8689ce61a42 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -10,6 +10,7 @@
 #ifndef _LINUX_MOUNT_H
 #define _LINUX_MOUNT_H
 
+#include <linux/cleanup.h>
 #include <linux/types.h>
 #include <asm/barrier.h>
 
@@ -99,6 +100,7 @@ extern bool our_mnt(struct vfsmount *mnt);
 
 extern struct vfsmount *kern_mount(struct file_system_type *);
 extern void kern_unmount(struct vfsmount *mnt);
+DEFINE_FREE(kern_unmount, struct vfsmount *, if (_T) kern_unmount(_T));
 extern int may_umount_tree(struct vfsmount *);
 extern int may_umount(struct vfsmount *);
 int do_mount(const char *, const char __user *,

-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 03/11] umh: add dirfd parameter
From: Thomas Weißschuh @ 2026-05-04  9:33 UTC (permalink / raw)
  To: Nathan Chancellor, Andrew Morton, Willy Tarreau,
	Thomas Weißschuh, Brendan Higgins, Shuah Khan,
	Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro,
	Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain,
	David Gow, Rae Moar
  Cc: linux-kbuild, linux-kernel, linux-kselftest, kunit-dev, linux-doc,
	workflows, linux-mm, linux-fsdevel, Thomas Weißschuh,
	Christophe Leroy, Nicolas Schier
In-Reply-To: <20260504-kunit-kselftests-v6-0-712d3d526d97@linutronix.de>

Allow callers to specify the directory against which to resolve the
helper's filename. Enables the running of helpers from private mounts.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 fs/coredump.c               | 2 +-
 include/linux/umh.h         | 3 ++-
 kernel/module/kmod.c        | 2 +-
 kernel/umh.c                | 9 ++++++---
 lib/kobject_uevent.c        | 2 +-
 security/keys/request_key.c | 2 +-
 6 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/fs/coredump.c b/fs/coredump.c
index bb6fdb1f458e..45df2387be3d 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -1015,7 +1015,7 @@ static bool coredump_pipe(struct core_name *cn, struct coredump_params *cprm,
 		helper_argv[argi] = cn->corename + argv[argi];
 	helper_argv[argi] = NULL;
 
-	sub_info = call_usermodehelper_setup(helper_argv[0], helper_argv, NULL,
+	sub_info = call_usermodehelper_setup(AT_FDCWD, helper_argv[0], helper_argv, NULL,
 					     GFP_KERNEL, umh_coredump_setup,
 					     NULL, cprm);
 	if (!sub_info)
diff --git a/include/linux/umh.h b/include/linux/umh.h
index daa6a7048c11..6670b9ff85d4 100644
--- a/include/linux/umh.h
+++ b/include/linux/umh.h
@@ -20,6 +20,7 @@ struct file;
 struct subprocess_info {
 	struct work_struct work;
 	struct completion *complete;
+	int dirfd;
 	const char *path;
 	char **argv;
 	char **envp;
@@ -34,7 +35,7 @@ extern int
 call_usermodehelper(const char *path, char **argv, char **envp, int wait);
 
 extern struct subprocess_info *
-call_usermodehelper_setup(const char *path, char **argv, char **envp,
+call_usermodehelper_setup(int dirfd, const char *path, char **argv, char **envp,
 			  gfp_t gfp_mask,
 			  int (*init)(struct subprocess_info *info, struct cred *new),
 			  void (*cleanup)(struct subprocess_info *), void *data);
diff --git a/kernel/module/kmod.c b/kernel/module/kmod.c
index a25dccdf7aa7..a85c57a707af 100644
--- a/kernel/module/kmod.c
+++ b/kernel/module/kmod.c
@@ -95,7 +95,7 @@ static int call_modprobe(char *orig_module_name, int wait)
 	argv[3] = module_name;	/* check free_modprobe_argv() */
 	argv[4] = NULL;
 
-	info = call_usermodehelper_setup(modprobe_path, argv, envp, GFP_KERNEL,
+	info = call_usermodehelper_setup(AT_FDCWD, modprobe_path, argv, envp, GFP_KERNEL,
 					 NULL, free_modprobe_argv, NULL);
 	if (!info)
 		goto free_module_name;
diff --git a/kernel/umh.c b/kernel/umh.c
index bab134fa8c36..5cdcba6005d9 100644
--- a/kernel/umh.c
+++ b/kernel/umh.c
@@ -106,7 +106,7 @@ static int call_usermodehelper_exec_async(void *data)
 	commit_creds(new);
 
 	wait_for_initramfs();
-	retval = kernel_execve(AT_FDCWD, sub_info->path,
+	retval = kernel_execve(sub_info->dirfd, sub_info->path,
 			       (const char *const *)sub_info->argv,
 			       (const char *const *)sub_info->envp);
 out:
@@ -331,6 +331,7 @@ static void helper_unlock(void)
 
 /**
  * call_usermodehelper_setup - prepare to call a usermode helper
+ * @dirfd: directory to resolve path against
  * @path: path to usermode executable
  * @argv: arg vector for process
  * @envp: environment for process
@@ -352,7 +353,7 @@ static void helper_unlock(void)
  * Function must be runnable in either a process context or the
  * context in which call_usermodehelper_exec is called.
  */
-struct subprocess_info *call_usermodehelper_setup(const char *path, char **argv,
+struct subprocess_info *call_usermodehelper_setup(int dirfd, const char *path, char **argv,
 		char **envp, gfp_t gfp_mask,
 		int (*init)(struct subprocess_info *info, struct cred *new),
 		void (*cleanup)(struct subprocess_info *info),
@@ -366,8 +367,10 @@ struct subprocess_info *call_usermodehelper_setup(const char *path, char **argv,
 	INIT_WORK(&sub_info->work, call_usermodehelper_exec_work);
 
 #ifdef CONFIG_STATIC_USERMODEHELPER
+	sub_info->dirfd = AT_FDCWD;
 	sub_info->path = CONFIG_STATIC_USERMODEHELPER_PATH;
 #else
+	sub_info->dirfd = dirfd;
 	sub_info->path = path;
 #endif
 	sub_info->argv = argv;
@@ -484,7 +487,7 @@ int call_usermodehelper(const char *path, char **argv, char **envp, int wait)
 	struct subprocess_info *info;
 	gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
 
-	info = call_usermodehelper_setup(path, argv, envp, gfp_mask,
+	info = call_usermodehelper_setup(AT_FDCWD, path, argv, envp, gfp_mask,
 					 NULL, NULL, NULL);
 	if (info == NULL)
 		return -ENOMEM;
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index ddbc4d7482d2..426ac83f1d2a 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -628,7 +628,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 			goto exit;
 
 		retval = -ENOMEM;
-		info = call_usermodehelper_setup(env->argv[0], env->argv,
+		info = call_usermodehelper_setup(AT_FDCWD, env->argv[0], env->argv,
 						 env->envp, GFP_KERNEL,
 						 NULL, cleanup_uevent_env, env);
 		if (info) {
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index a7673ad86d18..f6f3d4bc0bda 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -101,7 +101,7 @@ static int call_usermodehelper_keys(const char *path, char **argv, char **envp,
 {
 	struct subprocess_info *info;
 
-	info = call_usermodehelper_setup(path, argv, envp, GFP_KERNEL,
+	info = call_usermodehelper_setup(AT_FDCWD, path, argv, envp, GFP_KERNEL,
 					  umh_keys_init, umh_keys_cleanup,
 					  session_keyring);
 	if (!info)

-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 02/11] exec: add dirfd parameter to kernel_execve()
From: Thomas Weißschuh @ 2026-05-04  9:33 UTC (permalink / raw)
  To: Nathan Chancellor, Andrew Morton, Willy Tarreau,
	Thomas Weißschuh, Brendan Higgins, Shuah Khan,
	Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro,
	Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain,
	David Gow, Rae Moar
  Cc: linux-kbuild, linux-kernel, linux-kselftest, kunit-dev, linux-doc,
	workflows, linux-mm, linux-fsdevel, Thomas Weißschuh,
	Christophe Leroy, Nicolas Schier
In-Reply-To: <20260504-kunit-kselftests-v6-0-712d3d526d97@linutronix.de>

Allow callers to specify the directory against which to resolve the
program filename. Enables running executables from private mounts.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 fs/exec.c               | 4 ++--
 include/linux/binfmts.h | 2 +-
 init/main.c             | 2 +-
 kernel/umh.c            | 2 +-
 4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/fs/exec.c b/fs/exec.c
index ba12b4c466f6..affae4b4f6f6 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1846,7 +1846,7 @@ static int do_execveat_common(int fd, struct filename *filename,
 	return bprm_execve(bprm);
 }
 
-int kernel_execve(const char *kernel_filename,
+int kernel_execve(int dirfd, const char *kernel_filename,
 		  const char *const *argv, const char *const *envp)
 {
 	int retval;
@@ -1856,7 +1856,7 @@ int kernel_execve(const char *kernel_filename,
 		return -EINVAL;
 
 	CLASS(filename_kernel, filename)(kernel_filename);
-	CLASS(bprm, bprm)(AT_FDCWD, filename, 0);
+	CLASS(bprm, bprm)(dirfd, filename, 0);
 	if (IS_ERR(bprm))
 		return PTR_ERR(bprm);
 
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 65abd5ab8836..04e2b7a85b2b 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -144,7 +144,7 @@ int copy_string_kernel(const char *arg, struct linux_binprm *bprm);
 extern void set_binfmt(struct linux_binfmt *new);
 extern ssize_t read_code(struct file *, unsigned long, loff_t, size_t);
 
-int kernel_execve(const char *filename,
+int kernel_execve(int dirfd, const char *filename,
 		  const char *const *argv, const char *const *envp);
 
 #endif /* _LINUX_BINFMTS_H */
diff --git a/init/main.c b/init/main.c
index 96f93bb06c49..551d03681234 100644
--- a/init/main.c
+++ b/init/main.c
@@ -1511,7 +1511,7 @@ static int run_init_process(const char *init_filename)
 	pr_debug("  with environment:\n");
 	for (p = envp_init; *p; p++)
 		pr_debug("    %s\n", *p);
-	return kernel_execve(init_filename, argv_init, envp_init);
+	return kernel_execve(AT_FDCWD, init_filename, argv_init, envp_init);
 }
 
 static int try_to_run_init_process(const char *init_filename)
diff --git a/kernel/umh.c b/kernel/umh.c
index cffda97d961c..bab134fa8c36 100644
--- a/kernel/umh.c
+++ b/kernel/umh.c
@@ -106,7 +106,7 @@ static int call_usermodehelper_exec_async(void *data)
 	commit_creds(new);
 
 	wait_for_initramfs();
-	retval = kernel_execve(sub_info->path,
+	retval = kernel_execve(AT_FDCWD, sub_info->path,
 			       (const char *const *)sub_info->argv,
 			       (const char *const *)sub_info->envp);
 out:

-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 01/11] kbuild: doc: add label for userprogs section
From: Thomas Weißschuh @ 2026-05-04  9:33 UTC (permalink / raw)
  To: Nathan Chancellor, Andrew Morton, Willy Tarreau,
	Thomas Weißschuh, Brendan Higgins, Shuah Khan,
	Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro,
	Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain,
	David Gow, Rae Moar
  Cc: linux-kbuild, linux-kernel, linux-kselftest, kunit-dev, linux-doc,
	workflows, linux-mm, linux-fsdevel, Thomas Weißschuh,
	Christophe Leroy, Nicolas Schier, Masahiro Yamada
In-Reply-To: <20260504-kunit-kselftests-v6-0-712d3d526d97@linutronix.de>

Some upcoming documentation will link directly to the userprogs section.

Add a label to the section so it can be referenced.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Reviewed-by: Nicolas Schier <n.schier@avm.de>
Acked-by: Masahiro Yamada <masahiroy@kernel.org>
---
 Documentation/kbuild/makefiles.rst | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/kbuild/makefiles.rst b/Documentation/kbuild/makefiles.rst
index 24a4708d26e8..6e54ad4cfecb 100644
--- a/Documentation/kbuild/makefiles.rst
+++ b/Documentation/kbuild/makefiles.rst
@@ -891,6 +891,8 @@ This is possible in two ways:
     This will tell kbuild to build lxdialog even if not referenced in
     any rule.
 
+.. _kbuild_userprogs:
+
 Userspace Program support
 =========================
 

-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 00/11] kunit: Introduce UAPI testing framework
From: Thomas Weißschuh @ 2026-05-04  9:33 UTC (permalink / raw)
  To: Nathan Chancellor, Andrew Morton, Willy Tarreau,
	Thomas Weißschuh, Brendan Higgins, Shuah Khan,
	Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro,
	Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain,
	David Gow, Rae Moar
  Cc: linux-kbuild, linux-kernel, linux-kselftest, kunit-dev, linux-doc,
	workflows, linux-mm, linux-fsdevel, Thomas Weißschuh,
	Christophe Leroy, Nicolas Schier, Masahiro Yamada

Currently testing of userspace and in-kernel API use two different
frameworks. kselftests for the userspace ones and Kunit for the
in-kernel ones. Besides their different scopes, both have different
strengths and limitations:

Kunit:
* Tests are normal kernel code.
* They use the regular kernel toolchain.
* They can be packaged and distributed as modules conveniently.

Kselftests:
* Tests are normal userspace code
* They need a userspace toolchain.
  A kernel cross toolchain is likely not enough.
* A fair amout of userland is required to run the tests,
  which means a full distro or handcrafted rootfs.
* There is no way to conveniently package and run kselftests with a
  given kernel image.
* The kselftests makefiles are not as powerful as regular kbuild.
  For example they are missing proper header dependency tracking or more
  complex compiler option modifications.

Therefore kunit is much easier to run against different kernel
configurations and architectures.
This series aims to combine kselftests and kunit, avoiding both their
limitations. It works by compiling the userspace kselftests as part of
the regular kernel build, embedding them into the kunit kernel or module
and executing them from there. If the kernel toolchain is not fit to
produce userspace because of a missing libc, the kernel's own nolibc can
be used instead.
The structured TAP output from the kselftest is integrated into the
kunit KTAP output transparently, the kunit parser can parse the combined
logs together.

Further room for improvements:
* Call each test in its completely dedicated namespace
* Handle additional test files besides the test executable through
  archives. CPIO, cramfs, etc.
* Expose the blobs in debugfs
* Provide some convience wrappers around compat userprogs
* Figure out a migration path/coexistence solution for
  kunit UAPI and tools/testing/selftests/

Output from the kunit example testcase, note the output of
"example_uapi_tests".

$ ./tools/testing/kunit/kunit.py run --kunitconfig lib/kunit example
...
Running tests with:
$ .kunit/linux kunit.filter_glob=example kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[11:53:53] ================== example (10 subtests) ===================
[11:53:53] [PASSED] example_simple_test
[11:53:53] [SKIPPED] example_skip_test
[11:53:53] [SKIPPED] example_mark_skipped_test
[11:53:53] [PASSED] example_all_expect_macros_test
[11:53:53] [PASSED] example_static_stub_test
[11:53:53] [PASSED] example_static_stub_using_fn_ptr_test
[11:53:53] [PASSED] example_priv_test
[11:53:53] =================== example_params_test  ===================
[11:53:53] [SKIPPED] example value 3
[11:53:53] [PASSED] example value 2
[11:53:53] [PASSED] example value 1
[11:53:53] [SKIPPED] example value 0
[11:53:53] =============== [PASSED] example_params_test ===============
[11:53:53] [PASSED] example_slow_test
[11:53:53] ======================= (4 subtests) =======================
[11:53:53] [PASSED] procfs
[11:53:53] [PASSED] userspace test 2
[11:53:53] [SKIPPED] userspace test 3: some reason
[11:53:53] [PASSED] userspace test 4
[11:53:53] ================ [PASSED] example_uapi_test ================
[11:53:53] ===================== [PASSED] example =====================
[11:53:53] ============================================================
[11:53:53] Testing complete. Ran 16 tests: passed: 11, skipped: 5
[11:53:53] Elapsed time: 67.543s total, 1.823s configuring, 65.655s building, 0.058s running

---
Changes in v6:
- Use usermode helper framework
- Trim now unnecessary new module exports
- Report unhandled output line
- Add SUPERH to ARCH_HAS_NOLIBC
- Remove non-integral patches submitted elsewhere
- Drop CC_CAN_LINK_STATIC support. It is based on CC_CAN_LINK which is
  currently being reworked.
- Use more cleanup helpers
- Split stdout/stderr forwarding into its own patch
- Link to v5: https://lore.kernel.org/r/20250717-kunit-kselftests-v5-0-442b711cde2e@linutronix.de

Changes in v5:
- Initialize output variable of kernel_wait()
- Fix .incbin with in-tree builds
- Keep requirement of KTAP tests to have a number which was removed accidentally
- Only synthesize KTAP subtest failure if the outer one is TestStatus.FAILURE
- Use -I instead of -isystem in NOLIBC_USERCFLAGS to populate dependency files
- +To filesystem developers to all patches
- +To Luis Chamberlain for discussions about usage of usermodehelper
  (see patches 6 and 12)
- Link to v4: https://lore.kernel.org/r/20250626-kunit-kselftests-v4-0-48760534fef5@linutronix.de

Changes in v4:
- Move Kconfig.nolibc from tools/ to init/
- Drop generic userprogs nolibc integration
- Drop generic blob framework
- Pick up review tags from David
- Extend new kunit TAP parser tests
- Add MAINTAINERS entry
- Allow CONFIG_KUNIT_UAPI=m
- Split /proc validation into dedicated UAPI test
- Trim recipient list a bit
- Use KUNIT_FAIL_AND_ABORT() over KUNIT_FAIL()
- Link to v3: https://lore.kernel.org/r/20250611-kunit-kselftests-v3-0-55e3d148cbc6@linutronix.de

Changes in v3:
- Reintroduce CONFIG_CC_CAN_LINK_STATIC
- Enable CONFIG_ARCH_HAS_NOLIBC for m68k and SPARC
- Properly handle 'clean' target for userprogs
- Use ramfs over tmpfs to reduce dependencies
- Inherit userprogs byte order and ABI from kernel
- Drop now unnecessary "#ifndef NOLIBC"
- Pick up review tags
- Drop usage of __private in blob.h,
  sparse complains and it is not really necessary
- Fix execution on loongarch when using clang
- Drop userprogs libgcc handling, it was ugly and is not yet necessary
- Link to v2: https://lore.kernel.org/r/20250407-kunit-kselftests-v2-0-454114e287fd@linutronix.de

Changes in v2:
- Rebase onto v6.15-rc1
- Add documentation and kernel docs
- Resolve invalid kconfig breakages
- Drop already applied patch "kbuild: implement CONFIG_HEADERS_INSTALL for Usermode Linux"
- Drop userprogs CONFIG_WERROR integration, it doesn't need to be part of this series
- Replace patch prefix "kconfig" with "kbuild"
- Rename kunit_uapi_run_executable() to kunit_uapi_run_kselftest()
- Generate private, conflict-free symbols in the blob framework
- Handle kselftest exit codes
- Handle SIGABRT
- Forward output also to kunit debugfs log
- Install a fd=0 stdin filedescriptor
- Link to v1: https://lore.kernel.org/r/20250217-kunit-kselftests-v1-0-42b4524c3b0a@linutronix.de

To: Nathan Chancellor <nathan@kernel.org>
To: Andrew Morton <akpm@linux-foundation.org>
To: Willy Tarreau <w@1wt.eu>
To: Thomas Weißschuh <linux@weissschuh.net>
To: Brendan Higgins <brendan.higgins@linux.dev>
To: David Gow <davidgow@google.com>
To: Rae Moar <rmoar@google.com>
To: Shuah Khan <shuah@kernel.org>
To: Jonathan Corbet <corbet@lwn.net>
To: Nicolas Schier <nicolas.schier@linux.dev>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: linux-kbuild@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-kselftest@vger.kernel.org
Cc: kunit-dev@googlegroups.com
Cc: linux-doc@vger.kernel.org
Cc: workflows@vger.kernel.org
To: Kees Cook <kees@kernel.org>
To: Alexander Viro <viro@zeniv.linux.org.uk>
To: Christian Brauner <brauner@kernel.org>
To: Jan Kara <jack@suse.cz>
To: Christoph Hellwig <hch@lst.de>
To: Luis Chamberlain <mcgrof@kernel.org>
Cc: linux-mm@kvack.org
Cc: linux-fsdevel@vger.kernel.org
Cc: Nicolas Schier <n.schier@avm.de>
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>

---
Thomas Weißschuh (11):
      kbuild: doc: add label for userprogs section
      exec: add dirfd parameter to kernel_execve()
      umh: add dirfd parameter
      mount: add support for __free(kern_unmount)
      init: add nolibc build support
      kunit: qemu_configs: loongarch: Enable LSX/LSAX
      kunit: Introduce UAPI testing framework
      kunit: uapi: Forward test executable output to KUnit log
      kunit: uapi: Add example for UAPI tests
      kunit: uapi: Introduce preinit executable
      kunit: uapi: Validate usability of /proc

 Documentation/dev-tools/kunit/api/index.rst   |   5 +
 Documentation/dev-tools/kunit/api/uapi.rst    |  14 +
 Documentation/kbuild/makefiles.rst            |   2 +
 MAINTAINERS                                   |  11 +
 fs/coredump.c                                 |   2 +-
 fs/exec.c                                     |   4 +-
 include/kunit/uapi.h                          |  77 ++++++
 include/linux/binfmts.h                       |   2 +-
 include/linux/mount.h                         |   2 +
 include/linux/umh.h                           |   3 +-
 init/Kconfig                                  |   2 +
 init/Kconfig.nolibc                           |  16 ++
 init/Makefile.nolibc                          |  13 +
 init/main.c                                   |   2 +-
 kernel/module/kmod.c                          |   2 +-
 kernel/umh.c                                  |   9 +-
 lib/kobject_uevent.c                          |   2 +-
 lib/kunit/Kconfig                             |  16 ++
 lib/kunit/Makefile                            |  26 ++
 lib/kunit/kunit-example-test.c                |  15 ++
 lib/kunit/kunit-example-uapi.c                |  22 ++
 lib/kunit/kunit-test-uapi.c                   |  51 ++++
 lib/kunit/kunit-test.c                        |  24 +-
 lib/kunit/kunit-uapi.c                        | 351 ++++++++++++++++++++++++++
 lib/kunit/uapi-preinit.c                      |  68 +++++
 security/keys/request_key.c                   |   2 +-
 tools/testing/kunit/qemu_configs/loongarch.py |   2 +
 27 files changed, 732 insertions(+), 13 deletions(-)
---
base-commit: 813d26ba48f9e3909d39966857421500faef508a
change-id: 20241015-kunit-kselftests-56273bc40442

Best regards,
--  
Thomas Weißschuh <thomas.weissschuh@linutronix.de>


^ permalink raw reply

* [PATCH v8 4/4] kunit: Add documentation for warning backtrace suppression API
From: Albert Esteve @ 2026-05-04  7:41 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, Dan Carpenter,
	Alessandro Carminati, Albert Esteve, Kees Cook, David Gow
In-Reply-To: <20260504-kunit_add_support-v8-0-3e5957cdd235@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>
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>
---
 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
+	}

-- 
2.53.0


^ permalink raw reply related

* [PATCH v8 3/4] drm: Suppress intentional warning backtraces in scaling unit tests
From: Albert Esteve @ 2026-05-04  7:41 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, Dan Carpenter, Maíra Canal,
	Alessandro Carminati, Albert Esteve, Simona Vetter
In-Reply-To: <20260504-kunit_add_support-v8-0-3e5957cdd235@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.

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(&params->src, &params->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(&params->src, &params->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(&params->src, &params->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(&params->src, &params->dst,
+						      params->min_range, params->max_range);
+	}
 
 	KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
 }

-- 
2.53.0


^ permalink raw reply related

* [PATCH v8 2/4] kunit: Add backtrace suppression self-tests
From: Albert Esteve @ 2026-05-04  7:41 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, Dan Carpenter,
	Alessandro Carminati, Albert Esteve, Kees Cook
In-Reply-To: <20260504-kunit_add_support-v8-0-3e5957cdd235@redhat.com>

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>
---
 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");

-- 
2.53.0


^ permalink raw reply related

* [PATCH v8 1/4] bug/kunit: Core support for suppressing warning backtraces
From: Albert Esteve @ 2026-05-04  7:41 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: <20260504-kunit_add_support-v8-0-3e5957cdd235@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.

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>
---
 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 */

-- 
2.53.0


^ permalink raw reply related

* [PATCH v8 0/4] kunit: Add support for suppressing warning backtraces
From: Albert Esteve @ 2026-05-04  7:41 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, Dan Carpenter, Maíra Canal,
	Kees Cook, Simona Vetter, David Gow

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.

Three 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_SUPPRESSED_WARNING(test): manual macros for larger
  blocks or post-suppression count checks. Limited to one pair per
  scope.
- 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

--
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 |  63 ++++++++++-
 drivers/gpu/drm/tests/drm_rect_test.c   |  23 +++-
 include/kunit/test-bug.h                |  25 +++++
 include/kunit/test.h                    | 138 ++++++++++++++++++++++++
 kernel/panic.c                          |  15 ++-
 lib/bug.c                               |  10 ++
 lib/kunit/Makefile                      |   4 +-
 lib/kunit/backtrace-suppression-test.c  | 184 ++++++++++++++++++++++++++++++++
 lib/kunit/bug.c                         | 115 ++++++++++++++++++++
 lib/kunit/hooks-impl.h                  |   2 +
 10 files changed, 571 insertions(+), 8 deletions(-)
---
base-commit: 80234b5ab240f52fa45d201e899e207b9265ef91
change-id: 20260312-kunit_add_support-2f35806b19dd

Best regards,
-- 
Albert Esteve <aesteve@redhat.com>


^ permalink raw reply

* Re: [PATCH v4 00/10] Auto-generate maintainer profile entries
From: Mauro Carvalho Chehab @ 2026-05-04  7:00 UTC (permalink / raw)
  To: Jonathan Corbet
  Cc: Albert Ou, Mauro Carvalho Chehab, Palmer Dabbelt, Paul Walmsley,
	linux-doc, linux-kernel, linux-riscv, workflows, Alexandre Ghiti,
	Shuah Khan, Randy Dunlap, Dan Williams
In-Reply-To: <87lde0bii2.fsf@trenco.lwn.net>

On Sun, 03 May 2026 09:49:41 -0600
Jonathan Corbet <corbet@lwn.net> wrote:

> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> 
> > Hi Jon,
> >
> > This is basically the same patch series I sent during the merge
> > window, rebased on the top of post 7.1-rc1 docs-next branch.
> > It is tested both with and without O=DOCS.
> >
> > It contains just one extra trivial patch adding a missing SPDX
> > header, and, on v4, I dropped two patches touching MAINTAINERS,
> > as those aren't needed anymore.
> >
> > This patch series change the way maintainer entry profile links
> > are added to the documentation. Instead of having an entry for
> > each of them at an ReST file, get them from MAINTAINERS content.
> >
> > That should likely make easier to maintain, as there will be a single
> > point to place all such profiles.
> >
> > The output is a per-subsystem sorted (*) series of links shown as a
> > list like this:
> >
> >     - Arm And Arm64 Soc Sub-Architectures (Common Parts)
> >     - Arm/Samsung S3C, S5P And Exynos Arm Architectures
> >     - Arm/Tesla Fsd Soc Support
> >     ...
> >     - Xfs Filesystem
> >
> > Please notice that the series is doing one logical change per patch.
> > I could have merged some changes altogether, but I opted doing it
> > in small steps to help reviews. If you prefer, feel free to merge
> > maintainers_include changes on merge.
> >
> > There is one interesting side effect of this series: there is no
> > need to add rst files containing profiles inside a TOC tree: Just
> > creating the file anywhere inside Documentation and adding a P entry
> > is enough. Adding them to a TOC won't hurt.  
> 
> One thing I kind of dislike about these magic mechanisms is that we end
> up with a single, essentially unsorted list of stuff that readers have
> to go digging their way through.  It would be nice if we could somehow
> apply a bit of structure; as the number of these handbooks grows, our
> readers would appreciate it.

The output is sorted by subsystem's name:

	for profile, entry in sorted(maint.profile_entries.items()):
	    if entry.startswith("http"):
		output += f"- `{profile} <{entry}>`_\n"
            else:
		output += f"- :doc:`{profile} <{entry}>`\n"

But yeah, as this grows, We can apply some struct there later on.

I expect that this would be good enough for "P" entries: as such entries 
are used only by the biggest subsystems, I won't expect that the profiles 
list would be too big. 

If I'm wrong, though, changing its output is easy, as all the parsing
were done in separate: all we have to do would be to change this part.

-

Now, for the full MAINTAINERS content, I agree with you. I have
a patch series here which splits the parsing from the output,
which allows placing its contents inside a table and with a
filter javascript [1]. On my view, the output is a lot more
interesting for readers this way [2].
 
> Oh well, one can always hope.  Meanwhile, this seems useful, I've
> applied it.

Thanks!

---

[1] On such series, I'm creating a table with two rows:

        output += ".. _maintainers_table:\n\n"
        output += ".. flat-table::\n"
        output += "  :header-rows: 1\n\n"
        output += "  * - Subsystem\n"
        output += "    - Properties\n\n"

        self.state.document['maintainers_included'] = True

        for name, fields in maint_parser.maint_entries.items():
            output += f"  * - {name}\n"

            tag = "-"
            for field, lines in fields.items():
                field_name = maint_parser.fields.get(field, field)

                output += f"    {tag} :{field_name}:\n        "
                output += ",\n        ".join(lines) + "\n"
                tag = " "

            output += "\n"

   Which is a lot easier to read than the current output, and adding
   a small javascript that allows filtering entries, based at the
   contents of either subsystem or properties. That should help
   readers to seek for things they're interested.

   I considered ordering it by subsystems, and did some tests with that,
   but at the final version I ended removing.

   The main issue is that MAINTAINERS entries aren't grouped by
   subsystems. Also, we don't have any field to identify to what 
   subsystem each entry belongs.

   Using the mailing list field helps to have something close enough,
   while being fast. Even so, some caveats are needed, as:

   1) several entries contain multiple ML entries, which may include:
      - subsystem ML;
      - LKML;
      - driver-specific ML;
      - vendor-specific ML.

   2) several entries have only LKML.

   For the purpose of grouping such entries, even after filtering out LKML,
   due to (1), hints are needed to try to pick subsystem ML. Perhaps the
   best hint is to check if the entry is @kernel.org, which works reasonably
   well. Yet, not all subsystems have its ML there.

   I also considered sorting them by the number of files, using iglob 
   to calculate it. That would help to place the subsystem first, followed
   by subsystem drivers, and this is fast enough with my nvme disks but 
   this could slow kernel builds on mechanical HDs.

   So, I suspect that, if we want to have something more structured,
   the first step would be to do some rework at the MAINTAINERS file.

[2] I need some time to check if are there any regressions
    on the patch that splits the logic.

Regards,
Mauro

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox