[PATCH v6 10/11] kunit: uapi: Introduce preinit executable
From: Thomas Weißschuh
Date: Mon May 04 2026 - 05:35:25 EST
UAPI selftests may expect a "normal" userspace environment.
For example the normal kernel API pseudo-filesystems should be mounted.
This could be done from kernel code but it is non-idiomatic.
Add a preinit userspace executable which performs these setup steps
before running the final test executable.
This preinit executable is only ever run from the kernel.
Give it access to autoconf.h and kconfig.h to adapt itself to the
tested kernel.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@xxxxxxxxxxxxx>
Reviewed-by: David Gow <davidgow@xxxxxxxxxx>
---
MAINTAINERS | 1 +
lib/kunit/Makefile | 5 ++++
lib/kunit/kunit-uapi.c | 11 +++++---
lib/kunit/uapi-preinit.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 82 insertions(+), 3 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index b7358d89df70..4e8cf9fa7aa9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14401,6 +14401,7 @@ S: Maintained
F: include/kunit/uapi.h
F: lib/kunit/kunit-example-uapi.c
F: lib/kunit/kunit-uapi.c
+F: lib/kunit/uapi-preinit.c
KVM PARAVIRT (KVM/paravirt)
M: Paolo Bonzini <pbonzini@xxxxxxxxxx>
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 2434470e9985..05991d69aa70 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -14,8 +14,13 @@ kunit-objs += test.o \
device.o \
platform.o
+userprogs += uapi-preinit
+uapi-preinit-userccflags += -static $(NOLIBC_USERCFLAGS)
obj-$(CONFIG_KUNIT_UAPI) += kunit-uapi.o
+CFLAGS_kunit-uapi.o := -Wa,-I$(obj)
+$(obj)/kunit-uapi.o: $(obj)/uapi-preinit
+
ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
kunit-objs += debugfs.o
endif
diff --git a/lib/kunit/kunit-uapi.c b/lib/kunit/kunit-uapi.c
index 7f0309a827a5..702d26878ccd 100644
--- a/lib/kunit/kunit-uapi.c
+++ b/lib/kunit/kunit-uapi.c
@@ -33,6 +33,8 @@ enum {
KSFT_SKIP = 4,
};
+KUNIT_UAPI_EMBED_BLOB(kunit_uapi_preinit, "uapi-preinit");
+
static struct vfsmount *kunit_uapi_mount_fs(const char *name)
{
struct file_system_type *type;
@@ -158,18 +160,17 @@ static int kunit_uapi_run_executable_in_mount(struct kunit *test,
const struct kunit_uapi_blob *executable,
struct vfsmount *mnt)
{
- const char *executable_target = kunit_uapi_executable_target(executable);
struct kunit_uapi_usermodehelper_ctx ctx = {
.test = test,
.mnt = mnt,
};
struct subprocess_info *info;
const char *const argv[] = {
- executable_target,
+ kunit_uapi_executable_target(executable),
NULL
};
- info = call_usermodehelper_setup(AT_FDCWD, executable_target, (char **)argv, NULL,
+ info = call_usermodehelper_setup(AT_FDCWD, kunit_uapi_preinit.path, (char **)argv, NULL,
GFP_KERNEL, kunit_uapi_usermodehelper_init, NULL, &ctx);
if (!info)
return -ENOMEM;
@@ -192,6 +193,10 @@ static int kunit_uapi_run_executable(struct kunit *test, const struct kunit_uapi
if (err)
return err;
+ err = kunit_uapi_write_executable(mnt, &kunit_uapi_preinit);
+ if (err)
+ return err;
+
err = kunit_uapi_run_executable_in_mount(test, executable, mnt);
if (err)
return err;
diff --git a/lib/kunit/uapi-preinit.c b/lib/kunit/uapi-preinit.c
new file mode 100644
index 000000000000..686737ea3c76
--- /dev/null
+++ b/lib/kunit/uapi-preinit.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace environment setup.
+ *
+ * Copyright (C) 2026, Linutronix GmbH.
+ * Author: Thomas Weißschuh <thomas.weissschuh@xxxxxxxxxxxxx>
+ *
+ * This is *userspace* code.
+ */
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include "../../tools/testing/selftests/kselftest.h"
+
+#define KUNIT_UAPI_CHDIR_FD 3
+
+static int setup_api_mount(const char *target, const char *fstype)
+{
+ int ret;
+
+ ret = mkdir(target, 0755);
+ if (ret && errno != EEXIST)
+ return -errno;
+
+ ret = mount("none", target, fstype, 0, NULL);
+ if (ret && errno != EBUSY)
+ return -errno;
+
+ return 0;
+}
+
+static void exit_failure(const char *stage, int err)
+{
+ /* If preinit fails synthesize a failed test report. */
+ ksft_print_header();
+ ksft_set_plan(1);
+ ksft_test_result_fail("Failed during test setup: %s: %s\n", stage, strerror(-err));
+ ksft_finished();
+}
+
+int main(int argc, char **argv, char **envp)
+{
+ int ret;
+
+ ret = fchdir(KUNIT_UAPI_CHDIR_FD);
+ close(KUNIT_UAPI_CHDIR_FD);
+ if (ret)
+ exit_failure("fchdir", ret);
+
+ ret = setup_api_mount("/proc", "proc");
+ if (ret)
+ exit_failure("mount /proc", ret);
+
+ ret = setup_api_mount("/sys", "sysfs");
+ if (ret)
+ exit_failure("mount /sys", ret);
+
+ ret = setup_api_mount("/dev", "devtmpfs");
+ if (ret)
+ exit_failure("mount /dev", ret);
+
+ ret = execve(argv[0], argv, envp);
+ if (ret)
+ exit_failure("execve", ret);
+
+ return 0;
+}
--
2.53.0