[PATCH v3 00/16] kunit: Introduce UAPI testing framework

16 views
Skip to first unread message

Thomas Weißschuh

unread,
Jun 11, 2025, 3:38:35 AMJun 11
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
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.
* Compatibility with kselftest_harness.h (in progress)
* 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

Based on v6.15-rc1.

Signed-off-by: Thomas Weißschuh <thomas.w...@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-kselft...@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-kselft...@linutronix.de

---
Thomas Weißschuh (16):
kbuild: userprogs: avoid duplicating of flags inherited from kernel
kbuild: userprogs: also inherit byte order and ABI from kernel
init: re-add CONFIG_CC_CAN_LINK_STATIC
kbuild: userprogs: add nolibc support
kbuild: introduce CONFIG_ARCH_HAS_NOLIBC
kbuild: doc: add label for userprogs section
kbuild: introduce blob framework
kunit: tool: Add test for nested test result reporting
kunit: tool: Don't overwrite test status based on subtest counts
kunit: tool: Parse skipped tests from kselftest.h
kunit: Always descend into kunit directory during build
kunit: qemu_configs: loongarch: Enable LSX/LSAX
kunit: Introduce UAPI testing framework
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 | 12 +
Documentation/kbuild/makefiles.rst | 38 ++-
MAINTAINERS | 2 +
Makefile | 7 +-
include/kunit/uapi.h | 24 ++
include/linux/blob.h | 31 +++
init/Kconfig | 7 +
lib/Makefile | 4 -
lib/kunit/Kconfig | 10 +
lib/kunit/Makefile | 20 +-
lib/kunit/kunit-example-test.c | 15 ++
lib/kunit/kunit-example-uapi.c | 54 ++++
lib/kunit/uapi-preinit.c | 63 +++++
lib/kunit/uapi.c | 294 +++++++++++++++++++++
scripts/Makefile.blobs | 19 ++
scripts/Makefile.build | 6 +
scripts/Makefile.clean | 2 +-
scripts/Makefile.userprogs | 13 +-
scripts/blob-wrap.c | 27 ++
tools/include/nolibc/Kconfig.nolibc | 15 ++
tools/testing/kunit/kunit_parser.py | 13 +-
tools/testing/kunit/kunit_tool_test.py | 9 +
tools/testing/kunit/qemu_configs/loongarch.py | 2 +
.../test_is_test_passed-failure-nested.log | 10 +
.../test_data/test_is_test_passed-kselftest.log | 3 +-
26 files changed, 686 insertions(+), 19 deletions(-)
---
base-commit: f07a3558c4a5d76f3fea004075e5151c4516d055
change-id: 20241015-kunit-kselftests-56273bc40442

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

Thomas Weißschuh

unread,
Jun 11, 2025, 3:38:36 AMJun 11
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org, Thomas Weißschuh
Some upcoming new documentation should link directly to the userprogs section.

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

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
---
Documentation/kbuild/makefiles.rst | 2 ++
1 file changed, 2 insertions(+)

diff --git a/Documentation/kbuild/makefiles.rst b/Documentation/kbuild/makefiles.rst
index 4cc7a1b89f1803857a4723284613111e9ad71d92..2adea36ac6ebf6c292e01a3e04c0b633e3c1b8ad 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.49.0

Thomas Weißschuh

unread,
Jun 11, 2025, 3:38:38 AMJun 11
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
Various subsystems embed non-code build artifacts into the kernel,
for example the initramfs, /proc/config.gz, vDSO image, etc.
Currently each user has their own implementation for that.

Add a common "blob" framework to provide this functionality.
It provides standard kbuild and C APIs to embed and later access non-code
build artifacts into the kernel image or modules.

Reviewed-by: Nicolas Schier <n.sc...@avm.de>
Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
---
Due to its closeness to kbuild this is currently added to its MAINTAINER entry.
But I can also maintain it on its own.
---
Documentation/kbuild/makefiles.rst | 23 +++++++++++++++++++++--
MAINTAINERS | 2 ++
include/linux/blob.h | 31 +++++++++++++++++++++++++++++++
scripts/Makefile.blobs | 19 +++++++++++++++++++
scripts/Makefile.build | 6 ++++++
scripts/Makefile.clean | 2 +-
scripts/blob-wrap.c | 27 +++++++++++++++++++++++++++
7 files changed, 107 insertions(+), 3 deletions(-)

diff --git a/Documentation/kbuild/makefiles.rst b/Documentation/kbuild/makefiles.rst
index 2adea36ac6ebf6c292e01a3e04c0b633e3c1b8ad..5d158780948ab6d7d21287231e310dc87d5e1dc7 100644
--- a/Documentation/kbuild/makefiles.rst
+++ b/Documentation/kbuild/makefiles.rst
@@ -525,8 +525,8 @@ otherwise the command line check will fail, and the target will
always be built.

If the target is already listed in the recognized syntax such as
-obj-y/m, lib-y/m, extra-y/m, always-y/m, hostprogs, userprogs, Kbuild
-automatically adds it to $(targets). Otherwise, the target must be
+obj-y/m, lib-y/m, extra-y/m, always-y/m, hostprogs, userprogs, blobs,
+Kbuild automatically adds it to $(targets). Otherwise, the target must be
explicitly added to $(targets).

Assignments to $(targets) are without $(obj)/ prefix. if_changed may be
@@ -1019,6 +1019,25 @@ There are two ways to do this.
This will tell Kbuild to build binderfs_example when it visits this
Makefile.

+.. _kbuild_blobs:
+
+Blob framework
+==============
+
+Kbuild supports wrapping source or generated files into object files which are linked
+into the kernel and then accessed at runtime through ``include/linux/blob.h``.
+
+Example::
+
+ obj-m := some-module.o
+ userprogs := some-userprog
+ blobs := some-userprog.blob.o
+ some-userprog.blob-symbol := some_userprog
+ some-module-y += some-userprog.blob.o
+
+Kbuild will build the :ref:`userprog <kbuild_userprogs>` ``some-userprog`` and
+link it into ``some-module`` from where it can be accessed as ``BLOB(some_userprog)``.
+
Kbuild clean infrastructure
===========================

diff --git a/MAINTAINERS b/MAINTAINERS
index a92290fffa163f9fe8fe3f04bf66426f9a894409..435f8af750d40d859b48dd4f93f7991768f218e1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13063,11 +13063,13 @@ Q: https://patchwork.kernel.org/project/linux-kbuild/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git
F: Documentation/kbuild/
F: Makefile
+F: include/linux/blob.h
F: scripts/*vmlinux*
F: scripts/Kbuild*
F: scripts/Makefile*
F: scripts/bash-completion/
F: scripts/basic/
+F: scripts/blob-wrap.c
F: scripts/clang-tools/
F: scripts/dummy-tools/
F: scripts/include/
diff --git a/include/linux/blob.h b/include/linux/blob.h
new file mode 100644
index 0000000000000000000000000000000000000000..4104d04e036fadce220e05fd2d9b996323dd06e8
--- /dev/null
+++ b/include/linux/blob.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Linkable blob API.
+ *
+ * Copyright (C) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@linutronix.de>
+ */
+
+#ifndef _LINUX_BLOB_H
+#define _LINUX_BLOB_H
+
+#include <linux/args.h>
+#include <linux/types.h>
+
+struct blob {
+ const char *const path;
+ const u8 *data;
+ const u8 *end;
+};
+
+#define BLOB(_symbol) ({ \
+ extern const struct blob CONCATENATE(__blob_, _symbol); \
+ &CONCATENATE(__blob_, _symbol); \
+})
+
+static inline size_t blob_size(const struct blob *blob)
+{
+ return blob->end - blob->data;
+}
+
+#endif /* _LINUX_BLOB_H */
diff --git a/scripts/Makefile.blobs b/scripts/Makefile.blobs
new file mode 100644
index 0000000000000000000000000000000000000000..fd20ebb41c1d6509750debf7896a08a143d28759
--- /dev/null
+++ b/scripts/Makefile.blobs
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Build linkable blobs
+#
+
+blobs := $(addprefix $(obj)/, $(blobs))
+
+blob-stem = $(subst -,_,$(subst .blob,,$(basename $(patsubst $(obj)/%,%,$@))))
+blob-symbol = $(or $($(target-stem)-symbol),$(blob-stem))
+
+blob-flags = -DBLOB_SYMBOL="$(blob-symbol)" -DBLOB_INPUT=$<
+
+quiet_cmd_blob = BLOB $@
+ cmd_blob = $(CC) $(c_flags) $(blob-flags) -c -o $@ $(srctree)/scripts/blob-wrap.c
+
+$(blobs): $(obj)/%.blob.o: $(obj)/% $(srctree)/scripts/blob-wrap.c FORCE
+ $(call if_changed_dep,blob)
+
+targets += $(blobs)
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index a6461ea411f7a95a9dd156897bec43cb22ef1092..de000268a538875596aae597efaf06058474b17d 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -529,6 +529,12 @@ ifneq ($(need-dtbslist)$(dtb-y)$(dtb-)$(filter %.dtb %.dtb.o %.dtbo.o,$(targets)
include $(srctree)/scripts/Makefile.dtbs
endif

+# $(sort ...) is used here to remove duplicated words and excessive spaces.
+blobs := $(sort $(blobs))
+ifneq ($(blobs),)
+include $(srctree)/scripts/Makefile.blobs
+endif
+
# Build
# ---------------------------------------------------------------------------

diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean
index 6ead00ec7313b3e4330a8de5f1342f2da1d6eb84..536972b0a528d117e17296da9936825c3903af6e 100644
--- a/scripts/Makefile.clean
+++ b/scripts/Makefile.clean
@@ -25,7 +25,7 @@ subdir-ymn := $(addprefix $(obj)/,$(subdir-ymn))
# directory

__clean-files := \
- $(clean-files) $(targets) $(hostprogs) $(userprogs) \
+ $(clean-files) $(targets) $(hostprogs) $(userprogs) $(blobs) \
$(extra-y) $(extra-m) $(extra-) \
$(always-y) $(always-m) $(always-) \
$(hostprogs-always-y) $(hostprogs-always-m) $(hostprogs-always-) \
diff --git a/scripts/blob-wrap.c b/scripts/blob-wrap.c
new file mode 100644
index 0000000000000000000000000000000000000000..82ab3bc641bd69ec35029c2f4a9dd6d6c6720a02
--- /dev/null
+++ b/scripts/blob-wrap.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/args.h>
+#include <linux/blob.h>
+#include <linux/stringify.h>
+
+#define BLOB_SYMBOL_DATA CONCATENATE(__blob_data_, BLOB_SYMBOL)
+#define BLOB_SYMBOL_END CONCATENATE(__blob_end_, BLOB_SYMBOL)
+
+asm (
+" .pushsection .rodata, \"a\"\n"
+" .global " __stringify(BLOB_SYMBOL_DATA) "\n"
+__stringify(BLOB_SYMBOL_DATA) ":\n"
+" .incbin \"" __stringify(BLOB_INPUT) "\"\n"
+" .global " __stringify(BLOB_SYMBOL_END) "\n"
+__stringify(BLOB_SYMBOL_END) ":\n"
+" .popsection\n"
+);
+
+extern const u8 BLOB_SYMBOL_DATA;
+extern const u8 BLOB_SYMBOL_END;
+
+const struct blob CONCATENATE(__blob_, BLOB_SYMBOL) = {
+ .path = __stringify(BLOB_INPUT),
+ .data = &BLOB_SYMBOL_DATA,
+ .end = &BLOB_SYMBOL_END,
+};

--
2.49.0

Thomas Weißschuh

unread,
Jun 11, 2025, 3:38:38 AMJun 11
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org, Thomas Weißschuh
If a subtest itself reports success, but the outer testcase fails,
the whole testcase should be reported as a failure.
However the status is recalculated based on the test counts,
overwriting the outer test result.
Synthesize a failed test in this case to make sure the failure is not
swallowed.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
---
tools/testing/kunit/kunit_parser.py | 5 +++++
tools/testing/kunit/kunit_tool_test.py | 2 +-
tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log | 3 +++
3 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
index c176487356e6c94882046b19ea696d750905b8d5..2478beb28fc3db825855ad46200340e884da7df1 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -686,6 +686,11 @@ def bubble_up_test_results(test: Test) -> None:
counts.add_status(status)
elif test.counts.get_status() == TestStatus.TEST_CRASHED:
test.status = TestStatus.TEST_CRASHED
+ if not test.ok_status():
+ for t in subtests:
+ if not t.ok_status():
+ counts.add_status(t.status)
+ break

def parse_test(lines: LineStream, expected_num: int, log: List[str], is_subtest: bool, printer: Printer) -> Test:
"""
diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index 691cde9b030f7729128490c1bdb42ccee1967ad6..c25f52650837e83325b06bddd2aa665fd29f91d9 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -170,7 +170,7 @@ class KUnitParserTest(unittest.TestCase):
with open(nested_log) as file:
result = kunit_parser.parse_run_tests(file.readlines(), stdout)
self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
- self.assertEqual(result.counts.failed, 2)
+ self.assertEqual(result.counts.failed, 3)
self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[0].status)
self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[1].status)

diff --git a/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
index 835816e0a07715a514f5f5afab1b6250037feaf4..cd9033c464792e6294905a5676346684182874ad 100644
--- a/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
+++ b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
@@ -1,5 +1,8 @@
KTAP version 1
1..2
+ KTAP version 1
+ 1..1
+ ok 1 test 1
not ok 1 subtest 1
KTAP version 1
1..1

--
2.49.0

Thomas Weißschuh

unread,
Jun 11, 2025, 3:38:38 AMJun 11
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
Nolibc does not support all architectures.
Add a kconfig option, so users can know where it is available.

The new option is maintained inside tools/include/nolibc/ as only that
directory is responsible for nolibc's availability.

Reviewed-by: Nicolas Schier <n.sc...@avm.de>
Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
---
init/Kconfig | 2 ++
tools/include/nolibc/Kconfig.nolibc | 15 +++++++++++++++
2 files changed, 17 insertions(+)

diff --git a/init/Kconfig b/init/Kconfig
index 26cafbad4f1560fb56b4bef31ae29baf54175661..6d10f2816e453d1d28e4b8249cbbd95c28baa0f1 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -92,6 +92,8 @@ config CC_CAN_LINK_STATIC
default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m64-flag) -static) if 64BIT
default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m32-flag) -static)

+source "tools/include/nolibc/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/tools/include/nolibc/Kconfig.nolibc b/tools/include/nolibc/Kconfig.nolibc
new file mode 100644
index 0000000000000000000000000000000000000000..29cbc5437e70cbc5e256f00b74d0ab4801b40de7
--- /dev/null
+++ b/tools/include/nolibc/Kconfig.nolibc
@@ -0,0 +1,15 @@
+# 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 UML_X86
+ default y if X86

--
2.49.0

Thomas Weißschuh

unread,
Jun 11, 2025, 3:38:39 AMJun 11
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org, Thomas Weißschuh
Skipped tests reported by kselftest.h use a different format than KTAP,
there is no explicit test name. Normally the test name is part of the
free-form string after the SKIP keyword:

ok 3 # SKIP test: some reason

Extend the parser to handle those correctly. Use the free-form string as
test name instead.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
---
tools/testing/kunit/kunit_parser.py | 8 +++++---
tools/testing/kunit/test_data/test_is_test_passed-kselftest.log | 3 ++-
2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
index 2478beb28fc3db825855ad46200340e884da7df1..4599d23c79b79f0e219d655c7053c8c3b34f8152 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -352,9 +352,9 @@ def parse_test_plan(lines: LineStream, test: Test) -> bool:
lines.pop()
return True

-TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?([^#]*)( # .*)?$')
+TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+)? ?(- )?([^#]*)( # .*)?$')

-TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?(.*) # SKIP(.*)$')
+TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+)? ?(- )?(.*) # SKIP ?(.*)$')

def peek_test_name_match(lines: LineStream, test: Test) -> bool:
"""
@@ -379,6 +379,8 @@ def peek_test_name_match(lines: LineStream, test: Test) -> bool:
if not match:
return False
name = match.group(4)
+ if not name:
+ return False
return name == test.name

def parse_test_result(lines: LineStream, test: Test,
@@ -416,7 +418,7 @@ def parse_test_result(lines: LineStream, test: Test,

# Set name of test object
if skip_match:
- test.name = skip_match.group(4)
+ test.name = skip_match.group(4) or skip_match.group(5)
else:
test.name = match.group(4)

diff --git a/tools/testing/kunit/test_data/test_is_test_passed-kselftest.log b/tools/testing/kunit/test_data/test_is_test_passed-kselftest.log
index 65d3f27feaf22a3f47ed831c4c24f6f11c625a92..30d9ef18bcec177067288d5242771236f29b7d56 100644
--- a/tools/testing/kunit/test_data/test_is_test_passed-kselftest.log
+++ b/tools/testing/kunit/test_data/test_is_test_passed-kselftest.log
@@ -1,5 +1,5 @@
TAP version 13
-1..2
+1..3
# selftests: membarrier: membarrier_test_single_thread
# TAP version 13
# 1..2
@@ -12,3 +12,4 @@ ok 1 selftests: membarrier: membarrier_test_single_thread
# ok 1 sys_membarrier available
# ok 2 sys membarrier invalid command test: command = -1, flags = 0, errno = 22. Failed as expected
ok 2 selftests: membarrier: membarrier_test_multi_thread
+ok 3 # SKIP selftests: membarrier: membarrier_test_multi_thread

--
2.49.0

Thomas Weißschuh

unread,
Jun 11, 2025, 3:38:40 AMJun 11
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org, Thomas Weißschuh
An upcoming change will add 'userprogs' to the kunit subdirectory.
For kbuild to properly clean up these build artifacts the subdirectory
needs to be always processed.

Pushing the special logic for hook.o into the kunit Makefile also makes the
logic easier to understand.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
---
lib/Makefile | 4 ----
lib/kunit/Makefile | 2 +-
2 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index c38582f187dd81916113319072e5cfef26f26c84..698566135091cc3bf0054f1954b434dc3325364a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -108,11 +108,7 @@ test_fpu-y := test_fpu_glue.o test_fpu_impl.o
CFLAGS_test_fpu_impl.o += $(CC_FLAGS_FPU)
CFLAGS_REMOVE_test_fpu_impl.o += $(CC_FLAGS_NO_FPU)

-# Some KUnit files (hooks.o) need to be built-in even when KUnit is a module,
-# so we can't just use obj-$(CONFIG_KUNIT).
-ifdef CONFIG_KUNIT
obj-y += kunit/
-endif

ifeq ($(CONFIG_DEBUG_KOBJECT),y)
CFLAGS_kobject.o += -DDEBUG
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 5aa51978e456ab3bb60c12071a26cf2bdcb1b508..656f1fa35abcc635e67d5b4cb1bc586b48415ac5 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -17,7 +17,7 @@ kunit-objs += debugfs.o
endif

# KUnit 'hooks' are built-in even when KUnit is built as a module.
-obj-y += hooks.o
+obj-$(if $(CONFIG_KUNIT),y) += hooks.o

obj-$(CONFIG_KUNIT_TEST) += kunit-test.o
obj-$(CONFIG_KUNIT_TEST) += platform-test.o

--
2.49.0

Thomas Weißschuh

unread,
Jun 11, 2025, 3:38:40 AMJun 11
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org, Thomas Weißschuh
Currently there is no test validating the result reporting from nested
tests. Add one, it will also be used to validate upcoming changes to the
nested test parsing.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
---
tools/testing/kunit/kunit_tool_test.py | 9 +++++++++
.../kunit/test_data/test_is_test_passed-failure-nested.log | 7 +++++++
2 files changed, 16 insertions(+)

diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index bbba921e0eacb18663abfcabb2bccf330d8666f5..691cde9b030f7729128490c1bdb42ccee1967ad6 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -165,6 +165,15 @@ class KUnitParserTest(unittest.TestCase):
self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
self.assertEqual(result.counts.errors, 0)

+ def test_parse_failed_nested_tests_log(self):
+ nested_log = test_data_path('test_is_test_passed-failure-nested.log')
+ with open(nested_log) as file:
+ result = kunit_parser.parse_run_tests(file.readlines(), stdout)
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
+ self.assertEqual(result.counts.failed, 2)
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[0].status)
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[1].status)
+
def test_no_header(self):
empty_log = test_data_path('test_is_test_passed-no_tests_run_no_header.log')
with open(empty_log) as file:
diff --git a/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
new file mode 100644
index 0000000000000000000000000000000000000000..835816e0a07715a514f5f5afab1b6250037feaf4
--- /dev/null
+++ b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
@@ -0,0 +1,7 @@
+KTAP version 1
+1..2
+not ok 1 subtest 1
+ KTAP version 1
+ 1..1
+ not ok 1 test 1
+not ok 2 subtest 2

--
2.49.0

Thomas Weißschuh

unread,
Jun 11, 2025, 3:38:41 AMJun 11
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org, Thomas Weißschuh
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.w...@linutronix.de>
---
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 a92422967d1da9f1658ef1e80d0d7365ddbae307..1dba755284f11ffc94d8946105b0cfa49cb6f604 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.49.0

Thomas Weißschuh

unread,
Jun 11, 2025, 3:38:41 AMJun 11
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org, Thomas Weißschuh
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.w...@linutronix.de>
---
lib/kunit/Makefile | 9 ++++++-
lib/kunit/uapi-preinit.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++
lib/kunit/uapi.c | 11 +++++++--
3 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index e406a31df1df834a87961663de0b7921b59481c2..19493ec320c61e2ccbb58e8b2e943e9a4ec447e2 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -12,7 +12,14 @@ kunit-objs += test.o \
device.o \
platform.o

-kunit-$(CONFIG_KUNIT_UAPI) += uapi.o
+userprogs += uapi-preinit
+uapi-preinit-nolibc := $(CONFIG_ARCH_HAS_NOLIBC)
+uapi-preinit-userccflags += -static \
+ -include include/generated/autoconf.h \
+ -include $(srctree)/tools/include/linux/kconfig.h
+blobs += uapi-preinit.blob.o
+uapi-preinit.blob-symbol := kunit_uapi_preinit
+kunit-$(CONFIG_KUNIT_UAPI) += uapi.o uapi-preinit.blob.o

ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
kunit-objs += debugfs.o
diff --git a/lib/kunit/uapi-preinit.c b/lib/kunit/uapi-preinit.c
new file mode 100644
index 0000000000000000000000000000000000000000..81182039965a8c93aebb2d5d76f4113bfef277a6
--- /dev/null
+++ b/lib/kunit/uapi-preinit.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace environment setup.
+ *
+ * Copyright (C) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@linutronix.de>
+ *
+ * This is *userspace* code.
+ */
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include "../../tools/testing/selftests/kselftest.h"
+
+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 = 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);
+
+ if (IS_ENABLED(CONFIG_DEVTMPFS)) {
+ 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;
+}
diff --git a/lib/kunit/uapi.c b/lib/kunit/uapi.c
index 121146dda533b3f90aca37c20bd0e7a1d20cb3b5..bccc081a6538507724c1ef340203cfd147170dc4 100644
--- a/lib/kunit/uapi.c
+++ b/lib/kunit/uapi.c
@@ -139,7 +139,7 @@ static int kunit_uapi_user_mode_thread_init(void *data)
kernel_sigaction(SIGABRT, SIG_DFL);

complete(&ctx->setup_done);
- ctx->exec_err = kernel_execve(ctx->executable, argv, NULL);
+ ctx->exec_err = kernel_execve(kbasename(BLOB(kunit_uapi_preinit)->path), argv, NULL);
if (!ctx->exec_err)
return 0;
do_exit(0);
@@ -239,6 +239,7 @@ static int kunit_uapi_run_executable_in_mount(struct kunit *test, const char *ex

static int kunit_uapi_run_executable(struct kunit *test, const struct blob *executable)
{
+ const struct blob *preinit = BLOB(kunit_uapi_preinit);
const char *exe_name = kbasename(executable->path);
struct vfsmount *mnt;
int err;
@@ -247,7 +248,13 @@ static int kunit_uapi_run_executable(struct kunit *test, const struct blob *exec
if (IS_ERR(mnt))
return PTR_ERR(mnt);

- err = kunit_uapi_write_file(mnt, exe_name, 0755, executable->data, blob_size(executable));
+ err = kunit_uapi_write_file(mnt, kbasename(preinit->path), 0755,
+ preinit->data,
+ blob_size(preinit));
+
+ if (!err)
+ err = kunit_uapi_write_file(mnt, exe_name, 0755,
+ executable->data, blob_size(executable));

if (!err)
err = kunit_uapi_run_executable_in_mount(test, exe_name, mnt);

--
2.49.0

Thomas Weißschuh

unread,
Jun 11, 2025, 3:38:41 AMJun 11
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org, Thomas Weißschuh
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.w...@linutronix.de>

---
Currently this depends on CONFIG_KUNIT=y as it uses some non-exported
symbols around process management.
---
Documentation/dev-tools/kunit/api/index.rst | 5 +
Documentation/dev-tools/kunit/api/uapi.rst | 12 ++
include/kunit/uapi.h | 24 +++
lib/kunit/Kconfig | 10 +
lib/kunit/Makefile | 2 +
lib/kunit/uapi.c | 287 ++++++++++++++++++++++++++++
6 files changed, 340 insertions(+)

diff --git a/Documentation/dev-tools/kunit/api/index.rst b/Documentation/dev-tools/kunit/api/index.rst
index 5cdb552a0808f25baeff5e47a9227b7b62c69e40..34d8fee9a97059d6da919a6fb1a7e359b5e0beef 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 0000000000000000000000000000000000000000..b4764424c629bf69194cf2786f52aef154b02bf8
--- /dev/null
+++ b/Documentation/dev-tools/kunit/api/uapi.rst
@@ -0,0 +1,12 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==================
+Userspace Test API
+==================
+
+This file documents all of the userspace testing API.
+Userspace tests should be built as :ref:`userprogs <kbuild_userprogs>` and included into the test
+module or kernel as :ref:`blobs <kbuild_blobs>`.
+
+.. kernel-doc:: include/kunit/uapi.h
+ :internal:
diff --git a/include/kunit/uapi.h b/include/kunit/uapi.h
new file mode 100644
index 0000000000000000000000000000000000000000..a6181790c96a42df05839097991c1fbfd889cdbe
--- /dev/null
+++ b/include/kunit/uapi.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * KUnit Userspace testing API.
+ *
+ * Copyright (C) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@linutronix.de>
+ */
+
+#ifndef _KUNIT_UAPI_H
+#define _KUNIT_UAPI_H
+
+struct blob;
+struct kunit;
+
+/**
+ * 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 blob *executable);
+
+#endif /* _KUNIT_UAPI_H */
diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig
index a97897edd9642f3e5df7fdd9dee26ee5cf00d6a4..1f2f5f2213a7d8438cd2683955f22e34f3a036dd 100644
--- a/lib/kunit/Kconfig
+++ b/lib/kunit/Kconfig
@@ -93,4 +93,14 @@ config KUNIT_AUTORUN_ENABLED
In most cases this should be left as Y. Only if additional opt-in
behavior is needed should this be set to N.

+config KUNIT_UAPI
+ def_bool y
+ depends on KUNIT=y
+ depends on CC_CAN_LINK_STATIC || ARCH_HAS_NOLIBC
+ select HEADERS_INSTALL
+ 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.
+
endif # KUNIT
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 656f1fa35abcc635e67d5b4cb1bc586b48415ac5..dafa09bd4241c24d31c4c19edecb67bf724127d7 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -12,6 +12,8 @@ kunit-objs += test.o \
device.o \
platform.o

+kunit-$(CONFIG_KUNIT_UAPI) += uapi.o
+
ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
kunit-objs += debugfs.o
endif
diff --git a/lib/kunit/uapi.c b/lib/kunit/uapi.c
new file mode 100644
index 0000000000000000000000000000000000000000..121146dda533b3f90aca37c20bd0e7a1d20cb3b5
--- /dev/null
+++ b/lib/kunit/uapi.c
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace testing API.
+ *
+ * Copyright (C) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@linutronix.de>
+ */
+
+#include <linux/binfmts.h>
+#include <linux/blob.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/types.h>
+
+#include <kunit/test.h>
+#include <kunit/uapi.h>
+
+#define KSFT_PASS 0
+#define KSFT_FAIL 1
+#define KSFT_XFAIL 2
+#define KSFT_XPASS 3
+#define KSFT_SKIP 4
+
+static struct vfsmount *kunit_uapi_mount_ramfs(void)
+{
+ struct file_system_type *type;
+ struct vfsmount *mnt;
+
+ type = get_fs_type("ramfs");
+ if (!type)
+ return ERR_PTR(-ENODEV);
+
+ /* FIXME
+ * The mount setup is supposed to look like this:
+ * kunit_uapi_mount_ramfs() sets up a private mount,
+ * with nothing visible except the new tmpfs.
+ * Then each executable execution gets a new namespace on top of that
+ * on which it can mount whatever it needs.
+ * However I didn't manage to set this up, so keep everything simple
+ * for now and let somebody familiar with the VFS figure this out.
+ */
+
+ mnt = kern_mount(type);
+ put_filesystem(type);
+
+ return mnt;
+}
+
+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;
+ }
+
+ /* Flush delayed fput so exec can open the file read-only */
+ flush_delayed_fput();
+
+ return 0;
+}
+
+struct kunit_uapi_user_mode_thread_ctx {
+ const char *executable;
+
+ /* Signals mnt, out, pwd and tgid */
+ struct completion setup_done;
+ struct vfsmount *mnt;
+ struct file *out;
+ struct path pwd;
+ pid_t tgid;
+
+ /* Valid after wait(tgid) */
+ int exec_err;
+};
+
+static int kunit_uapi_user_mode_thread_init(void *data)
+{
+ struct kunit_uapi_user_mode_thread_ctx *ctx = data;
+ const char *const argv[] = {
+ ctx->executable,
+ NULL
+ };
+ struct file *out[2];
+ int err;
+
+ err = create_pipe_files(out, 0);
+ if (err)
+ return err;
+
+ /* stdin, use the *write* end to the pipe to have an unreadable input */
+ err = replace_fd(0, out[1], 0);
+ if (err < 0) {
+ fput(out[0]);
+ fput(out[1]);
+ return err;
+ }
+
+ /* stdout */
+ err = replace_fd(1, out[1], 0);
+ if (err < 0) {
+ replace_fd(0, NULL, 0);
+ fput(out[0]);
+ fput(out[1]);
+ return err;
+ }
+
+ /* stderr */
+ err = replace_fd(2, out[1], 0);
+ if (err < 0) {
+ replace_fd(0, NULL, 0);
+ replace_fd(1, NULL, 0);
+ fput(out[0]);
+ fput(out[1]);
+ return err;
+ }
+
+ fput(out[1]);
+
+ ctx->out = out[0];
+ ctx->tgid = current->tgid;
+
+ set_fs_pwd(current->fs, &ctx->pwd);
+ kernel_sigaction(SIGKILL, SIG_DFL);
+ kernel_sigaction(SIGABRT, SIG_DFL);
+
+ complete(&ctx->setup_done);
+ ctx->exec_err = kernel_execve(ctx->executable, argv, NULL);
+ if (!ctx->exec_err)
+ return 0;
+ do_exit(0);
+}
+
+static size_t kunit_uapi_printk_subtest_lines(struct kunit *test, char *buf, size_t s)
+{
+ const char *ptr = buf, *newline;
+ size_t n;
+
+ while (s) {
+ newline = strnchr(ptr, s, '\n');
+ if (!newline)
+ break;
+
+ n = newline - ptr + 1;
+
+ kunit_log(KERN_INFO, test, KUNIT_SUBSUBTEST_INDENT "%.*s", (int)n, ptr);
+ ptr += n;
+ s -= n;
+ }
+
+ memmove(buf, ptr, s);
+
+ return s;
+}
+
+static int kunit_uapi_forward_to_printk(struct kunit *test, struct file *output)
+{
+ /*
+ * printk() automatically adds a newline after each message.
+ * Therefore only fully accumulated lines can be forwarded.
+ * Each line needs to fit into the buffer below.
+ */
+ char buf[512];
+ size_t s = 0;
+ ssize_t n;
+
+ while (1) {
+ n = kernel_read(output, buf + s, sizeof(buf) - s, NULL);
+ if (n <= 0)
+ return n;
+ s = kunit_uapi_printk_subtest_lines(test, buf, s + n);
+ }
+}
+
+static void kunit_uapi_kill_pid(pid_t pid)
+{
+ struct pid *p;
+
+ p = find_get_pid(pid);
+ kill_pid(p, SIGKILL, 1);
+ put_pid(p);
+}
+
+static int kunit_uapi_run_executable_in_mount(struct kunit *test, const char *executable,
+ struct vfsmount *mnt)
+{
+ struct kunit_uapi_user_mode_thread_ctx ctx = {
+ .setup_done = COMPLETION_INITIALIZER_ONSTACK(ctx.setup_done),
+ .executable = executable,
+ .pwd = {
+ .mnt = mnt,
+ .dentry = mnt->mnt_root,
+ },
+ };
+ int forward_err, wait_err, ret;
+ pid_t pid;
+
+ /* If SIGCHLD is ignored do_wait won't populate the status. */
+ kernel_sigaction(SIGCHLD, SIG_DFL);
+ pid = user_mode_thread(kunit_uapi_user_mode_thread_init, &ctx, SIGCHLD);
+ if (pid < 0) {
+ kernel_sigaction(SIGCHLD, SIG_IGN);
+ return pid;
+ }
+
+ wait_for_completion(&ctx.setup_done);
+
+ forward_err = kunit_uapi_forward_to_printk(test, ctx.out);
+ if (forward_err)
+ kunit_uapi_kill_pid(ctx.tgid);
+
+ wait_err = kernel_wait(ctx.tgid, &ret);
+
+ /* Restore default kernel sig handler */
+ kernel_sigaction(SIGCHLD, SIG_IGN);
+
+ if (ctx.exec_err)
+ return ctx.exec_err;
+ if (forward_err)
+ return forward_err;
+ if (wait_err < 0)
+ return wait_err;
+ return ret;
+}
+
+static int kunit_uapi_run_executable(struct kunit *test, const struct blob *executable)
+{
+ const char *exe_name = kbasename(executable->path);
+ struct vfsmount *mnt;
+ int err;
+
+ mnt = kunit_uapi_mount_ramfs();
+ if (IS_ERR(mnt))
+ return PTR_ERR(mnt);
+
+ err = kunit_uapi_write_file(mnt, exe_name, 0755, executable->data, blob_size(executable));
+
+ if (!err)
+ err = kunit_uapi_run_executable_in_mount(test, exe_name, mnt);
+
+ kern_unmount(mnt);
+
+ return err;
+}
+
+void kunit_uapi_run_kselftest(struct kunit *test, const struct blob *executable)
+{
+ u8 exit_code, exit_signal;
+ int err;
+
+ err = kunit_uapi_run_executable(test, executable);
+ if (err < 0)
+ KUNIT_FAIL(test, "Could not run test executable: %pe\n", ERR_PTR(err));
+
+ exit_code = err >> 8;
+ exit_signal = err & 0xff;
+
+ if (exit_signal)
+ KUNIT_FAIL(test, "kselftest exited with signal: %d\n", exit_signal);
+ else if (exit_code == KSFT_PASS)
+ ; /* Noop */
+ else if (exit_code == KSFT_FAIL)
+ KUNIT_FAIL(test, "kselftest exited with code KSFT_FAIL\n");
+ else if (exit_code == KSFT_XPASS)
+ KUNIT_FAIL(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(test, "kselftest exited with unknown exit code: %d\n", exit_code);
+}
+EXPORT_SYMBOL_GPL(kunit_uapi_run_kselftest);

--
2.49.0

Thomas Weißschuh

unread,
Jun 11, 2025, 3:38:41 AMJun 11
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org, Thomas Weißschuh
Show that the selftests are executed from a fairly "normal"
userspace context.

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

diff --git a/lib/kunit/kunit-example-uapi.c b/lib/kunit/kunit-example-uapi.c
index 4ce657050dd4a576632a41ca0309c4cb5134ce14..5e7a0f3b68f182c42b03e667567e66f02d8c2b86 100644
--- a/lib/kunit/kunit-example-uapi.c
+++ b/lib/kunit/kunit-example-uapi.c
@@ -8,13 +8,45 @@
* 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-example-u\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(4);
- ksft_test_result_pass("userspace test 1\n");
+ test_procfs();
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");

--
2.49.0

Thomas Weißschuh

unread,
Jun 11, 2025, 3:38:41 AMJun 11
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org, Thomas Weißschuh
Extend the example to show how to run a userspace executable.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
---
lib/kunit/Makefile | 9 ++++++++-
lib/kunit/kunit-example-test.c | 15 +++++++++++++++
lib/kunit/kunit-example-uapi.c | 22 ++++++++++++++++++++++
3 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index dafa09bd4241c24d31c4c19edecb67bf724127d7..e406a31df1df834a87961663de0b7921b59481c2 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -30,4 +30,11 @@ obj-$(CONFIG_KUNIT_TEST) += string-stream-test.o
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
+kunit-example-uapi-nolibc := $(CONFIG_ARCH_HAS_NOLIBC)
+blobs += kunit-example-uapi.blob.o
+
+obj-$(CONFIG_KUNIT_EXAMPLE_TEST) += kunit-example-mod.o
+kunit-example-mod-y += kunit-example-test.o
+kunit-example-mod-$(CONFIG_KUNIT_UAPI) += kunit-example-uapi.blob.o
diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c
index 3056d6bc705d0a8f196f0f4412e679dbb0e03114..b2681a6e047dfd6fea4a7cca60e81651d09c2eae 100644
--- a/lib/kunit/kunit-example-test.c
+++ b/lib/kunit/kunit-example-test.c
@@ -6,8 +6,11 @@
* Author: Brendan Higgins <brendan...@google.com>
*/

+#include <linux/blob.h>
+
#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
@@ -277,6 +280,17 @@ static void example_slow_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, 1 + 1, 2);
}

+/*
+ * This test shows the usage of UAPI tests.
+ */
+static void example_uapi_test(struct kunit *test)
+{
+ if (IS_ENABLED(CONFIG_KUNIT_UAPI))
+ kunit_uapi_run_kselftest(test, BLOB(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.
@@ -297,6 +311,7 @@ static struct kunit_case example_test_cases[] = {
KUNIT_CASE(example_priv_test),
KUNIT_CASE_PARAM(example_params_test, example_gen_params),
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 0000000000000000000000000000000000000000..4ce657050dd4a576632a41ca0309c4cb5134ce14
--- /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) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@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.49.0

Masahiro Yamada

unread,
Jun 16, 2025, 11:39:01 AMJun 16
to Thomas Weißschuh, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Wed, Jun 11, 2025 at 4:38 PM Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> Various subsystems embed non-code build artifacts into the kernel,
> for example the initramfs, /proc/config.gz, vDSO image, etc.
> Currently each user has their own implementation for that.
>
> Add a common "blob" framework to provide this functionality.
> It provides standard kbuild and C APIs to embed and later access non-code
> build artifacts into the kernel image or modules.
>
> Reviewed-by: Nicolas Schier <n.sc...@avm.de>
> Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>

Kbuild provides only a small set of syntaxes, yet it's flexible enough
to allow each Makefile to implement what it needs.
I aim to keep Kbuild scripts as simple as possible and avoid over-engineering.

Instead, you can implement this in lib/kunit/Makefile.kunit-uapi or somewhere.
That way, I do not have to be worried about what you do.

Also, your separate blob approach looks questionable to me.
In your approach, the blob (kunit-example-uapi.blob.o)
and the entry point (kunit-example-test.o) can be separate modules.
The entry point would be a small amount of boilerplate.
I would keep the user-program blob and its entry point in the same C file.
(and I may consider writing a macro for populating a blob + knit entry)



> ---
> Due to its closeness to kbuild this is currently added to its MAINTAINER entry.
> But I can also maintain it on its own.

Or, maybe do not add this.






--
Best Regards
Masahiro Yamada

Thomas Weißschuh

unread,
Jun 17, 2025, 3:51:03 AMJun 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Tue, Jun 17, 2025 at 12:38:21AM +0900, Masahiro Yamada wrote:
> On Wed, Jun 11, 2025 at 4:38 PM Thomas Weißschuh
> <thomas.w...@linutronix.de> wrote:
> >
> > Various subsystems embed non-code build artifacts into the kernel,
> > for example the initramfs, /proc/config.gz, vDSO image, etc.
> > Currently each user has their own implementation for that.
> >
> > Add a common "blob" framework to provide this functionality.
> > It provides standard kbuild and C APIs to embed and later access non-code
> > build artifacts into the kernel image or modules.
> >
> > Reviewed-by: Nicolas Schier <n.sc...@avm.de>
> > Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
>
> Kbuild provides only a small set of syntaxes, yet it's flexible enough
> to allow each Makefile to implement what it needs.
> I aim to keep Kbuild scripts as simple as possible and avoid over-engineering.
>
> Instead, you can implement this in lib/kunit/Makefile.kunit-uapi or somewhere.
> That way, I do not have to be worried about what you do.

The goal was to have a framework that can be used independently of KUnit,
for the usecases listed in the commit message (and a few unlisted ones).
But I can go with a more specific solution, too.

> Also, your separate blob approach looks questionable to me.

> In your approach, the blob (kunit-example-uapi.blob.o)
> and the entry point (kunit-example-test.o) can be separate modules.

Indeed, however I don't see the issue for this specific point.

> The entry point would be a small amount of boilerplate.
> I would keep the user-program blob and its entry point in the same C file.

A Makefile dependency between the C file and blob payload is also necessary.

> (and I may consider writing a macro for populating a blob + knit entry)

That is what I had in during my early development,
and I guess I'll go with it again.


Thomas

David Gow

unread,
Jun 20, 2025, 5:37:41 AMJun 20
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
Thanks very much for persisting with this, and sorry for the delayed response.

I've taken quite a liking to it: it'd definitely have made my life
easier more than once.

As a more general wrapping of selftests in KUnit tests, I do think
that there's still some risk of confusion as to when a KUnit UAPI test
makes sense versus a simple selftest. The UAPI tests are definitely
(IMO) easier to build and run, but won't be easier to debug, or to run
on an existing, non-test system as a part of troubleshooting (which
has been a complaint when selftests have been ported to KUnit in the
past).

Nevertheless, I'm pretty happy to have this be a part of KUnit, though
I have three slight reservations:
1. There's no real _user_ of this yet -- save for the small test of
/proc/self/comm in the example -- I'd like to see a real-world test
using this.
2. There's a fair bit of complexity here, and we're already a bit
behind with KUnit reviews. I'd love it if you could commit to helping
maintain the KUnit parts of this in MAINTAINERS.
3. We need to make sure that there's a clear understanding of when to
use this, versus in-kernel KUnit tests, versus kselftest. This'll
probably involve (a) making sure Shuah is on board -- or at least not
strongly opposed, and (b) updating
Documentation/dev-tools/testing-overview.rst.

But thanks very much -- it's working well in my testing here, and
running the tests is very pleasant.

Cheers,
-- David

David Gow

unread,
Jun 20, 2025, 5:37:55 AMJun 20
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Wed, 11 Jun 2025 at 15:38, Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> Currently there is no test validating the result reporting from nested
> tests. Add one, it will also be used to validate upcoming changes to the
> nested test parsing.
>
> Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> ---

This looks good, modulo a couple of minor suggestions below.

Regardless,
Reviewed-by: David Gow <davi...@google.com>

Cheers,
-- David

> tools/testing/kunit/kunit_tool_test.py | 9 +++++++++
> .../kunit/test_data/test_is_test_passed-failure-nested.log | 7 +++++++
> 2 files changed, 16 insertions(+)
>
> diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
> index bbba921e0eacb18663abfcabb2bccf330d8666f5..691cde9b030f7729128490c1bdb42ccee1967ad6 100755
> --- a/tools/testing/kunit/kunit_tool_test.py
> +++ b/tools/testing/kunit/kunit_tool_test.py
> @@ -165,6 +165,15 @@ class KUnitParserTest(unittest.TestCase):
> self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
> self.assertEqual(result.counts.errors, 0)
>
> + def test_parse_failed_nested_tests_log(self):
> + nested_log = test_data_path('test_is_test_passed-failure-nested.log')
> + with open(nested_log) as file:
> + result = kunit_parser.parse_run_tests(file.readlines(), stdout)
> + self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
> + self.assertEqual(result.counts.failed, 2)
> + self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[0].status)

Is it worth also testing the value of the nested test's result here? i.e.,
self.assertEqual(kunit_parser.TestStatus.FAILURE,
result.subtests[0].subtests[0].status)


> + self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[1].status)
> +
> def test_no_header(self):
> empty_log = test_data_path('test_is_test_passed-no_tests_run_no_header.log')
> with open(empty_log) as file:
> diff --git a/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
> new file mode 100644
> index 0000000000000000000000000000000000000000..835816e0a07715a514f5f5afab1b6250037feaf4
> --- /dev/null
> +++ b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
> @@ -0,0 +1,7 @@
> +KTAP version 1
> +1..2
> +not ok 1 subtest 1
> + KTAP version 1
> + 1..1
> + not ok 1 test 1
> +not ok 2 subtest 2

Having these named 'subtest 1' and 'test 1' is a bit confusing to me
(as it implies the outer tests are subtests of the inner ones, which
isn't right).

Could we either swap 'subtest' and 'test' here, or -- if we want to
preserve the match between 'subtest' here and the subtest in the
python code -- label the inner one something like 'subsubtest'?


>
> --
> 2.49.0
>

David Gow

unread,
Jun 20, 2025, 5:37:59 AMJun 20
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Wed, 11 Jun 2025 at 15:38, Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> If a subtest itself reports success, but the outer testcase fails,
> the whole testcase should be reported as a failure.
> However the status is recalculated based on the test counts,
> overwriting the outer test result.
> Synthesize a failed test in this case to make sure the failure is not
> swallowed.
>
> Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> ---

Hmm... this is definitely a nasty edge-case. I don't completely like
this solution, but none of the other options seem drastically better.

I think the more obvious options are either to _always_ count tests
alongside their subtests, or to _never_ do so, but acknowledge that
"test failed, but failure count is 0" is a valid option. But neither
of those are especially satisfying, either greatly inflating test
counts, or creating obvious contradictions.

So I'm tentatively in favour of this, but if anyone has a nicer way of
doing it, I'm all ears.

The implementation looks good. If we can add the explicit checks for
the sub(sub)test results as mentioned in the previous patch, that'd be
even better.

Reviewed-by: David Gow <davi...@google.com>
Could we add:
self.assertEqual(kunit_parser.TestStatus.SUCCESS,
result.subtests[0].subtests[0].status)

> self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[1].status)

and

self.assertEqual(kunit_parser.TestStatus.FAILURE,
result.subtests[1].subtests[0].status)

David Gow

unread,
Jun 20, 2025, 5:38:07 AMJun 20
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Wed, 11 Jun 2025 at 15:38, Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> Skipped tests reported by kselftest.h use a different format than KTAP,
> there is no explicit test name. Normally the test name is part of the
> free-form string after the SKIP keyword:
>
> ok 3 # SKIP test: some reason
>
> Extend the parser to handle those correctly. Use the free-form string as
> test name instead.
>
> Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> ---

Nice: this is a great improvement.

Reviewed-by: David Gow <davi...@google.com>

Cheers,
-- David


David Gow

unread,
Jun 20, 2025, 5:38:13 AMJun 20
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Wed, 11 Jun 2025 at 15:38, Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> 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.w...@linutronix.de>
> ---

Looks fine to me. I confess to not knowing much about the details of
Loongarch CPUs, though, so while it hasn't broken anything here, I
make no further guarantees.

Reviewed-by: David Gow <davi...@google.com>

Cheers,
-- David


David Gow

unread,
Jun 20, 2025, 5:47:54 AMJun 20
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Wed, 11 Jun 2025 at 15:38, Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> 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.w...@linutronix.de>
>
> ---

It feels to me like there are three features hidden in here:
- KUnit helpers for manipulating vfs files
- A way of having KUnit tests run userspace helpers
- The full framework for writing/running whole tests in userspace.

It's really the first two which excite me personally most -- as they
give us a sort-of inverse to the kselftest "helper module" paradigm --
so we can test things which are impossible to test from within
kernelspace. So maybe those APIs should be exposed separately (so a
test can be written mostly in kernel-space using the KUnit framework
APIs, and just call out to a helper where needed). But I'm happy for
them to stay private functions until we have a test which actually
needs them.


> Currently this depends on CONFIG_KUNIT=y as it uses some non-exported
> symbols around process management.

That's fine for now, IMHO, but will make it difficult to use this on,
e.g., Red Hat setups, where CONFIG_KUNIT=m. Hopefully we can resolve
this by exporting some of the symbols?


In general, I'm happy with the implementation here. The fs stuff
probably needs a closer look from someone who knows the vfs better
than me, though.

Nevertheless,
Reviewed-by: David Gow <davi...@google.com>

Cheers,
-- David

Maybe it's worth making this configurable separately? I could imagine
people wanting an easy way to build a kernel without all of the test
blobs built-in.

David Gow

unread,
Jun 20, 2025, 5:48:08 AMJun 20
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Wed, 11 Jun 2025 at 15:38, Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> Extend the example to show how to run a userspace executable.
>
> Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> ---

Reviewed-by: David Gow <davi...@google.com>

Cheers,
-- David



David Gow

unread,
Jun 20, 2025, 5:48:13 AMJun 20
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Wed, 11 Jun 2025 at 15:38, Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> An upcoming change will add 'userprogs' to the kunit subdirectory.
> For kbuild to properly clean up these build artifacts the subdirectory
> needs to be always processed.
>
> Pushing the special logic for hook.o into the kunit Makefile also makes the
> logic easier to understand.
>
> Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> ---

I'm quite happy with this.

Reviewed-by: David Gow <davi...@google.com>

Cheers,
-- David


> --
> You received this message because you are subscribed to the Google Groups "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to kunit-dev+...@googlegroups.com.
> To view this discussion visit https://groups.google.com/d/msgid/kunit-dev/20250611-kunit-kselftests-v3-11-55e3d148cbc6%40linutronix.de.

David Gow

unread,
Jun 20, 2025, 5:48:19 AMJun 20
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Wed, 11 Jun 2025 at 15:38, Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> 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.w...@linutronix.de>
> ---

Looks good and works here.

Reviewed-by: David Gow <davi...@google.com>

(Although, personally, _I wish_ it were more idiomatic to mount things
from kernelspace.)

Cheers,
-- David

David Gow

unread,
Jun 20, 2025, 5:48:22 AMJun 20
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Wed, 11 Jun 2025 at 15:38, Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> Show that the selftests are executed from a fairly "normal"
> userspace context.
>
> Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> ---

This is good. I'm not 100% sure the example test is the best place for
it, though.

Would it make more sense to either have this:
- in the main kunit test (since it's really _verifying_ the KUnit
environment, rather than documenting it)
- in a separate kunit-uapi test (if we want to keep some separation
between the UAPI and entirely in-kernel tests)
- in a separate procfs test (since it tests procfs functionality as
much as it's testing the KUnit environment)

Personally, my gut feeling is the main kunit-test is the best place
for this, even if it means spinning up a separate file is best here.

As for the actual implementation, though, that looks fine to me. A few
small comments below, but nothing particularly important.

Reviewed-by: David Gow <davi...@google.com>

Cheers,
-- David

Do we want to use TASK_COMM_LEN rather than hardcoding 16 below?

(And, if so, do we need something more complicated in case it's not 16?)

Thomas Weißschuh

unread,
Jun 20, 2025, 9:18:26 AMJun 20
to David Gow, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
Thanks for the review.

> I've taken quite a liking to it: it'd definitely have made my life
> easier more than once.
>
> As a more general wrapping of selftests in KUnit tests, I do think
> that there's still some risk of confusion as to when a KUnit UAPI test
> makes sense versus a simple selftest. The UAPI tests are definitely
> (IMO) easier to build and run, but won't be easier to debug, or to run
> on an existing, non-test system as a part of troubleshooting (which
> has been a complaint when selftests have been ported to KUnit in the
> past).

The tests I am currently running with this framework are actually real
kselftests. They primarily live in tools/testing/selftests/ but I have a
wrapper in the "real" source tree and also build as part of KUnit.
This gives the advantages of both systems.
FWIW, the KUnit UAPI tests still exist as regular binaries in the output
tree and can also be used on their own.

> Nevertheless, I'm pretty happy to have this be a part of KUnit, though
> I have three slight reservations:
> 1. There's no real _user_ of this yet -- save for the small test of
> /proc/self/comm in the example -- I'd like to see a real-world test
> using this.

As mentioned before I am using this with real kselftests.
So far I have plugged in:

* all of tools/testing/selftests/vDSO/
* all of tools/testing/selftests/timens/
* a bit of tools/testing/selftests/x86/
* a bit of tools/testing/selftests/timers/

The selftests require a few small changes but these are mostly to resolve
warnings introduced by the more struct userprogs CFLAGS.
Or make the tests compatible with nolibc by changing syscall constants
from the generic SYS_foo to the Linux UAPI variant __NR_foo.

If you want to take a look at the (very WIP) code:
https://git.kernel.org/pub/scm/linux/kernel/git/thomas.weissschuh/linux.git/log/?h=kunit-kselftests-integration

In addition, some extensions to nolibc and the vDSO selftest libraries were
necessary. But all of that has been upstreamed already.

> 2. There's a fair bit of complexity here, and we're already a bit
> behind with KUnit reviews. I'd love it if you could commit to helping
> maintain the KUnit parts of this in MAINTAINERS.

Ack. I'll add this in the next revision.

> 3. We need to make sure that there's a clear understanding of when to
> use this, versus in-kernel KUnit tests, versus kselftest. This'll
> probably involve (a) making sure Shuah is on board -- or at least not
> strongly opposed, and (b) updating
> Documentation/dev-tools/testing-overview.rst.

As mentioned above, I think for most testcases both can be used from the same
codebase. So far I don't have any other requirements, although I am fairly sure
those will come up at some point. Let's go there when necessary.

I talked to Shuah about the proposal before and she had a positive reaction.
But I still would be very happy to get more feedback from her, also about the
posted patches.

I'll also update testing-overview.rst.

> But thanks very much -- it's working well in my testing here, and
> running the tests is very pleasant.

Good to hear!

<snip>

Thomas Weißschuh

unread,
Jun 20, 2025, 9:20:13 AMJun 20
to David Gow, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
This should be result.subtests[1].subtests[0].status.
But Ack and done.

> > + self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[1].status)
> > +
> > def test_no_header(self):
> > empty_log = test_data_path('test_is_test_passed-no_tests_run_no_header.log')
> > with open(empty_log) as file:
> > diff --git a/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..835816e0a07715a514f5f5afab1b6250037feaf4
> > --- /dev/null
> > +++ b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
> > @@ -0,0 +1,7 @@
> > +KTAP version 1
> > +1..2
> > +not ok 1 subtest 1
> > + KTAP version 1
> > + 1..1
> > + not ok 1 test 1
> > +not ok 2 subtest 2
>
> Having these named 'subtest 1' and 'test 1' is a bit confusing to me
> (as it implies the outer tests are subtests of the inner ones, which
> isn't right).
>
> Could we either swap 'subtest' and 'test' here, or -- if we want to
> preserve the match between 'subtest' here and the subtest in the
> python code -- label the inner one something like 'subsubtest'?

Ack.

Thomas Weißschuh

unread,
Jun 20, 2025, 9:23:14 AMJun 20
to David Gow, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Fri, Jun 20, 2025 at 05:37:44PM +0800, David Gow wrote:
> On Wed, 11 Jun 2025 at 15:38, Thomas Weißschuh
> <thomas.w...@linutronix.de> wrote:
> >
> > If a subtest itself reports success, but the outer testcase fails,
> > the whole testcase should be reported as a failure.
> > However the status is recalculated based on the test counts,
> > overwriting the outer test result.
> > Synthesize a failed test in this case to make sure the failure is not
> > swallowed.
> >
> > Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> > ---
>
> Hmm... this is definitely a nasty edge-case. I don't completely like
> this solution, but none of the other options seem drastically better.
>
> I think the more obvious options are either to _always_ count tests
> alongside their subtests, or to _never_ do so, but acknowledge that
> "test failed, but failure count is 0" is a valid option. But neither
> of those are especially satisfying, either greatly inflating test
> counts, or creating obvious contradictions.
>
> So I'm tentatively in favour of this, but if anyone has a nicer way of
> doing it, I'm all ears.

Agreed, it is not great. I'd also be happy for better ideas.
Ack.

> and
>
> self.assertEqual(kunit_parser.TestStatus.FAILURE,
> result.subtests[1].subtests[0].status)

This is now already in the previous patch.

Thomas Weißschuh

unread,
Jun 20, 2025, 9:43:48 AMJun 20
to David Gow, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Fri, Jun 20, 2025 at 05:47:39PM +0800, David Gow wrote:
> On Wed, 11 Jun 2025 at 15:38, Thomas Weißschuh
> <thomas.w...@linutronix.de> wrote:
> >
> > 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.w...@linutronix.de>
> >
> > ---
>
> It feels to me like there are three features hidden in here:
> - KUnit helpers for manipulating vfs files
> - A way of having KUnit tests run userspace helpers
> - The full framework for writing/running whole tests in userspace.
>
> It's really the first two which excite me personally most -- as they
> give us a sort-of inverse to the kselftest "helper module" paradigm --
> so we can test things which are impossible to test from within
> kernelspace.

For me it is only the third feature that I really care about right now.
But I do expect users for the first two to pop up at some point and these are
obviously valid usecases.

> So maybe those APIs should be exposed separately (so a
> test can be written mostly in kernel-space using the KUnit framework
> APIs, and just call out to a helper where needed). But I'm happy for
> them to stay private functions until we have a test which actually
> needs them.

Agreed, let's expose it when there are users.

> > Currently this depends on CONFIG_KUNIT=y as it uses some non-exported
> > symbols around process management.
>
> That's fine for now, IMHO, but will make it difficult to use this on,
> e.g., Red Hat setups, where CONFIG_KUNIT=m. Hopefully we can resolve
> this by exporting some of the symbols?

I'll try to use the new EXPORT_SYMBOL_GPL_FOR_MODULES() on these symbols and
see what the maintainers say about it.

> In general, I'm happy with the implementation here. The fs stuff
> probably needs a closer look from someone who knows the vfs better
> than me, though.
>
> Nevertheless,
> Reviewed-by: David Gow <davi...@google.com>

Thanks

>
> Cheers,
> -- David
>
> > ---
> > Documentation/dev-tools/kunit/api/index.rst | 5 +
> > Documentation/dev-tools/kunit/api/uapi.rst | 12 ++
> > include/kunit/uapi.h | 24 +++
> > lib/kunit/Kconfig | 10 +
> > lib/kunit/Makefile | 2 +
> > lib/kunit/uapi.c | 287 ++++++++++++++++++++++++++++
> > 6 files changed, 340 insertions(+)

<snip>

Thomas Weißschuh

unread,
Jun 20, 2025, 9:50:24 AMJun 20
to David Gow, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, linux...@lists.infradead.org, work...@vger.kernel.org
On Fri, Jun 20, 2025 at 05:48:07PM +0800, David Gow wrote:
> On Wed, 11 Jun 2025 at 15:38, Thomas Weißschuh
> <thomas.w...@linutronix.de> wrote:
> >
> > Show that the selftests are executed from a fairly "normal"
> > userspace context.
> >
> > Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> > ---
>
> This is good. I'm not 100% sure the example test is the best place for
> it, though.
>
> Would it make more sense to either have this:
> - in the main kunit test (since it's really _verifying_ the KUnit
> environment, rather than documenting it)
> - in a separate kunit-uapi test (if we want to keep some separation
> between the UAPI and entirely in-kernel tests)
> - in a separate procfs test (since it tests procfs functionality as
> much as it's testing the KUnit environment)

Originally this change was really meant as an example for users.
But moving it into the main kunit test probably makes more sense.

> Personally, my gut feeling is the main kunit-test is the best place
> for this, even if it means spinning up a separate file is best here.

Ack.
TASK_COMM_LEN is not part of the UAPI headers.
But I don't think it can ever change.

Thomas Weißschuh

unread,
Jun 26, 2025, 2:10:21 AMJun 26
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, linu...@kvack.org, linux-...@vger.kernel.org
Based on v6.16-rc1.

Signed-off-by: Thomas Weißschuh <thomas.w...@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-kselft...@linutronix.de
Thomas Weißschuh (15):
kbuild: userprogs: avoid duplication of flags inherited from kernel
kbuild: userprogs: also inherit byte order and ABI from kernel
kbuild: doc: add label for userprogs section
init: re-add CONFIG_CC_CAN_LINK_STATIC
init: add nolibc build support
fs,fork,exit: export symbols necessary for KUnit UAPI support
kunit: tool: Add test for nested test result reporting
kunit: tool: Don't overwrite test status based on subtest counts
kunit: tool: Parse skipped tests from kselftest.h
kunit: Always descend into kunit directory during build
kunit: qemu_configs: loongarch: Enable LSX/LSAX
kunit: Introduce UAPI testing framework
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 +
Makefile | 7 +-
fs/exec.c | 2 +
fs/file.c | 1 +
fs/filesystems.c | 2 +
fs/fs_struct.c | 1 +
fs/pipe.c | 2 +
include/kunit/uapi.h | 77 ++++++
init/Kconfig | 7 +
init/Kconfig.nolibc | 15 +
init/Makefile.nolibc | 13 +
kernel/exit.c | 3 +
kernel/fork.c | 2 +
lib/Makefile | 4 -
lib/kunit/Kconfig | 14 +
lib/kunit/Makefile | 27 +-
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 | 23 +-
lib/kunit/kunit-uapi.c | 305 +++++++++++++++++++++
lib/kunit/uapi-preinit.c | 63 +++++
tools/testing/kunit/kunit_parser.py | 13 +-
tools/testing/kunit/kunit_tool_test.py | 11 +
tools/testing/kunit/qemu_configs/loongarch.py | 2 +
.../test_is_test_passed-failure-nested.log | 10 +
.../test_data/test_is_test_passed-kselftest.log | 3 +-
30 files changed, 714 insertions(+), 13 deletions(-)
---
base-commit: 9d5898b413d17510b2a41664a42390a2c79f8bf4

Thomas Weißschuh

unread,
Jun 26, 2025, 2:10:21 AMJun 26
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh
Some upcoming new documentation should link directly to the userprogs section.

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

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
---
Documentation/kbuild/makefiles.rst | 2 ++
1 file changed, 2 insertions(+)

diff --git a/Documentation/kbuild/makefiles.rst b/Documentation/kbuild/makefiles.rst
index 8aef3650c1f32b6b197e0dc777e26775d371a081..c14c1f632f6069c8751c8388a35bef539e19f9e8 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.50.0

Thomas Weißschuh

unread,
Jun 26, 2025, 2:10:22 AMJun 26
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh
For the kunit UAPI functionality this feature is needed.

This reverts commit d1b99cdf22e0 ("init: remove unused CONFIG_CC_CAN_LINK_STATIC")

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
---
init/Kconfig | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/init/Kconfig b/init/Kconfig
index af4c2f0854554bbcdf193852cf5c1d2c2accc64f..26cafbad4f1560fb56b4bef31ae29baf54175661 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -87,6 +87,11 @@ config CC_CAN_LINK
default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m64-flag)) if 64BIT
default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m32-flag))

+config CC_CAN_LINK_STATIC
+ bool
+ default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m64-flag) -static) if 64BIT
+ default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m32-flag) -static)
+
# 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

--
2.50.0

Thomas Weißschuh

unread,
Jun 26, 2025, 2:10:24 AMJun 26
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh
Currently there is no test validating the result reporting from nested
tests. Add one, it will also be used to validate upcoming changes to the
nested test parsing.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
Reviewed-by: David Gow <davi...@google.com>
---
tools/testing/kunit/kunit_tool_test.py | 10 ++++++++++
.../kunit/test_data/test_is_test_passed-failure-nested.log | 7 +++++++
2 files changed, 17 insertions(+)

diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index bbba921e0eacb18663abfcabb2bccf330d8666f5..b74dc05fc2fe5b3ff629172fc7aafeb5c3d29fb3 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -165,6 +165,16 @@ class KUnitParserTest(unittest.TestCase):
self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
self.assertEqual(result.counts.errors, 0)

+ def test_parse_failed_nested_tests_log(self):
+ nested_log = test_data_path('test_is_test_passed-failure-nested.log')
+ with open(nested_log) as file:
+ result = kunit_parser.parse_run_tests(file.readlines(), stdout)
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
+ self.assertEqual(result.counts.failed, 2)
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[0].status)
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[1].status)
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[1].subtests[0].status)
+
def test_no_header(self):
empty_log = test_data_path('test_is_test_passed-no_tests_run_no_header.log')
with open(empty_log) as file:
diff --git a/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
new file mode 100644
index 0000000000000000000000000000000000000000..2e528da39ab5b2be0fca6cf9160c10929fba3c9e
--- /dev/null
+++ b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
@@ -0,0 +1,7 @@
+KTAP version 1
+1..2
+not ok 1 subtest 1
+ KTAP version 1
+ 1..1
+ not ok 1 subsubtest 1
+not ok 2 subtest 2

--
2.50.0

Thomas Weißschuh

unread,
Jun 26, 2025, 2:10:24 AMJun 26
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh
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.w...@linutronix.de>
---
MAINTAINERS | 2 ++
init/Kconfig | 2 ++
init/Kconfig.nolibc | 15 +++++++++++++++
init/Makefile.nolibc | 13 +++++++++++++
4 files changed, 32 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index a92290fffa163f9fe8fe3f04bf66426f9a894409..e806158cc6798cf97a4aab58c038fb5351d469aa 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17702,6 +17702,8 @@ M: Willy Tarreau <w...@1wt.eu>
M: Thomas Weißschuh <li...@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 26cafbad4f1560fb56b4bef31ae29baf54175661..0af62f135192e0470e16eb6bb2fbb45ac38f4b81 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -92,6 +92,8 @@ config CC_CAN_LINK_STATIC
default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m64-flag) -static) if 64BIT
default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m32-flag) -static)

+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 0000000000000000000000000000000000000000..29cbc5437e70cbc5e256f00b74d0ab4801b40de7
--- /dev/null
+++ b/init/Kconfig.nolibc
@@ -0,0 +1,15 @@
+# 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 UML_X86
+ default y if X86
diff --git a/init/Makefile.nolibc b/init/Makefile.nolibc
new file mode 100644
index 0000000000000000000000000000000000000000..a8a193f78e34e0c4a6004e871bc206e06925f88a
--- /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 \
+ -isystem $(objtree)/usr/include -isystem $(srctree)/tools/include/nolibc/
+
+NOLIBC_USERLDFLAGS := -nostdlib -nostdinc -static
+
+endif # CONFIG_ARCH_HAS_NOLIBC && CONFIG_HEADERS_INSTALL

--
2.50.0

Thomas Weißschuh

unread,
Jun 26, 2025, 2:10:25 AMJun 26
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh
Skipped tests reported by kselftest.h use a different format than KTAP,
there is no explicit test name. Normally the test name is part of the
free-form string after the SKIP keyword:

ok 3 # SKIP test: some reason

Extend the parser to handle those correctly. Use the free-form string as
test name instead.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
Reviewed-by: David Gow <davi...@google.com>
---
tools/testing/kunit/kunit_parser.py | 8 +++++---
tools/testing/kunit/test_data/test_is_test_passed-kselftest.log | 3 ++-
2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
index 2478beb28fc3db825855ad46200340e884da7df1..4599d23c79b79f0e219d655c7053c8c3b34f8152 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
2.50.0

Thomas Weißschuh

unread,
Jun 26, 2025, 2:10:25 AMJun 26
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh
If a subtest itself reports success, but the outer testcase fails,
the whole testcase should be reported as a failure.
However the status is recalculated based on the test counts,
overwriting the outer test result.
Synthesize a failed test in this case to make sure the failure is not
swallowed.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
Reviewed-by: David Gow <davi...@google.com>
---
tools/testing/kunit/kunit_parser.py | 5 +++++
tools/testing/kunit/kunit_tool_test.py | 3 ++-
tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log | 3 +++
3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
index c176487356e6c94882046b19ea696d750905b8d5..2478beb28fc3db825855ad46200340e884da7df1 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -686,6 +686,11 @@ def bubble_up_test_results(test: Test) -> None:
counts.add_status(status)
elif test.counts.get_status() == TestStatus.TEST_CRASHED:
test.status = TestStatus.TEST_CRASHED
+ if not test.ok_status():
+ for t in subtests:
+ if not t.ok_status():
+ counts.add_status(t.status)
+ break

def parse_test(lines: LineStream, expected_num: int, log: List[str], is_subtest: bool, printer: Printer) -> Test:
"""
diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index b74dc05fc2fe5b3ff629172fc7aafeb5c3d29fb3..48a0dd0f9c87caf9f018aade161db90a613fc407 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -170,8 +170,9 @@ class KUnitParserTest(unittest.TestCase):
with open(nested_log) as file:
result = kunit_parser.parse_run_tests(file.readlines(), stdout)
self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
- self.assertEqual(result.counts.failed, 2)
+ self.assertEqual(result.counts.failed, 3)
self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[0].status)
+ self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.subtests[0].subtests[0].status)
self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[1].status)
self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[1].subtests[0].status)

diff --git a/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
index 2e528da39ab5b2be0fca6cf9160c10929fba3c9e..5498dfd0b0db24663e1a1e9bf78c587de6746522 100644
--- a/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
+++ b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
@@ -1,5 +1,8 @@
KTAP version 1
1..2
+ KTAP version 1
+ 1..1
+ ok 1 test 1
not ok 1 subtest 1
KTAP version 1
1..1

--
2.50.0

Thomas Weißschuh

unread,
Jun 26, 2025, 2:10:27 AMJun 26
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh
An upcoming change will add 'userprogs' to the kunit subdirectory.
For kbuild to properly clean up these build artifacts the subdirectory
needs to be always processed.

Pushing the special logic for hook.o into the kunit Makefile also makes the
logic easier to understand.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
Reviewed-by: David Gow <davi...@google.com>
---
lib/Makefile | 4 ----
lib/kunit/Makefile | 2 +-
2 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index c38582f187dd81916113319072e5cfef26f26c84..698566135091cc3bf0054f1954b434dc3325364a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -108,11 +108,7 @@ test_fpu-y := test_fpu_glue.o test_fpu_impl.o
CFLAGS_test_fpu_impl.o += $(CC_FLAGS_FPU)
CFLAGS_REMOVE_test_fpu_impl.o += $(CC_FLAGS_NO_FPU)

-# Some KUnit files (hooks.o) need to be built-in even when KUnit is a module,
-# so we can't just use obj-$(CONFIG_KUNIT).
-ifdef CONFIG_KUNIT
obj-y += kunit/
-endif

ifeq ($(CONFIG_DEBUG_KOBJECT),y)
CFLAGS_kobject.o += -DDEBUG
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 5aa51978e456ab3bb60c12071a26cf2bdcb1b508..656f1fa35abcc635e67d5b4cb1bc586b48415ac5 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -17,7 +17,7 @@ kunit-objs += debugfs.o
endif

# KUnit 'hooks' are built-in even when KUnit is built as a module.
-obj-y += hooks.o
+obj-$(if $(CONFIG_KUNIT),y) += hooks.o

obj-$(CONFIG_KUNIT_TEST) += kunit-test.o
obj-$(CONFIG_KUNIT_TEST) += platform-test.o

--
2.50.0

Thomas Weißschuh

unread,
Jun 26, 2025, 2:10:28 AMJun 26
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh
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.w...@linutronix.de>
Reviewed-by: David Gow <davi...@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 a92422967d1da9f1658ef1e80d0d7365ddbae307..1dba755284f11ffc94d8946105b0cfa49cb6f604 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.50.0

Thomas Weißschuh

unread,
Jun 26, 2025, 2:10:30 AMJun 26
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, linu...@kvack.org, linux-...@vger.kernel.org
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.w...@linutronix.de>

---
To: Kees Cook <ke...@kernel.org>
To: Alexander Viro <vi...@zeniv.linux.org.uk>
To: Christian Brauner <bra...@kernel.org>
To: Jan Kara <ja...@suse.cz>
Cc: linu...@kvack.org
Cc: linux-...@vger.kernel.org
---
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 | 14 ++
lib/kunit/Makefile | 2 +
lib/kunit/kunit-uapi.c | 300 ++++++++++++++++++++++++++++
7 files changed, 418 insertions(+)

diff --git a/Documentation/dev-tools/kunit/api/index.rst b/Documentation/dev-tools/kunit/api/index.rst
index 5cdb552a0808f25baeff5e47a9227b7b62c69e40..34d8fee9a97059d6da919a6fb1a7e359b5e0beef 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 0000000000000000000000000000000000000000..1f01b5c6c9db42f603f6507f2f33ef388f5b91d7
--- /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 e806158cc6798cf97a4aab58c038fb5351d469aa..0f60501c6de570723123b24eb930d15f1bd956eb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13540,6 +13540,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.w...@linutronix.de>
+S: Maintained
+F: include/kunit/uapi.h
+F: lib/kunit/kunit-uapi.c
+
KVM PARAVIRT (KVM/paravirt)
M: Paolo Bonzini <pbon...@redhat.com>
R: Vitaly Kuznetsov <vkuz...@redhat.com>
diff --git a/include/kunit/uapi.h b/include/kunit/uapi.h
new file mode 100644
index 0000000000000000000000000000000000000000..a5c923f5d82a91e0acd9dc17369f84f00b7d342f
--- /dev/null
+++ b/include/kunit/uapi.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * KUnit Userspace testing API.
+ *
+ * Copyright (C) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@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 a97897edd9642f3e5df7fdd9dee26ee5cf00d6a4..c88e6cf5610bc8246c94d16b9025461f0cd3b2d2 100644
--- a/lib/kunit/Kconfig
+++ b/lib/kunit/Kconfig
@@ -93,4 +93,18 @@ config KUNIT_AUTORUN_ENABLED
In most cases this should be left as Y. Only if additional opt-in
behavior is needed should this be set to N.

+config KUNIT_UAPI
+ tristate "KUnit UAPI testing framework"
+ depends on KUNIT
+ depends on CC_CAN_LINK_STATIC || ARCH_HAS_NOLIBC
+ depends on !LTO_CLANG # https://github.com/llvm/llvm-project/issues/112920
+ select HEADERS_INSTALL
+ 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 Y.
+
endif # KUNIT
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 656f1fa35abcc635e67d5b4cb1bc586b48415ac5..6059621a2d32c8e7384acda59793f05826af8c81 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 0000000000000000000000000000000000000000..cfe8440e16fde942a5f0fa7ac9d8ab90a737215b
--- /dev/null
+++ b/lib/kunit/kunit-uapi.c
@@ -0,0 +1,300 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace testing API.
+ *
+ * Copyright (C) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@linutronix.de>
+ */
+
+#include <linux/binfmts.h>
+#include <linux/export.h>
+
+ return 0;
+}
+
+static int kunit_uapi_write_executable(struct vfsmount *mnt,
+ const struct kunit_uapi_blob *executable)
+{
+ return kunit_uapi_write_file(mnt, kbasename(executable->path), 0755,
+ executable->data, executable->end - executable->data);
+ const struct kunit_uapi_blob *executable)
+{
+ const char *exe_name = kbasename(executable->path);
+ struct vfsmount *mnt;
+ int err;
+
+ mnt = kunit_uapi_mount_ramfs();
+ if (IS_ERR(mnt))
+ return PTR_ERR(mnt);
+
+ err = kunit_uapi_write_executable(mnt, executable);
+
+ if (!err)
+ err = kunit_uapi_run_executable_in_mount(test, exe_name, mnt);
+
+ kern_unmount(mnt);
+
+ return err;
+}
+
+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.w...@linutronix.de");
+MODULE_LICENSE("GPL");

--
2.50.0

Thomas Weißschuh

unread,
Jun 26, 2025, 2:10:31 AMJun 26
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh
Extend the example to show how to run a userspace executable.

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

diff --git a/MAINTAINERS b/MAINTAINERS
index 0f60501c6de570723123b24eb930d15f1bd956eb..b1405f0a0e638d1654d9dc9e51d784ddc838cf5b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13544,6 +13544,7 @@ KUNIT UAPI TESTING FRAMEWORK (in addition to KERNEL UNIT TESTING FRAMEWORK)
M: Thomas Weißschuh <thomas.w...@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 6059621a2d32c8e7384acda59793f05826af8c81..1bba7965613e36e26939d6b31e1d65acf5bad0dc 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,10 @@ 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
+$(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 3056d6bc705d0a8f196f0f4412e679dbb0e03114..0c5e1e59f9358b84aee2621e342d824a2f99f9aa 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
@@ -277,6 +278,19 @@ static void example_slow_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, 1 + 1, 2);
}

+/*
+ * 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.
@@ -297,6 +311,7 @@ static struct kunit_case example_test_cases[] = {
KUNIT_CASE(example_priv_test),
KUNIT_CASE_PARAM(example_params_test, example_gen_params),
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 0000000000000000000000000000000000000000..4ce657050dd4a576632a41ca0309c4cb5134ce14
--- /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) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@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.50.0

Thomas Weißschuh

unread,
Jun 26, 2025, 2:10:32 AMJun 26
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh
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.w...@linutronix.de>
Reviewed-by: David Gow <davi...@google.com>
---
MAINTAINERS | 1 +
lib/kunit/Makefile | 6 +++++
lib/kunit/kunit-uapi.c | 9 +++++--
lib/kunit/uapi-preinit.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index b1405f0a0e638d1654d9dc9e51d784ddc838cf5b..e81dfa180ab374ef91c7a45e546e6e9a8f454fa7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13546,6 +13546,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 <pbon...@redhat.com>
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 1bba7965613e36e26939d6b31e1d65acf5bad0dc..b50f3bc8bc7f3ade03be4900d9163d7a0d96863c 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -14,8 +14,14 @@ kunit-objs += test.o \
device.o \
platform.o

+userprogs += uapi-preinit
+uapi-preinit-userccflags += -static $(NOLIBC_USERCFLAGS) \
+ -include include/generated/autoconf.h \
+ -include $(srctree)/tools/include/linux/kconfig.h
obj-$(CONFIG_KUNIT_UAPI) += kunit-uapi.o

+$(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 cfe8440e16fde942a5f0fa7ac9d8ab90a737215b..7c87605b9ded9dbeb3968af8a8f4650ab5938887 100644
--- a/lib/kunit/kunit-uapi.c
+++ b/lib/kunit/kunit-uapi.c
@@ -25,6 +25,8 @@
#define KSFT_XPASS 3
#define KSFT_SKIP 4

+KUNIT_UAPI_EMBED_BLOB(kunit_uapi_preinit, "uapi-preinit");
+
static struct vfsmount *kunit_uapi_mount_ramfs(void)
{
struct file_system_type *type;
@@ -146,7 +148,7 @@ static int kunit_uapi_user_mode_thread_init(void *data)
kernel_sigaction(SIGABRT, SIG_DFL);

complete(&ctx->setup_done);
- ctx->exec_err = kernel_execve(ctx->executable, argv, NULL);
+ ctx->exec_err = kernel_execve(kbasename(kunit_uapi_preinit.path), argv, NULL);
if (!ctx->exec_err)
return 0;
do_exit(0);
@@ -255,7 +257,10 @@ static int kunit_uapi_run_executable(struct kunit *test,
if (IS_ERR(mnt))
return PTR_ERR(mnt);

- err = kunit_uapi_write_executable(mnt, executable);
+ err = kunit_uapi_write_executable(mnt, &kunit_uapi_preinit);
+
+ if (!err)
+ err = kunit_uapi_write_executable(mnt, executable);

if (!err)
err = kunit_uapi_run_executable_in_mount(test, exe_name, mnt);
diff --git a/lib/kunit/uapi-preinit.c b/lib/kunit/uapi-preinit.c
new file mode 100644
index 0000000000000000000000000000000000000000..81182039965a8c93aebb2d5d76f4113bfef277a6
--- /dev/null
+++ b/lib/kunit/uapi-preinit.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace environment setup.
+ *
+ * Copyright (C) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@linutronix.de>
+ *
+ * This is *userspace* code.
+ */
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include "../../tools/testing/selftests/kselftest.h"
+
+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;
+}
+
+
+ return 0;
+}

--
2.50.0

Thomas Weißschuh

unread,
Jun 26, 2025, 2:10:33 AMJun 26
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh
Show that the selftests are executed from a fairly "normal"
userspace context.

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

diff --git a/MAINTAINERS b/MAINTAINERS
index e81dfa180ab374ef91c7a45e546e6e9a8f454fa7..d86e8e0bfee75acecfeb9569d53ea8ea99727985 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13545,6 +13545,7 @@ M: Thomas Weißschuh <thomas.w...@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 b50f3bc8bc7f3ade03be4900d9163d7a0d96863c..25384e5c3c4cd1f92e4ec2c3830e0be1c6732ac1 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -30,6 +30,14 @@ 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
+$(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 0000000000000000000000000000000000000000..ec5395d809ee2a4bd3c47a573a576e2f98ef5c1b
--- /dev/null
+++ b/lib/kunit/kunit-test-uapi.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace selftest.
+ *
+ * Copyright (C) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@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 d9c781c859fde1f3623eb71b6829e82aa4803762..03972a3cb172d4af61bec17be800ddfb4bbd7268 100644
--- a/lib/kunit/kunit-test.c
+++ b/lib/kunit/kunit-test.c
@@ -8,6 +8,7 @@
#include "linux/gfp_types.h"
#include <kunit/test.h>
#include <kunit/test-bug.h>
+#include <kunit/uapi.h>

#include <linux/device.h>
#include <kunit/device.h>
@@ -868,10 +869,30 @@ static struct kunit_suite kunit_current_test_suite = {
.test_cases = kunit_current_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_fault_test_suite, &kunit_uapi_test_suite);

MODULE_DESCRIPTION("KUnit test for core test infrastructure");
MODULE_LICENSE("GPL v2");

--
2.50.0

Benjamin Berg

unread,
Jun 26, 2025, 2:11:35 PMJun 26
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, linu...@kvack.org, linux-...@vger.kernel.org
Hi Thomas,

I ran into two minor issues trying out the patches, see inline.

On Thu, 2025-06-26 at 08:10 +0200, Thomas Weißschuh wrote:
> 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.w...@linutronix.de>
>
> [SNIP]
For me, the compiler could not find the files for the ".incbin" unless
I added an include path. i.e. adding
ccflags-y := -I$(obj)
to lib/kunit/Makefile fixed the problem for me.

> [SNIP]
> +static int kunit_uapi_run_executable_in_mount(struct kunit *test, const char *executable,
> +    struct vfsmount *mnt)
> +{
> + struct kunit_uapi_user_mode_thread_ctx ctx = {
> + .setup_done = COMPLETION_INITIALIZER_ONSTACK(ctx.setup_done),
> + .executable = executable,
> + .pwd = {
> + .mnt = mnt,
> + .dentry = mnt->mnt_root,
> + },
> + };
> + int forward_err, wait_err, ret;

ret needs to be initialized to zero here as the kernel_wait function
will only set "ret" if wo.wo_stat is non-zero.

Benjamin

> [SNIP]

Thomas Weißschuh

unread,
Jun 27, 2025, 12:20:10 AMJun 27
to Benjamin Berg, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, linu...@kvack.org, linux-...@vger.kernel.org
Hi Benjamin,

On Thu, Jun 26, 2025 at 08:11:17PM +0200, Benjamin Berg wrote:
> I ran into two minor issues trying out the patches, see inline.

Thanks for testing the series.
Can you share some more details on your build setup?
This worked for me as-is and also passed 0day build testing.

> > [SNIP]
> > +static int kunit_uapi_run_executable_in_mount(struct kunit *test, const char *executable,
> > +    struct vfsmount *mnt)
> > +{
> > + struct kunit_uapi_user_mode_thread_ctx ctx = {
> > + .setup_done = COMPLETION_INITIALIZER_ONSTACK(ctx.setup_done),
> > + .executable = executable,
> > + .pwd = {
> > + .mnt = mnt,
> > + .dentry = mnt->mnt_root,
> > + },
> > + };
> > + int forward_err, wait_err, ret;
>
> ret needs to be initialized to zero here as the kernel_wait function
> will only set "ret" if wo.wo_stat is non-zero.

Ack.

> > [SNIP]


Thomas

Benjamin Berg

unread,
Jun 27, 2025, 2:59:04 AMJun 27
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, linu...@kvack.org, linux-...@vger.kernel.org
Hi,
Funny, I ran this on a Fedora 41 with gcc --version saying
gcc (GCC) 14.3.1 20250523 (Red Hat 14.3.1-1)

I tried both 32 and 64 bit builds for ARCH=um.

Attaching my current kernel configuration and the last few lines of a
V=1 build.

The kernel I used is a bit newer than what you had. Applied on top of
ee88bddf7f2f5d1f1da87dd7bedc734048b70e88 (bpf-fixes merge).

Benjamin
build.log
.config

Thomas Weißschuh

unread,
Jun 27, 2025, 4:27:44 AMJun 27
to Benjamin Berg, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, linu...@kvack.org, linux-...@vger.kernel.org
So this happens because you are building inside the source tree.
scripts/Makefile.lib has this block:

# $(src) for including checkin headers from generated source files
# $(obj) for including generated headers from checkin source files
ifdef building_out_of_srctree
_c_flags += $(addprefix -I, $(src) $(obj))
_a_flags += $(addprefix -I, $(src) $(obj))
_cpp_flags += $(addprefix -I, $(src) $(obj))
endif

Apparently GNU/clang assemblers don't look for .incbin/.include files next to
the including files [0].
In contrast, the ARM compiler does (at least according to its docs) [1].

Maybe we can work around this in the macro, but I assume this will become even
uglier. So for the next revision I'll use your proposal of explicit cflags.
Or if Masahiro prefers to have a more global and generic solution, we can do that.

[0] https://sourceware.org/binutils/docs/as/I.html
[1] https://developer.arm.com/documentation/dui0801/l/Directives-Reference/INCBIN


Thomas

Rae Moar

unread,
Jul 1, 2025, 5:12:12 PMJul 1
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org
On Thu, Jun 26, 2025 at 2:10 AM Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> If a subtest itself reports success, but the outer testcase fails,
> the whole testcase should be reported as a failure.
> However the status is recalculated based on the test counts,
> overwriting the outer test result.
> Synthesize a failed test in this case to make sure the failure is not
> swallowed.

Hello!

This is a very exciting patch series! However, I have a few concerns
with this patch.

When I parse the following KTAP with this change:

KTAP version 1
1..2
KTAP version 1
1..2
ok 1 test 1
not ok 2 test 2
not ok 1 subtest 1
KTAP version 1
1..1
not ok 1 subsubtest 1
not ok 2 subtest 2

The output is:

[20:54:12] ============================================================
[20:54:12] ======================= (2 subtests) =======================
[20:54:12] [PASSED] test 1
[20:54:12] [FAILED] test 2
[20:54:12] ==================== [FAILED] subtest 1 ====================
[20:54:12] ======================= (1 subtest) ========================
[20:54:12] [FAILED] subsubtest 1
[20:54:12] ==================== [FAILED] subtest 2 ====================
[20:54:12] ============================================================
[20:54:12] Testing complete. Ran 6 tests: passed: 1, failed: 5

This reports a total of 6 tests, which is not equivalent to the three
subtests plus the two suites. I believe this is because the change to
bubble_up_test_results below double counts the failed test case.

Historically, the KUnit parser only counts the results of test cases,
not the suites. I would like to stay as close to this as possible so
as to not inflate existing testing numbers. However, I believe the
main concern here is the case where if there is a suite reporting
failure but all subtests pass, it will not appear in the summary line.
For example,

KTAP version 1
1..1
KTAP version 1
1..1
ok 1 test 1
not ok 1 subtest 1

Reporting: All passing: Tests run: 1, passed: 1

This is absolutely an important edge case to cover. Therefore, we
should add 1 failure count to the suite count if the bubbled up
results indicate it should instead pass.

Thanks!
-Rae

>
> Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> Reviewed-by: David Gow <davi...@google.com>
> ---
> tools/testing/kunit/kunit_parser.py | 5 +++++
> tools/testing/kunit/kunit_tool_test.py | 3 ++-
> tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log | 3 +++
> 3 files changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
> index c176487356e6c94882046b19ea696d750905b8d5..2478beb28fc3db825855ad46200340e884da7df1 100644
> --- a/tools/testing/kunit/kunit_parser.py
> +++ b/tools/testing/kunit/kunit_parser.py
> @@ -686,6 +686,11 @@ def bubble_up_test_results(test: Test) -> None:
> counts.add_status(status)
> elif test.counts.get_status() == TestStatus.TEST_CRASHED:
> test.status = TestStatus.TEST_CRASHED
> + if not test.ok_status():
> + for t in subtests:
> + if not t.ok_status():
> + counts.add_status(t.status)
> + break

Here instead I recommend checking if not test.ok_status() and
test.counts.get_status() == TestStatus.SUCCESS and if so
counts.add_status(status)
> --
> You received this message because you are subscribed to the Google Groups "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to kunit-dev+...@googlegroups.com.
> To view this discussion visit https://groups.google.com/d/msgid/kunit-dev/20250626-kunit-kselftests-v4-8-48760534fef5%40linutronix.de.

Rae Moar

unread,
Jul 1, 2025, 5:22:20 PMJul 1
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org
On Thu, Jun 26, 2025 at 2:10 AM Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> Skipped tests reported by kselftest.h use a different format than KTAP,
> there is no explicit test name. Normally the test name is part of the
> free-form string after the SKIP keyword:
>
> ok 3 # SKIP test: some reason
>
> Extend the parser to handle those correctly. Use the free-form string as
> test name instead.

Hello!

I am happy to see that the kunit_parser will be used to parse
kselftest.h patches!

This patch looks pretty good to me! However, I do have one concern
where it does cause the parser to break.

Thanks!
-Rae

>
> Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> Reviewed-by: David Gow <davi...@google.com>
> ---
> tools/testing/kunit/kunit_parser.py | 8 +++++---
> tools/testing/kunit/test_data/test_is_test_passed-kselftest.log | 3 ++-
> 2 files changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
> index 2478beb28fc3db825855ad46200340e884da7df1..4599d23c79b79f0e219d655c7053c8c3b34f8152 100644
> --- a/tools/testing/kunit/kunit_parser.py
> +++ b/tools/testing/kunit/kunit_parser.py
> @@ -352,9 +352,9 @@ def parse_test_plan(lines: LineStream, test: Test) -> bool:
> lines.pop()
> return True
>
> -TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?([^#]*)( # .*)?$')
> +TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+)? ?(- )?([^#]*)( # .*)?$')
>
> -TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?(.*) # SKIP(.*)$')
> +TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+)? ?(- )?(.*) # SKIP ?(.*)$')

My concern with this patch is that this makes the test number optional
([0-9]+) -> ([0-9]+)? for both the test result regex matches. But if I
do pass in KTAP containing a line where the test number is missing, it
causes the parser to crash because other lines of the code rely on the
match with the test number.

I would prefer if we keep the test number as required. This is
integral to the KTAP specification and seems to be largely shared by
different frameworks test output.

Rae Moar

unread,
Jul 1, 2025, 5:27:07 PMJul 1
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org
On Thu, Jun 26, 2025 at 2:10 AM Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> Currently there is no test validating the result reporting from nested
> tests. Add one, it will also be used to validate upcoming changes to the
> nested test parsing.

Hello!

This patch looks good to me! However, most of the tests in
kunit-tool-test do check nested test output but we do lack checks for
failing tests. Could we change this commit description to be something
like: "Currently there is a lack of tests validating failed results
reporting from nested tests."?

Reviewed-by: Rae Moar <rm...@google.com>

Thanks!
-Rae

Thomas Weißschuh

unread,
Jul 1, 2025, 8:48:36 PMJul 1
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, linu...@kvack.org, linux-...@vger.kernel.org
The KUnit UAPI infrastructure starts userspace processes.
As it should be able to be built as a module, export the necessary symbols.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>

---
To: Kees Cook <ke...@kernel.org>
To: Alexander Viro <vi...@zeniv.linux.org.uk>
To: Christian Brauner <bra...@kernel.org>
To: Jan Kara <ja...@suse.cz>
Cc: linu...@kvack.org
Cc: linux-...@vger.kernel.org

./get_maintainer.pl would have also Cc-ed all of the memory management and
scheduler maintainers. I trimmed the list to only BINFMT/EXEC and VFS.
---
fs/exec.c | 2 ++
fs/file.c | 1 +
fs/filesystems.c | 2 ++
fs/fs_struct.c | 1 +
fs/pipe.c | 2 ++
kernel/exit.c | 3 +++
kernel/fork.c | 2 ++
7 files changed, 13 insertions(+)

diff --git a/fs/exec.c b/fs/exec.c
index 1f5fdd2e096e392b342f122d35aba4cf035441c7..13f7f27641942eddcb179bdd93d99b799d155813 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -68,6 +68,7 @@
#include <linux/user_events.h>
#include <linux/rseq.h>
#include <linux/ksm.h>
+#include <linux/export.h>

#include <linux/uaccess.h>
#include <asm/mmu_context.h>
@@ -1919,6 +1920,7 @@ int kernel_execve(const char *kernel_filename,
putname(filename);
return retval;
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(kernel_execve, "kunit-uapi");

static int do_execve(struct filename *filename,
const char __user *const __user *__argv,
diff --git a/fs/file.c b/fs/file.c
index 3a3146664cf37115624e12f7f06826d48827e9d7..89d07feb9c328337451ce40cb0f368b6cb986c2c 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -1317,6 +1317,7 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
spin_unlock(&files->file_lock);
return err;
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(replace_fd, "kunit-uapi");

/**
* receive_fd() - Install received file into file descriptor table
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 95e5256821a53494d88f496193305a2e50e04444..a3a588f387bbd8268246d1026389deaadf265d0b 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/fs_parser.h>
+#include <linux/export.h>

/*
* Handling of filesystem drivers list.
@@ -45,6 +46,7 @@ void put_filesystem(struct file_system_type *fs)
{
module_put(fs->owner);
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(put_filesystem, "kunit-uapi");

static struct file_system_type **find_filesystem(const char *name, unsigned len)
{
diff --git a/fs/fs_struct.c b/fs/fs_struct.c
index 64c2d0814ed6889cc12603410e6e9dc44089586f..26340d225deba3f2ec30252293fdf417235a6a4a 100644
--- a/fs/fs_struct.c
+++ b/fs/fs_struct.c
@@ -46,6 +46,7 @@ void set_fs_pwd(struct fs_struct *fs, const struct path *path)
if (old_pwd.dentry)
path_put(&old_pwd);
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(set_fs_pwd, "kunit-uapi");

static inline int replace_path(struct path *p, const struct path *old, const struct path *new)
{
diff --git a/fs/pipe.c b/fs/pipe.c
index 45077c37bad154ef146b047834d35d489fcc4d8d..d6cb743d2cfc041f08b498a5a764e9a96dc34069 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -27,6 +27,7 @@
#include <linux/watch_queue.h>
#include <linux/sysctl.h>
#include <linux/sort.h>
+#include <linux/export.h>

#include <linux/uaccess.h>
#include <asm/ioctls.h>
@@ -971,6 +972,7 @@ int create_pipe_files(struct file **res, int flags)
file_set_fsnotify_mode(res[1], FMODE_NONOTIFY_PERM);
return 0;
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(create_pipe_files, "kunit-uapi");

static int __do_pipe_flags(int *fd, struct file **files, int flags)
{
diff --git a/kernel/exit.c b/kernel/exit.c
index bd743900354ca5fc6c550f80e30393a632eb9a4e..610dffb1276ac60b475708587ca053f315fea9c3 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -70,6 +70,7 @@
#include <linux/user_events.h>
#include <linux/uaccess.h>
#include <linux/pidfs.h>
+#include <linux/export.h>

#include <uapi/linux/wait.h>

@@ -1005,6 +1006,7 @@ void __noreturn do_exit(long code)
lockdep_free_task(tsk);
do_task_dead();
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(do_exit, "kunit-uapi");

void __noreturn make_task_dead(int signr)
{
@@ -1887,6 +1889,7 @@ int kernel_wait(pid_t pid, int *stat)
put_pid(wo.wo_pid);
return ret;
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(kernel_wait, "kunit-uapi");

SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr,
int, options, struct rusage __user *, ru)
diff --git a/kernel/fork.c b/kernel/fork.c
index 1ee8eb11f38bae1d2eb6de9494aea94b7a19e6c3..5de7a9bc005ade6dcfbdfe1a63cadbef8782658c 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -105,6 +105,7 @@
#include <uapi/linux/pidfd.h>
#include <linux/pidfs.h>
#include <linux/tick.h>
+#include <linux/export.h>

#include <asm/pgalloc.h>
#include <linux/uaccess.h>
@@ -2676,6 +2677,7 @@ pid_t user_mode_thread(int (*fn)(void *), void *arg, unsigned long flags)

return kernel_clone(&args);
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(user_mode_thread, "kunit-uapi");

#ifdef __ARCH_WANT_SYS_FORK
SYSCALL_DEFINE0(fork)

--
2.50.0

Nicolas Schier

unread,
Jul 3, 2025, 10:00:38 AMJul 3
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org
On Thu, Jun 26, 2025 at 08:10:11AM +0200, Thomas Weißschuh wrote:
> Some upcoming new documentation should link directly to the userprogs section.
>
> Add a label to the section so it can be referenced.
>
> Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> ---
> Documentation/kbuild/makefiles.rst | 2 ++
> 1 file changed, 2 insertions(+)

Reviewed-by: Nicolas Schier <n.sc...@avm.de>
signature.asc

Nicolas Schier

unread,
Jul 3, 2025, 10:00:59 AMJul 3
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org
On Thu, Jun 26, 2025 at 08:10:12AM +0200, Thomas Weißschuh wrote:
> For the kunit UAPI functionality this feature is needed.
>
> This reverts commit d1b99cdf22e0 ("init: remove unused CONFIG_CC_CAN_LINK_STATIC")
>
> Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> ---
> init/Kconfig | 5 +++++
> 1 file changed, 5 insertions(+)

Reviewed-by: Nicolas Schier <n.sc...@avm.de>
signature.asc

Nicolas Schier

unread,
Jul 3, 2025, 10:01:19 AMJul 3
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org
On Thu, Jun 26, 2025 at 08:10:13AM +0200, Thomas Weißschuh wrote:
> 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.w...@linutronix.de>
> ---
> MAINTAINERS | 2 ++
> init/Kconfig | 2 ++
> init/Kconfig.nolibc | 15 +++++++++++++++
> init/Makefile.nolibc | 13 +++++++++++++
> 4 files changed, 32 insertions(+)

Reviewed-by: Nicolas Schier <n.sc...@avm.de>
signature.asc

Thomas Weißschuh

unread,
Jul 3, 2025, 11:30:06 AMJul 3
to Rae Moar, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org
On Tue, Jul 01, 2025 at 05:11:59PM -0400, Rae Moar wrote:
> On Thu, Jun 26, 2025 at 2:10 AM Thomas Weißschuh
> <thomas.w...@linutronix.de> wrote:
> >
> > If a subtest itself reports success, but the outer testcase fails,
> > the whole testcase should be reported as a failure.
> > However the status is recalculated based on the test counts,
> > overwriting the outer test result.
> > Synthesize a failed test in this case to make sure the failure is not
> > swallowed.
>
> This is a very exciting patch series! However, I have a few concerns
> with this patch.

Thanks for the review!
Makes sense.

> >
> > Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> > Reviewed-by: David Gow <davi...@google.com>
> > ---
> > tools/testing/kunit/kunit_parser.py | 5 +++++
> > tools/testing/kunit/kunit_tool_test.py | 3 ++-
> > tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log | 3 +++
> > 3 files changed, 10 insertions(+), 1 deletion(-)
> >
> > diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
> > index c176487356e6c94882046b19ea696d750905b8d5..2478beb28fc3db825855ad46200340e884da7df1 100644
> > --- a/tools/testing/kunit/kunit_parser.py
> > +++ b/tools/testing/kunit/kunit_parser.py
> > @@ -686,6 +686,11 @@ def bubble_up_test_results(test: Test) -> None:
> > counts.add_status(status)
> > elif test.counts.get_status() == TestStatus.TEST_CRASHED:
> > test.status = TestStatus.TEST_CRASHED
> > + if not test.ok_status():
> > + for t in subtests:
> > + if not t.ok_status():
> > + counts.add_status(t.status)
> > + break
>
> Here instead I recommend checking if not test.ok_status() and
> test.counts.get_status() == TestStatus.SUCCESS and if so
> counts.add_status(status)

Thanks for the recommendation. I tried this and it works well for this specific
testcase, but unfortunately all kinds of othes tests are now broken.
I'll look into it some more, but any hints are highly appreciated.
It has been a while since I looked at the code.

Thomas Weißschuh

unread,
Jul 3, 2025, 12:00:06 PMJul 3
to Rae Moar, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org
On Tue, Jul 01, 2025 at 05:22:07PM -0400, Rae Moar wrote:
> On Thu, Jun 26, 2025 at 2:10 AM Thomas Weißschuh
> <thomas.w...@linutronix.de> wrote:

<snip>

> > -TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?([^#]*)( # .*)?$')
> > +TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+)? ?(- )?([^#]*)( # .*)?$')
> >
> > -TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?(.*) # SKIP(.*)$')
> > +TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+)? ?(- )?(.*) # SKIP ?(.*)$')
>
> My concern with this patch is that this makes the test number optional
> ([0-9]+) -> ([0-9]+)? for both the test result regex matches. But if I
> do pass in KTAP containing a line where the test number is missing, it
> causes the parser to crash because other lines of the code rely on the
> match with the test number.
>
> I would prefer if we keep the test number as required. This is
> integral to the KTAP specification and seems to be largely shared by
> different frameworks test output.

This part of the patch was actually unnecessary, so I dropped it.
Good catch, thanks.

<snip>

Thomas Weißschuh

unread,
Jul 4, 2025, 8:55:42 AMJul 4
to Rae Moar, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org
Hi Rae,

On Thu, Jul 03, 2025 at 05:30:02PM +0200, Thomas Weißschuh wrote:
> On Tue, Jul 01, 2025 at 05:11:59PM -0400, Rae Moar wrote:

<snip>
The following variant passes all tests. What do you think?

diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
index 333cd3a4a56b..5338489dcbe4 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -689,6 +689,9 @@ def bubble_up_test_results(test: Test) -> None:
elif test.counts.get_status() == TestStatus.TEST_CRASHED:
test.status = TestStatus.TEST_CRASHED

+ if status == TestStatus.FAILURE and test.counts.get_status() == TestStatus.SUCCESS:
+ counts.add_status(status)
+

Masahiro Yamada

unread,
Jul 4, 2025, 5:56:08 PMJul 4
to Thomas Weißschuh, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org
Reviewed-by: Masahiro Yamada <masa...@kernel.org>



--
Best Regards
Masahiro Yamada

Masahiro Yamada

unread,
Jul 4, 2025, 5:56:37 PMJul 4
to Thomas Weißschuh, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org
On Thu, Jun 26, 2025 at 3:10 PM Thomas Weißschuh
<thomas.w...@linutronix.de> wrote:
>
> Some upcoming new documentation should link directly to the userprogs section.
>
> Add a label to the section so it can be referenced.
>
> Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
> ---
> Documentation/kbuild/makefiles.rst | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/Documentation/kbuild/makefiles.rst b/Documentation/kbuild/makefiles.rst
> index 8aef3650c1f32b6b197e0dc777e26775d371a081..c14c1f632f6069c8751c8388a35bef539e19f9e8 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


Acked-by: Masahiro Yamada <masa...@kernel.org>

Jonathan Corbet

unread,
Jul 7, 2025, 2:18:06 PMJul 7
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Thomas Weißschuh, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, linu...@kvack.org, linux-...@vger.kernel.org
Thomas Weißschuh <thomas.w...@linutronix.de> writes:

> 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.

Please forgive the possibly dumb question but ... this series sets up
the framework, but doesn't actually integrate the kselftests, right?
Will it be necessary to write a little KUnit glue function for each
kselftest, or is there some other scheme in mind here?

Thanks,

jon

Thomas Weißschuh

unread,
Jul 8, 2025, 1:51:10 AMJul 8
to Jonathan Corbet, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, linu...@kvack.org, linux-...@vger.kernel.org
On Mon, Jul 07, 2025 at 12:18:01PM -0600, Jonathan Corbet wrote:
> Thomas Weißschuh <thomas.w...@linutronix.de> writes:
>
> > 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.
>
> Please forgive the possibly dumb question but ... this series sets up
> the framework, but doesn't actually integrate the kselftests, right?

Correct.

> Will it be necessary to write a little KUnit glue function for each
> kselftest, or is there some other scheme in mind here?

With the current framework it is necessary to write some glue code:
* A stub .c file which #includes the existing kselftest source
* A kbuild userprog Makefile
* A custom KUnit function which calls kunit_uapi_run_kselftest()

A more high-level scheme may come later, but so far I have not worked on that.
It would be nice for example to build and run the tests for all ABIs supported
by a kernel without a lot of manual code duplication.
And maybe have some higher level helpers around declaring the tests.


Thomas

Muhammad Usama Anjum

unread,
Jul 12, 2025, 5:50:57 AMJul 12
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org
On 6/26/25 11:10 AM, Thomas WeiÃschuh wrote:
> 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.
From perspective of kselftests, I've liked the approach. Once we have an
automated way to run all the tests by some simple stubs, it would solve
the inherent problem of kselftests that it require different config options
enabled before tests can run. Hopefully, they would be auto enabled / disabled as
kernel config changes.

Acked-by: Muhammad Usama Anjum <usama...@collabora.com>
Positive error values are passed to strerror() without the - sign in userspace.
Probably - needs to be removed from strerror() here.

Thomas Weißschuh

unread,
Jul 17, 2025, 4:48:56 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
Make sure the byte order and ABI of the userprogs matches the one of the
kernel, similar to how the bit size is handled.
Otherwise the userprogs may not be executable.
This happens for example on powerpc little endian, or riscv32.

Reviewed-by: Nicolas Schier <n.sc...@avm.de>
Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
Acked-by: Masahiro Yamada <masa...@kernel.org>
---
Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index c4293cf91e968ca8ee64452841fb266e24df63f6..b9aa1058321dabd3b3dd5610e45a2807dfa257f4 100644
--- a/Makefile
+++ b/Makefile
@@ -1129,8 +1129,8 @@ ifneq ($(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS),)
LDFLAGS_vmlinux += --emit-relocs --discard-none
endif

-# Align the bit size of userspace programs with the kernel
-USERFLAGS_FROM_KERNEL := -m32 -m64 --target=%
+# Align the bit size, byte order and architecture of userspace programs with the kernel
+USERFLAGS_FROM_KERNEL := -m32 -m64 -mlittle-endian -mbig-endian --target=% -march=% -mabi=%
KBUILD_USERCFLAGS += $(filter $(USERFLAGS_FROM_KERNEL), $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS))
KBUILD_USERLDFLAGS += $(filter $(USERFLAGS_FROM_KERNEL), $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS))


--
2.50.0

Thomas Weißschuh

unread,
Jul 17, 2025, 4:48:56 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
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.
* Compatibility with kselftest_harness.h (in progress)
* 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

Based on v6.16-rc1.

Signed-off-by: Thomas Weißschuh <thomas.w...@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-kselft...@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-kselft...@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-kselft...@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-kselft...@linutronix.de

---
Thomas Weißschuh (15):
kbuild: userprogs: avoid duplication of flags inherited from kernel
kbuild: userprogs: also inherit byte order and ABI from kernel
kbuild: doc: add label for userprogs section
init: re-add CONFIG_CC_CAN_LINK_STATIC
init: add nolibc build support
fs,fork,exit: export symbols necessary for KUnit UAPI support
kunit: tool: Add test for nested test result reporting
kunit: tool: Don't overwrite test status based on subtest counts
kunit: tool: Parse skipped tests from kselftest.h
kunit: Always descend into kunit directory during build
kunit: qemu_configs: loongarch: Enable LSX/LSAX
kunit: Introduce UAPI testing framework
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 +
Makefile | 7 +-
fs/exec.c | 2 +
fs/file.c | 1 +
fs/filesystems.c | 2 +
fs/fs_struct.c | 1 +
fs/pipe.c | 2 +
include/kunit/uapi.h | 77 ++++++
init/Kconfig | 7 +
init/Kconfig.nolibc | 15 +
init/Makefile.nolibc | 13 +
kernel/exit.c | 3 +
kernel/fork.c | 2 +
lib/Makefile | 4 -
lib/kunit/Kconfig | 14 +
lib/kunit/Makefile | 30 +-
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 | 23 +-
lib/kunit/kunit-uapi.c | 305 +++++++++++++++++++++
lib/kunit/uapi-preinit.c | 63 +++++
tools/testing/kunit/kunit_parser.py | 11 +-
tools/testing/kunit/kunit_tool_test.py | 11 +
tools/testing/kunit/qemu_configs/loongarch.py | 2 +
.../test_is_test_passed-failure-nested.log | 10 +
.../test_data/test_is_test_passed-kselftest.log | 3 +-
30 files changed, 715 insertions(+), 13 deletions(-)
---
base-commit: 9d5898b413d17510b2a41664a42390a2c79f8bf4
change-id: 20241015-kunit-kselftests-56273bc40442

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

Thomas Weißschuh

unread,
Jul 17, 2025, 4:48:57 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
For the kunit UAPI functionality this feature is needed again.

Effectively revert commit d1b99cdf22e0 ("init: remove unused
CONFIG_CC_CAN_LINK_STATIC"), which removed the option.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
Reviewed-by: Nicolas Schier <n.sc...@avm.de>
Reviewed-by: Masahiro Yamada <masa...@kernel.org>

Thomas Weißschuh

unread,
Jul 17, 2025, 4:48:57 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
The duplication makes maintenance harder. Changes need to be done in two
places and the lines will grow overly long.

Use an intermediary variable instead.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
Reviewed-by: Nicolas Schier <n.sc...@avm.de>
Acked-by: Masahiro Yamada <masa...@kernel.org>
---
Makefile | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index 35e6e5240c61a8a329011929fcd0352b881dccdc..c4293cf91e968ca8ee64452841fb266e24df63f6 100644
--- a/Makefile
+++ b/Makefile
@@ -1130,8 +1130,9 @@ LDFLAGS_vmlinux += --emit-relocs --discard-none
endif

# Align the bit size of userspace programs with the kernel
-KBUILD_USERCFLAGS += $(filter -m32 -m64 --target=%, $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS))
-KBUILD_USERLDFLAGS += $(filter -m32 -m64 --target=%, $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS))
+USERFLAGS_FROM_KERNEL := -m32 -m64 --target=%
+KBUILD_USERCFLAGS += $(filter $(USERFLAGS_FROM_KERNEL), $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS))
+KBUILD_USERLDFLAGS += $(filter $(USERFLAGS_FROM_KERNEL), $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS))

# userspace programs are linked via the compiler, use the correct linker
ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_LD_IS_LLD),yy)

--
2.50.0

Thomas Weißschuh

unread,
Jul 17, 2025, 4:48:57 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
Some upcoming documentation will link directly to the userprogs section.

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

Reviewed-by: Nicolas Schier <n.sc...@avm.de>
Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
Acked-by: Masahiro Yamada <masa...@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 8aef3650c1f32b6b197e0dc777e26775d371a081..c14c1f632f6069c8751c8388a35bef539e19f9e8 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.50.0

Thomas Weißschuh

unread,
Jul 17, 2025, 4:48:58 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
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.

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

diff --git a/MAINTAINERS b/MAINTAINERS
index a92290fffa163f9fe8fe3f04bf66426f9a894409..e806158cc6798cf97a4aab58c038fb5351d469aa 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17702,6 +17702,8 @@ M: Willy Tarreau <w...@1wt.eu>
M: Thomas Weißschuh <li...@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 26cafbad4f1560fb56b4bef31ae29baf54175661..0af62f135192e0470e16eb6bb2fbb45ac38f4b81 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -92,6 +92,8 @@ config CC_CAN_LINK_STATIC
default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m64-flag) -static) if 64BIT
default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m32-flag) -static)

+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 0000000000000000000000000000000000000000..29cbc5437e70cbc5e256f00b74d0ab4801b40de7
--- /dev/null
+++ b/init/Kconfig.nolibc
@@ -0,0 +1,15 @@
+# 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 UML_X86
+ default y if X86
diff --git a/init/Makefile.nolibc b/init/Makefile.nolibc
new file mode 100644
index 0000000000000000000000000000000000000000..dacc78ab4c81c93f3a24ebeb70e34253842f9a53
--- /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.50.0

Thomas Weißschuh

unread,
Jul 17, 2025, 4:48:59 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
The KUnit UAPI infrastructure starts userspace processes.
As it should be able to be built as a module, export the necessary symbols.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>

---
For details on how these are used, see patch 12:
"kunit: Introduce UAPI testing framework".
Any ideas on how to make this work without new exports are very welcome.
---
fs/exec.c | 2 ++
fs/file.c | 1 +
fs/filesystems.c | 2 ++
fs/fs_struct.c | 1 +

Thomas Weißschuh

unread,
Jul 17, 2025, 4:49:00 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
If a subtest itself reports success, but the outer testcase fails,
the whole testcase should be reported as a failure.
However the status is recalculated based on the test counts,
overwriting the outer test result.
Synthesize a failed test in this case to make sure the failure is not
swallowed.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
Reviewed-by: David Gow <davi...@google.com>
---
tools/testing/kunit/kunit_parser.py | 3 +++
tools/testing/kunit/kunit_tool_test.py | 1 +
tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log | 3 +++
3 files changed, 7 insertions(+)

diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
index c176487356e6c94882046b19ea696d750905b8d5..a7a61e627e348db14b953080ec8789994fba955a 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -687,6 +687,9 @@ def bubble_up_test_results(test: Test) -> None:
elif test.counts.get_status() == TestStatus.TEST_CRASHED:
test.status = TestStatus.TEST_CRASHED

+ if status == TestStatus.FAILURE and test.counts.get_status() == TestStatus.SUCCESS:
+ counts.add_status(status)
+
def parse_test(lines: LineStream, expected_num: int, log: List[str], is_subtest: bool, printer: Printer) -> Test:
"""
Finds next test to parse in LineStream, creates new Test object,
diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index b74dc05fc2fe5b3ff629172fc7aafeb5c3d29fb3..d5bbcb95ab6abb1a8ee91439d87daaf29d159294 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -172,6 +172,7 @@ class KUnitParserTest(unittest.TestCase):
self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
self.assertEqual(result.counts.failed, 2)

Thomas Weißschuh

unread,
Jul 17, 2025, 4:49:00 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
Currently there is a lack of tests validating the result reporting from
nested tests. Add one, it will also be used to validate upcoming changes
to the nested test parsing.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
Reviewed-by: David Gow <davi...@google.com>
Reviewed-by: Rae Moar <rm...@google.com>
---
tools/testing/kunit/kunit_tool_test.py | 10 ++++++++++
.../kunit/test_data/test_is_test_passed-failure-nested.log | 7 +++++++
2 files changed, 17 insertions(+)

diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index bbba921e0eacb18663abfcabb2bccf330d8666f5..b74dc05fc2fe5b3ff629172fc7aafeb5c3d29fb3 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -165,6 +165,16 @@ class KUnitParserTest(unittest.TestCase):
self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
self.assertEqual(result.counts.errors, 0)

+ def test_parse_failed_nested_tests_log(self):
+ nested_log = test_data_path('test_is_test_passed-failure-nested.log')
+ with open(nested_log) as file:
+ result = kunit_parser.parse_run_tests(file.readlines(), stdout)
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
+ self.assertEqual(result.counts.failed, 2)
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[0].status)
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[1].status)
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.subtests[1].subtests[0].status)
+
def test_no_header(self):
empty_log = test_data_path('test_is_test_passed-no_tests_run_no_header.log')
with open(empty_log) as file:
diff --git a/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
new file mode 100644
index 0000000000000000000000000000000000000000..2e528da39ab5b2be0fca6cf9160c10929fba3c9e
--- /dev/null
+++ b/tools/testing/kunit/test_data/test_is_test_passed-failure-nested.log
@@ -0,0 +1,7 @@
+KTAP version 1
+1..2
+not ok 1 subtest 1
+ KTAP version 1
+ 1..1

Thomas Weißschuh

unread,
Jul 17, 2025, 4:49:01 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
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.w...@linutronix.de>
Reviewed-by: David Gow <davi...@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 a92422967d1da9f1658ef1e80d0d7365ddbae307..1dba755284f11ffc94d8946105b0cfa49cb6f604 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.50.0

Thomas Weißschuh

unread,
Jul 17, 2025, 4:49:01 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
Skipped tests reported by kselftest.h use a different format than KTAP,
there is no explicit test name. Normally the test name is part of the
free-form string after the SKIP keyword:

ok 3 # SKIP test: some reason

Extend the parser to handle those correctly. Use the free-form string as
test name instead.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
Reviewed-by: David Gow <davi...@google.com>
---
tools/testing/kunit/kunit_parser.py | 8 +++++---
tools/testing/kunit/test_data/test_is_test_passed-kselftest.log | 3 ++-
2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
index a7a61e627e348db14b953080ec8789994fba955a..5338489dcbe48c01912c5e8f02a481d6860a5d15 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -352,9 +352,9 @@ def parse_test_plan(lines: LineStream, test: Test) -> bool:
lines.pop()
return True

-TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?([^#]*)( # .*)?$')
+TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(- )?([^#]*)( # .*)?$')

-TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?(.*) # SKIP(.*)$')
+TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(- )?(.*) # SKIP ?(.*)$')

Thomas Weißschuh

unread,
Jul 17, 2025, 4:49:02 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
An upcoming change will add 'userprogs' to the kunit subdirectory.
For kbuild to properly clean up these build artifacts the subdirectory
needs to be always processed.

Pushing the special logic for hook.o into the kunit Makefile also makes the
logic easier to understand.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
Reviewed-by: David Gow <davi...@google.com>
---
lib/Makefile | 4 ----
lib/kunit/Makefile | 2 +-
2 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index c38582f187dd81916113319072e5cfef26f26c84..698566135091cc3bf0054f1954b434dc3325364a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -108,11 +108,7 @@ test_fpu-y := test_fpu_glue.o test_fpu_impl.o
CFLAGS_test_fpu_impl.o += $(CC_FLAGS_FPU)
CFLAGS_REMOVE_test_fpu_impl.o += $(CC_FLAGS_NO_FPU)

-# Some KUnit files (hooks.o) need to be built-in even when KUnit is a module,
-# so we can't just use obj-$(CONFIG_KUNIT).
-ifdef CONFIG_KUNIT
obj-y += kunit/
-endif

ifeq ($(CONFIG_DEBUG_KOBJECT),y)
CFLAGS_kobject.o += -DDEBUG
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 5aa51978e456ab3bb60c12071a26cf2bdcb1b508..656f1fa35abcc635e67d5b4cb1bc586b48415ac5 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -17,7 +17,7 @@ kunit-objs += debugfs.o
endif

# KUnit 'hooks' are built-in even when KUnit is built as a module.
-obj-y += hooks.o
+obj-$(if $(CONFIG_KUNIT),y) += hooks.o

obj-$(CONFIG_KUNIT_TEST) += kunit-test.o
obj-$(CONFIG_KUNIT_TEST) += platform-test.o

--
2.50.0

Thomas Weißschuh

unread,
Jul 17, 2025, 4:49:03 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
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.w...@linutronix.de>

---
This is similar to the usermode helper framework, but not using it as there
would be some issues. It gets neutered by CONFIG_STATIC_USERMODEHELPER_PATH.
That could be worked around by overriding sub_info->path, but that would be
a hack. Also it does not allow the implementation of a custom wait routine
to forward the process output to KUnit as implemented in
kunit_uapi_forward_to_printk(). That may be solved by adding another thread,
or messing with the internals of the framework, but that would also be ugly.
---
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 | 14 ++
lib/kunit/Makefile | 2 +
lib/kunit/kunit-uapi.c | 300 ++++++++++++++++++++++++++++
7 files changed, 418 insertions(+)

diff --git a/Documentation/dev-tools/kunit/api/index.rst b/Documentation/dev-tools/kunit/api/index.rst
index 5cdb552a0808f25baeff5e47a9227b7b62c69e40..34d8fee9a97059d6da919a6fb1a7e359b5e0beef 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 0000000000000000000000000000000000000000..1f01b5c6c9db42f603f6507f2f33ef388f5b91d7
--- /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 e806158cc6798cf97a4aab58c038fb5351d469aa..0f60501c6de570723123b24eb930d15f1bd956eb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13540,6 +13540,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.w...@linutronix.de>
+S: Maintained
+F: include/kunit/uapi.h
+F: lib/kunit/kunit-uapi.c
+
KVM PARAVIRT (KVM/paravirt)
M: Paolo Bonzini <pbon...@redhat.com>
R: Vitaly Kuznetsov <vkuz...@redhat.com>
diff --git a/include/kunit/uapi.h b/include/kunit/uapi.h
new file mode 100644
index 0000000000000000000000000000000000000000..a5c923f5d82a91e0acd9dc17369f84f00b7d342f
--- /dev/null
+++ b/include/kunit/uapi.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * KUnit Userspace testing API.
+ *
+ * Copyright (C) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@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 a97897edd9642f3e5df7fdd9dee26ee5cf00d6a4..c88e6cf5610bc8246c94d16b9025461f0cd3b2d2 100644
--- a/lib/kunit/Kconfig
+++ b/lib/kunit/Kconfig
@@ -93,4 +93,18 @@ config KUNIT_AUTORUN_ENABLED
In most cases this should be left as Y. Only if additional opt-in
behavior is needed should this be set to N.

+config KUNIT_UAPI
+ tristate "KUnit UAPI testing framework"
+ depends on KUNIT
+ depends on CC_CAN_LINK_STATIC || ARCH_HAS_NOLIBC
+ depends on !LTO_CLANG # https://github.com/llvm/llvm-project/issues/112920
+ select HEADERS_INSTALL
+ 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 Y.
+
endif # KUNIT
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 656f1fa35abcc635e67d5b4cb1bc586b48415ac5..6059621a2d32c8e7384acda59793f05826af8c81 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 0000000000000000000000000000000000000000..24356f68eca0df07032fb8a9e92daffde01b21d3
--- /dev/null
+++ b/lib/kunit/kunit-uapi.c
@@ -0,0 +1,300 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace testing API.
+ *
+ * Copyright (C) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@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/types.h>
+
+#include <kunit/test.h>
+#include <kunit/uapi.h>
+
+#define KSFT_PASS 0
+#define KSFT_FAIL 1
+#define KSFT_XFAIL 2
+#define KSFT_XPASS 3
+#define KSFT_SKIP 4
+
+static struct vfsmount *kunit_uapi_mount_ramfs(void)
+{
+ struct file_system_type *type;
+ struct vfsmount *mnt;
+
+ type = get_fs_type("ramfs");
+ if (!type)
+ return ERR_PTR(-ENODEV);
+
+ /* FIXME
+ * The mount setup is supposed to look like this:
+ * kunit_uapi_mount_ramfs() sets up a private mount,
+ * with nothing visible except the new tmpfs.
+ * Then each executable execution gets a new namespace on top of that
+ * on which it can mount whatever it needs.
+ * However I didn't manage to set this up, so keep everything simple
+ * for now and let somebody familiar with the VFS figure this out.
+ */
+
+ mnt = kern_mount(type);
+ put_filesystem(type);
+
+ return mnt;
+}
+
+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;
+ }
+
+ /* Flush delayed fput so exec can open the file read-only */
+ flush_delayed_fput();
+
+ return 0;
+}
+
+static int kunit_uapi_write_executable(struct vfsmount *mnt,
+ const struct kunit_uapi_blob *executable)
+{
+ return kunit_uapi_write_file(mnt, kbasename(executable->path), 0755,
+ executable->data, executable->end - executable->data);
+}
+
+struct kunit_uapi_user_mode_thread_ctx {
+ const char *executable;
+
+ /* Signals mnt, out, pwd and tgid */
+ struct completion setup_done;
+ struct vfsmount *mnt;
+ struct file *out;
+ struct path pwd;
+ pid_t tgid;
+
+ /* Valid after wait(tgid) */
+ int exec_err;
+};
+
+static int kunit_uapi_user_mode_thread_init(void *data)
+{
+ struct kunit_uapi_user_mode_thread_ctx *ctx = data;
+ const char *const argv[] = {
+ ctx->executable,
+ NULL
+ };
+ struct file *out[2];
+ int err;
+
+ err = create_pipe_files(out, 0);
+ if (err)
+ return err;
+
+ /* stdin, use the *write* end to the pipe to have an unreadable input */
+ err = replace_fd(0, out[1], 0);
+ if (err < 0) {
+ fput(out[0]);
+ fput(out[1]);
+ return err;
+ }
+
+ /* stdout */
+ err = replace_fd(1, out[1], 0);
+ if (err < 0) {
+ replace_fd(0, NULL, 0);
+ fput(out[0]);
+ fput(out[1]);
+ return err;
+ }
+
+ /* stderr */
+ err = replace_fd(2, out[1], 0);
+ if (err < 0) {
+ replace_fd(0, NULL, 0);
+ replace_fd(1, NULL, 0);
+ fput(out[0]);
+ fput(out[1]);
+ return err;
+ }
+
+ fput(out[1]);
+
+ ctx->out = out[0];
+ ctx->tgid = current->tgid;
+
+ set_fs_pwd(current->fs, &ctx->pwd);
+ kernel_sigaction(SIGKILL, SIG_DFL);
+ kernel_sigaction(SIGABRT, SIG_DFL);
+
+ complete(&ctx->setup_done);
+ ctx->exec_err = kernel_execve(ctx->executable, argv, NULL);
+ if (!ctx->exec_err)
+ return 0;
+ do_exit(0);
+}
+
+static size_t kunit_uapi_printk_subtest_lines(struct kunit *test, char *buf, size_t s)
+{
+ const char *ptr = buf, *newline;
+ size_t n;
+
+ while (s) {
+ newline = strnchr(ptr, s, '\n');
+ if (!newline)
+ break;
+
+ n = newline - ptr + 1;
+
+ kunit_log(KERN_INFO, test, KUNIT_SUBSUBTEST_INDENT "%.*s", (int)n, ptr);
+ ptr += n;
+ s -= n;
+ }
+
+ memmove(buf, ptr, s);
+
+ return s;
+}
+
+static int kunit_uapi_forward_to_printk(struct kunit *test, struct file *output)
+{
+ /*
+ * printk() automatically adds a newline after each message.
+ * Therefore only fully accumulated lines can be forwarded.
+ * Each line needs to fit into the buffer below.
+ */
+ char buf[512];
+ size_t s = 0;
+ ssize_t n;
+
+ while (1) {
+ n = kernel_read(output, buf + s, sizeof(buf) - s, NULL);
+ if (n <= 0)
+ return n;
+ s = kunit_uapi_printk_subtest_lines(test, buf, s + n);
+ }
+}
+
+static void kunit_uapi_kill_pid(pid_t pid)
+{
+ struct pid *p;
+
+ p = find_get_pid(pid);
+ kill_pid(p, SIGKILL, 1);
+ put_pid(p);
+}
+
+static int kunit_uapi_run_executable_in_mount(struct kunit *test, const char *executable,
+ struct vfsmount *mnt)
+{
+ struct kunit_uapi_user_mode_thread_ctx ctx = {
+ .setup_done = COMPLETION_INITIALIZER_ONSTACK(ctx.setup_done),
+ .executable = executable,
+ .pwd = {
+ .mnt = mnt,
+ .dentry = mnt->mnt_root,
+ },
+ };
+ int forward_err, wait_err, ret = 0;
+ pid_t pid;
+
+ /* If SIGCHLD is ignored do_wait won't populate the status. */
+ kernel_sigaction(SIGCHLD, SIG_DFL);
+ pid = user_mode_thread(kunit_uapi_user_mode_thread_init, &ctx, SIGCHLD);
+ if (pid < 0) {
+ kernel_sigaction(SIGCHLD, SIG_IGN);
+ return pid;
+ }
+
+ wait_for_completion(&ctx.setup_done);
+
+ forward_err = kunit_uapi_forward_to_printk(test, ctx.out);
+ if (forward_err)
+ kunit_uapi_kill_pid(ctx.tgid);
+
+ wait_err = kernel_wait(ctx.tgid, &ret);
+
+ /* Restore default kernel sig handler */
+ kernel_sigaction(SIGCHLD, SIG_IGN);
+
+ if (ctx.exec_err)
+ return ctx.exec_err;
+ if (forward_err)
+ return forward_err;
+ if (wait_err < 0)
+ return wait_err;
+ return ret;
+}
+
+static int kunit_uapi_run_executable(struct kunit *test,
+ const struct kunit_uapi_blob *executable)
+{
+ const char *exe_name = kbasename(executable->path);
+ struct vfsmount *mnt;
+ int err;
+
+ mnt = kunit_uapi_mount_ramfs();
+ if (IS_ERR(mnt))
+ return PTR_ERR(mnt);
+
+ err = kunit_uapi_write_executable(mnt, executable);
+
+ if (!err)
+ err = kunit_uapi_run_executable_in_mount(test, exe_name, mnt);
+
+ kern_unmount(mnt);
+
+ return err;
+}
+
+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.w...@linutronix.de");
+MODULE_LICENSE("GPL");

--
2.50.0

Thomas Weißschuh

unread,
Jul 17, 2025, 4:49:04 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
Extend the example to show how to run a userspace executable.

Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
Reviewed-by: David Gow <davi...@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 0f60501c6de570723123b24eb930d15f1bd956eb..b1405f0a0e638d1654d9dc9e51d784ddc838cf5b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13544,6 +13544,7 @@ KUNIT UAPI TESTING FRAMEWORK (in addition to KERNEL UNIT TESTING FRAMEWORK)
M: Thomas Weißschuh <thomas.w...@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 6059621a2d32c8e7384acda59793f05826af8c81..2434470e998525e5667ebc207d11659835b5e888 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 3056d6bc705d0a8f196f0f4412e679dbb0e03114..0c5e1e59f9358b84aee2621e342d824a2f99f9aa 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
@@ -277,6 +278,19 @@ static void example_slow_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, 1 + 1, 2);
}

+/*
+ * 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.
@@ -297,6 +311,7 @@ static struct kunit_case example_test_cases[] = {
KUNIT_CASE(example_priv_test),
KUNIT_CASE_PARAM(example_params_test, example_gen_params),
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 0000000000000000000000000000000000000000..4ce657050dd4a576632a41ca0309c4cb5134ce14
--- /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) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@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.50.0

Thomas Weißschuh

unread,
Jul 17, 2025, 4:49:04 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
Show that the selftests are executed from a fairly "normal"
userspace context.

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

diff --git a/MAINTAINERS b/MAINTAINERS
index e81dfa180ab374ef91c7a45e546e6e9a8f454fa7..d86e8e0bfee75acecfeb9569d53ea8ea99727985 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13545,6 +13545,7 @@ M: Thomas Weißschuh <thomas.w...@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 e52a31b0852caef5669f11f6059c29ce5911aa43..44a93c59a48fb7b4bb34b26333a28283c704cdef 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -31,6 +31,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 0000000000000000000000000000000000000000..ec5395d809ee2a4bd3c47a573a576e2f98ef5c1b
--- /dev/null
+++ b/lib/kunit/kunit-test-uapi.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace selftest.
+ *
+ * Copyright (C) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@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 d9c781c859fde1f3623eb71b6829e82aa4803762..03972a3cb172d4af61bec17be800ddfb4bbd7268 100644
--- a/lib/kunit/kunit-test.c
+++ b/lib/kunit/kunit-test.c
@@ -8,6 +8,7 @@
#include "linux/gfp_types.h"
#include <kunit/test.h>
#include <kunit/test-bug.h>
+#include <kunit/uapi.h>

#include <linux/device.h>
#include <kunit/device.h>
@@ -868,10 +869,30 @@ static struct kunit_suite kunit_current_test_suite = {
.test_cases = kunit_current_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_fault_test_suite, &kunit_uapi_test_suite);

MODULE_DESCRIPTION("KUnit test for core test infrastructure");
MODULE_LICENSE("GPL v2");

--
2.50.0

Thomas Weißschuh

unread,
Jul 17, 2025, 4:49:04 AMJul 17
to Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org, Thomas Weißschuh, Nicolas Schier
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.w...@linutronix.de>
Reviewed-by: David Gow <davi...@google.com>
---
MAINTAINERS | 1 +
lib/kunit/Makefile | 7 ++++++
lib/kunit/kunit-uapi.c | 9 +++++--
lib/kunit/uapi-preinit.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 78 insertions(+), 2 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index b1405f0a0e638d1654d9dc9e51d784ddc838cf5b..e81dfa180ab374ef91c7a45e546e6e9a8f454fa7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13546,6 +13546,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 <pbon...@redhat.com>
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 2434470e998525e5667ebc207d11659835b5e888..e52a31b0852caef5669f11f6059c29ce5911aa43 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -14,8 +14,15 @@ kunit-objs += test.o \
device.o \
platform.o

+userprogs += uapi-preinit
+uapi-preinit-userccflags += -static $(NOLIBC_USERCFLAGS) \
+ -include include/generated/autoconf.h \
+ -include $(srctree)/tools/include/linux/kconfig.h
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 24356f68eca0df07032fb8a9e92daffde01b21d3..382a2bfee3c78a6e042a56a9ccdefcd55b5265a1 100644
--- a/lib/kunit/kunit-uapi.c
+++ b/lib/kunit/kunit-uapi.c
@@ -25,6 +25,8 @@
#define KSFT_XPASS 3
#define KSFT_SKIP 4

+KUNIT_UAPI_EMBED_BLOB(kunit_uapi_preinit, "uapi-preinit");
+
static struct vfsmount *kunit_uapi_mount_ramfs(void)
{
struct file_system_type *type;
@@ -146,7 +148,7 @@ static int kunit_uapi_user_mode_thread_init(void *data)
kernel_sigaction(SIGABRT, SIG_DFL);

complete(&ctx->setup_done);
- ctx->exec_err = kernel_execve(ctx->executable, argv, NULL);
+ ctx->exec_err = kernel_execve(kbasename(kunit_uapi_preinit.path), argv, NULL);
if (!ctx->exec_err)
return 0;
do_exit(0);
@@ -255,7 +257,10 @@ static int kunit_uapi_run_executable(struct kunit *test,
if (IS_ERR(mnt))
return PTR_ERR(mnt);

- err = kunit_uapi_write_executable(mnt, executable);
+ err = kunit_uapi_write_executable(mnt, &kunit_uapi_preinit);
+
+ if (!err)
+ err = kunit_uapi_write_executable(mnt, executable);

if (!err)
err = kunit_uapi_run_executable_in_mount(test, exe_name, mnt);
diff --git a/lib/kunit/uapi-preinit.c b/lib/kunit/uapi-preinit.c
new file mode 100644
index 0000000000000000000000000000000000000000..81182039965a8c93aebb2d5d76f4113bfef277a6
--- /dev/null
+++ b/lib/kunit/uapi-preinit.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace environment setup.
+ *
+ * Copyright (C) 2025, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.w...@linutronix.de>
+ *
+ * This is *userspace* code.
+ */
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include "../../tools/testing/selftests/kselftest.h"
+
+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 = 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);
+
+ if (IS_ENABLED(CONFIG_DEVTMPFS)) {
+ 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.50.0

Mark Brown

unread,
Jul 17, 2025, 9:49:14 AMJul 17
to Christoph Hellwig, Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org
On Thu, Jul 17, 2025 at 03:23:00PM +0200, Christoph Hellwig wrote:
> On Thu, Jul 17, 2025 at 10:48:02AM +0200, Thomas Weißschuh wrote:

> > If the kernel toolchain is not fit to
> > produce userspace because of a missing libc, the kernel's own nolibc can
> > be used instead.

> Is nolibc enough to run all the selftests? If so we should just do
> it unconditionally, but linking to different libraries by availability
> seems a bit problematic.

There's some that rely on standard userspace libraries for accessing the
functionality they're testing or for things like crypto which would
require a bunch more work.
signature.asc

Thomas Weißschuh

unread,
Jul 18, 2025, 2:22:35 AMJul 18
to Christoph Hellwig, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org
On Thu, Jul 17, 2025 at 03:23:00PM +0200, Christoph Hellwig wrote:
> On Thu, Jul 17, 2025 at 10:48:02AM +0200, Thomas Weißschuh wrote:

(...)

> > 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.

(...)

> I had my own fair share of problems with kselftests,
> mostly because of the lack of structure and automated way to run them,

How did you overcome these issues? Why does everbody need to reinvent the
wheel here? KUnit already exists and provides a lot of structure and tooling.

> but adding them to the kernel (or a module) is overshooting the target
> by far.

That's a subjective statement without any reasoning I can engange with.
I would be happy to do so, but for now I can only say that I disagree.
The patches have been on the testing-related lists for
some time and so far nobody had an issue with this aspect.

> > If the kernel toolchain is not fit to
> > produce userspace because of a missing libc, the kernel's own nolibc can
> > be used instead.
>
> Is nolibc enough to run all the selftests?

It is not and most probably won't ever be. The maintainers of each testcase
will decide which libc to use. Like it is in tools/testing/selftests/ today.
Some use glibc, some nolibc and some can do both.

> If so we should just do it unconditionally, but linking to different
> libraries by availability seems a bit problematic.

Agreed. But as mentioned above it will be the maintainers decision.

Only the preinit executable will need to support all configurations so needs
the availability check. For the framework selftest it also makes sense to
support as many configurations as possible. For the example test, any
configuration is fine.

(...)

While having this discussion, can we also work on dealing with the symbol
exports, as discussed before?


Thomas

Al Viro

unread,
Jul 18, 2025, 12:44:45 PMJul 18
to Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org
On Thu, Jul 17, 2025 at 10:48:08AM +0200, Thomas Weißschuh wrote:
> The KUnit UAPI infrastructure starts userspace processes.
> As it should be able to be built as a module, export the necessary symbols.
>
> Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>

No. This is just plain wrong. This is way too low-level; teach kernel/umh.c
to provide what you need, but do *not* add more kernel_execve() callers.
And the situation with ramfs needs cleaning up, but "export put_filesystem()"
is not a solution.

Thomas Weißschuh

unread,
Jul 21, 2025, 2:42:47 AMJul 21
to Al Viro, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org
On Fri, Jul 18, 2025 at 05:44:12PM +0100, Al Viro wrote:
> On Thu, Jul 17, 2025 at 10:48:08AM +0200, Thomas Weißschuh wrote:
> > The KUnit UAPI infrastructure starts userspace processes.
> > As it should be able to be built as a module, export the necessary symbols.
> >
> > Signed-off-by: Thomas Weißschuh <thomas.w...@linutronix.de>
>
> No. This is just plain wrong. This is way too low-level; teach kernel/umh.c
> to provide what you need, but do *not* add more kernel_execve() callers.

Sounds good.

> And the situation with ramfs needs cleaning up, but "export put_filesystem()"
> is not a solution.

Cleaning up would mean to stop calling put_filesystem(), as it is a no-op
here anyways, right?


This would still leave the exports for replace_fd(), create_pipe_files()
and set_fs_pwd(). Instead of using kernel/umh.c, I can also extend
kernel/usermode_driver.c to provide these in a way that works for me.
But kernel/usermode_driver.c is dead code, unused since commit
98e20e5e13d2 ("bpfilter: remove bpfilter")
Would it be fine to export those symbols? And delete usermode_driver.c,
as carrying around an unused generic framework seems pointless.


Thomas

Christoph Hellwig

unread,
Jul 26, 2025, 4:31:10 AMJul 26
to Thomas Weißschuh, Christoph Hellwig, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org
On Fri, Jul 18, 2025 at 08:22:26AM +0200, Thomas Weißschuh wrote:
> > I had my own fair share of problems with kselftests,
> > mostly because of the lack of structure and automated way to run them,
>
> How did you overcome these issues? Why does everbody need to reinvent the
> wheel here?

Told people to use everything remotely file system related to use
xfstests instead, and either ignore or suffer from the rest.

> KUnit already exists and provides a lot of structure and tooling.

That's great. Let's reuse it without having to drive running userspace
programs from kernel code.

> > but adding them to the kernel (or a module) is overshooting the target
> > by far.
>
> That's a subjective statement without any reasoning I can engange with.

Well, then we're done here if you can't engage.

> I would be happy to do so, but for now I can only say that I disagree.
> The patches have been on the testing-related lists for
> some time and so far nobody had an issue with this aspect.

Has anyone actually chimed in and said "it's great that we bloat the
kernel to run userspace tests", or have people just mostly ignored it
like most things?

> > > If the kernel toolchain is not fit to
> > > produce userspace because of a missing libc, the kernel's own nolibc can
> > > be used instead.
> >
> > Is nolibc enough to run all the selftests?
>
> It is not and most probably won't ever be. The maintainers of each testcase
> will decide which libc to use. Like it is in tools/testing/selftests/ today.
> Some use glibc, some nolibc and some can do both.

So why do you want to use it here? And how is is related to the rest
of the series?

> While having this discussion, can we also work on dealing with the symbol
> exports, as discussed before?

Well, the scope of the entire series makes it pretty clear that this
series as is simply should not go in.

You present running pure userspace tests as the solution to a problem
you don't even explain, or rather just state very highlevel. Yes,
kselftests suck as most people will agree. But the answer is not
to add a lot of kernel bloat to treat userspace integration tests
like kernel units tests. How about you just fix kselftests, preferably
by reusing well known and teststed userland code?

Christoph Hellwig

unread,
Jul 26, 2025, 4:31:10 AMJul 26
to Thomas Weißschuh, Al Viro, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Shuah Khan, Jonathan Corbet, Nicolas Schier, Kees Cook, Christian Brauner, Jan Kara, Christoph Hellwig, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org
On Mon, Jul 21, 2025 at 08:42:40AM +0200, Thomas Weißschuh wrote:
> This would still leave the exports for replace_fd(), create_pipe_files()
> and set_fs_pwd(). Instead of using kernel/umh.c,

Please look into a way to just run your userspace tests from userspace.

It's not that hard, people have done this novel concept for at least
a few decades if you look into it.

> I can also extend
> kernel/usermode_driver.c to provide these in a way that works for me.
> But kernel/usermode_driver.c is dead code, unused since commit
> 98e20e5e13d2 ("bpfilter: remove bpfilter")
> Would it be fine to export those symbols? And delete usermode_driver.c,
> as carrying around an unused generic framework seems pointless.

Unused code should always go away. Weirdly enough USERMODE_DRIVER is
selected by BPF_PRELOAD despite that not really using any code from
it, though.

Thomas Weißschuh

unread,
Aug 4, 2025, 11:01:40 AMAug 4
to Christoph Hellwig, Shuah Khan, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org
Hi Christoph,

On Mon, Jul 21, 2025 at 09:09:58AM +0200, Christoph Hellwig wrote:
> On Fri, Jul 18, 2025 at 08:22:26AM +0200, Thomas Weißschuh wrote:
> > > I had my own fair share of problems with kselftests,
> > > mostly because of the lack of structure and automated way to run them,
> >
> > How did you overcome these issues? Why does everbody need to reinvent the
> > wheel here?
>
> Told people to use everything remotely file system related to use
> xfstests instead, and either ignore or suffer from the rest.

Suffering from the rest is what I am trying to avoid.
(More on that below)

> > KUnit already exists and provides a lot of structure and tooling.
>
> That's great. Let's reuse it without having to drive running userspace
> programs from kernel code.

Running in the kernel is the point behind KUnit. It could be done by putting
all the userspace test into a initramfs and run them on boot from there.
But that has other drawbacks:
* The tests can't be run on an existing system.
* All tests need to be loaded into memory together, and not on demand.
* The tests can not be rerun.

> > > but adding them to the kernel (or a module) is overshooting the target
> > > by far.
> >
> > That's a subjective statement without any reasoning I can engange with.
>
> Well, then we're done here if you can't engage.

This was a response to one specific statement. Could you be a bit more specific
in your critique? I am not sure what exactly you mean in some cases, making it
hard to respond properly. For example "bloat", it is bloaty
* source code,
* object code for users enabling the new kconfig options,
* object code for other users *not* enabling the new kconfig options?

> > I would be happy to do so, but for now I can only say that I disagree.
> > The patches have been on the testing-related lists for
> > some time and so far nobody had an issue with this aspect.
>
> Has anyone actually chimed in and said "it's great that we bloat the
> kernel to run userspace tests", or have people just mostly ignored it
> like most things?

That specific wording wasn't used. Obviously...
So far nobody had any issues with the overall goal of the series.
There was criticism around implementation details and I have been and will be
working on resolving those.

Some feedback I got:

David [0]: "I've taken quite a liking to it: it'd definitely have made my
life easier more than once."
Benjamin is already playing with it, having built his own testcase [1].
I asked Shuah about it before starting development and she gave a go-ahead.
A collegue of mine is also using it to validate the PREEMPT_RT safety of
various UAPIs by combining KUnit UAPI with a runtime validator [2].

> > > > If the kernel toolchain is not fit to
> > > > produce userspace because of a missing libc, the kernel's own nolibc can
> > > > be used instead.
> > >
> > > Is nolibc enough to run all the selftests?
> >
> > It is not and most probably won't ever be. The maintainers of each testcase
> > will decide which libc to use. Like it is in tools/testing/selftests/ today.
> > Some use glibc, some nolibc and some can do both.
>
> So why do you want to use it here? And how is is related to the rest
> of the series?

To make it easier to test a wide range of architectures by not requiring a
libc from the toolchain. It also avoids relying on a bunch of out-of-tree
code (glibc) as part of the test. And there are existing kselftests which
use it over glibc for their own reasons.

But using nolibc in test code is not necessary and nobody is forced to do so.

(Maybe a disclaimer that I'm one of the nolibc maintainers is in order)

(...)

> You present running pure userspace tests as the solution to a problem
> you don't even explain, or rather just state very highlevel.

To run kselftests we need the following things:
a) A toolchain which can build userspace executables.
b) Quite a bit of supporting userland, at least glibc, coreutils and bash.
c) A rootfs assembled out of these.
d) An efficient way to incrementally rebuild the test executables and rootfs.
e) A way to put that rootfs into the system under test.
f) A way to configure a kernel which
* is as small as possible and as fast as possible to build,
* can run on QEMU or a real machine,
* can run the functionality under test.
g) A way to select the tests to run in the system under test.
h) A way to communicate back the results.
i) Something to interpret the results.
j) Hook up everything into a CI system.

And for all of this there should be good in-tree tooling.

For a) and b) I am not aware of any toolchain provider or distribution which
provides this for all necessary architectures. And the existing userspace test
frameworks don't even try to address the points a) to e)/f) and let the user
figure it out. This is the case for xfstests and LTP. virtme(-ng) provide most
of it but don't support cross-architecture setups. On the other hand the tree
already contains solutions for most of those points. a) and d) are solved by
kbuild userprogs, e) to j) by KUnit and my new framework plugs b) and c).
Moving to a pure userspace solution would preclude the usage of KUnit as far as
I can see.

This all started when I worked on the generic vDSO data storage patches [3].
I needed to run the existing vDSO selftests against a bunch of architectures,
including some esoteric ones [4]. With my framework, running the vDSO selftests
for any architecture is now trivial and blazingly fast.

Does this make more sense?

> Yes, kselftests suck as most people will agree. But the answer is not
> to add a lot of kernel bloat to treat userspace integration tests
> like kernel units tests.

I fail to understand how this test code is worse than the existing KUnit test
code. This is not meant to test complex scenarios, but single system calls or
specific UAPIs, which may depend on architecture features. For example timers,
signals, vDSO, mm etc.

> How about you just fix kselftests, preferably
> by reusing well known and teststed userland code?

Is "well known and tested userland code" referring to glibc or testing
frameworks? As mentioned above, glibc can be used just fine and the frameworks
I know about are lacking.


Thomas


[0] https://lore.kernel.org/all/CABVgOSn+530YJ3OPNJQncLDQ...@mail.gmail.com/
[1] https://lore.kernel.org/all/20250626195714.2...@sipsolutions.net/
[2] https://lore.kernel.org/lkml/cover.1752088...@linutronix.de/
[3] https://lore.kernel.org/lkml/20250204-vdso-store-...@linutronix.de/
[4] https://lore.kernel.org/lkml/20250724-vdso-sparc64-ge...@linutronix.de/

Christoph Hellwig

unread,
Aug 12, 2025, 5:41:15 AMAug 12
to Thomas Weißschuh, Christoph Hellwig, Shuah Khan, Masahiro Yamada, Nathan Chancellor, Andrew Morton, Willy Tarreau, Thomas Weißschuh, Brendan Higgins, David Gow, Rae Moar, Jonathan Corbet, Nicolas Schier, Kees Cook, Alexander Viro, Christian Brauner, Jan Kara, Luis Chamberlain, Christophe Leroy, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linu...@vger.kernel.org, work...@vger.kernel.org, linu...@kvack.org, linux-...@vger.kernel.org
On Mon, Aug 04, 2025 at 05:01:35PM +0200, Thomas Weißschuh wrote:
> > That's great. Let's reuse it without having to drive running userspace
> > programs from kernel code.
>
> Running in the kernel is the point behind KUnit.

When using kunit as is to unit test kernel functionality - obviously.

When running it to integration test the syscall boundary - not at all.

> It could be done by putting
> all the userspace test into a initramfs and run them on boot from there.
> But that has other drawbacks:
> * The tests can't be run on an existing system.
> * All tests need to be loaded into memory together, and not on demand.
> * The tests can not be rerun.

None of that is true. While running syscall level tests from an
initramfs could be a nice feature for an automatd kernel CI system,
nothin in this tests should require running from an initramfs.

> This was a response to one specific statement. Could you be a bit more specific
> in your critique? I am not sure what exactly you mean in some cases, making it
> hard to respond properly. For example "bloat", it is bloaty
> * source code,
> * object code for users enabling the new kconfig options,
> * object code for other users *not* enabling the new kconfig options?

You are adding kernel code both at the source and object level to run
userspace tests. That is very clearly bloat. Even more so as it adds
functionality and exports that don't fit in with what the kernel already
does for actual kernel functionality.

> > > It is not and most probably won't ever be. The maintainers of each testcase
> > > will decide which libc to use. Like it is in tools/testing/selftests/ today.
> > > Some use glibc, some nolibc and some can do both.
> >
> > So why do you want to use it here? And how is is related to the rest
> > of the series?
>
> To make it easier to test a wide range of architectures by not requiring a
> libc from the toolchain. It also avoids relying on a bunch of out-of-tree
> code (glibc) as part of the test. And there are existing kselftests which
> use it over glibc for their own reasons.
>
> But using nolibc in test code is not necessary and nobody is forced to do so.
>
> (Maybe a disclaimer that I'm one of the nolibc maintainers is in order)

Well, why do you even mix it up with this unrelated series then?

> To run kselftests we need the following things:
> a) A toolchain which can build userspace executables.

You'll need that for any userspace program, no matter what test
harness.

> b) Quite a bit of supporting userland, at least glibc, coreutils and bash.

Well, a libc you will need anyway. Maybe nolibc is good enough for
some tests, but as you already stated not for very many. The others
are just an artifcat of how you run tests.

> c) A rootfs assembled out of these.
> d) An efficient way to incrementally rebuild the test executables and rootfs.
> e) A way to put that rootfs into the system under test.

You don't need a rootfs.

> And for all of this there should be good in-tree tooling.

Absolutely.

> Moving to a pure userspace solution would preclude the usage of KUnit as far as
> I can see.

You've still failed why using kunit is the goal and not just something
that made your life easier archieving your goal.

> > Yes, kselftests suck as most people will agree. But the answer is not
> > to add a lot of kernel bloat to treat userspace integration tests
> > like kernel units tests.
>
> I fail to understand how this test code is worse than the existing KUnit test
> code. This is not meant to test complex scenarios, but single system calls or
> specific UAPIs, which may depend on architecture features. For example timers,
> signals, vDSO, mm etc.

So now having another half-assed test framework is a good thing?

> > How about you just fix kselftests, preferably
> > by reusing well known and teststed userland code?
>
> Is "well known and tested userland code" referring to glibc or testing
> frameworks? As mentioned above, glibc can be used just fine and the frameworks
> I know about are lacking.

Basically any kind of testing framework that has broad use. It's not
like there aren't userland unit test frameworks if you really want to
use that.
Reply all
Reply to author
Forward
0 new messages