UAPI selftests may expect a "normal" userspace environment. For example the normal kernel API pseudo-filesystems should be mounted. This could be done from kernel code but it is non-idiomatic.
Add a preinit userspace executable which performs these setup steps before running the final test executable. This preinit executable is only ever run from the kernel. Give it access to autoconf.h and kconfig.h to adapt itself to the tested kernel.
Signed-off-by: Thomas Weißschuh thomas.weissschuh@linutronix.de Reviewed-by: David Gow davidgow@google.com --- MAINTAINERS | 1 + lib/kunit/Makefile | 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 pbonzini@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.weissschuh@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; +}