@@ -12,7 +12,14 @@ kunit-objs += test.o \
device.o \
platform.o
-obj-$(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
+obj-$(CONFIG_KUNIT_UAPI) += uapi.o uapi-preinit.blob.o
ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
kunit-objs += debugfs.o
new file mode 100644
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit Userspace environment setup.
+ *
+ * Copyright (C) 2025, Linuxtronix GmbH.
+ * Author: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
+ */
+
+#ifndef NOLIBC
+#include <sys/mount.h>
+#include <sys/stat.h>
+#endif
+
+#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;
+}
@@ -19,6 +19,8 @@
#include <kunit/test.h>
#include <kunit/uapi.h>
+#define KUNIT_UAPI_PREINIT "preinit"
+
static struct vfsmount *kunit_uapi_mount_tmpfs(void)
{
struct file_system_type *type;
@@ -118,7 +120,7 @@ static int kunit_uapi_user_mode_thread_init(void *data)
kernel_sigaction(SIGKILL, SIG_DFL);
complete(&ctx->setup_done);
- ctx->exec_err = kernel_execve(ctx->executable, argv, NULL);
+ ctx->exec_err = kernel_execve(KUNIT_UAPI_PREINIT, argv, NULL);
if (!ctx->exec_err)
return 0;
do_exit(0);
@@ -213,6 +215,8 @@ static int kunit_uapi_run_executable_in_mount(struct kunit *test, const char *ex
void kunit_uapi_run_executable(struct kunit *test, const struct blob *blob)
{
+ DECLARE_BLOB(kunit_uapi_preinit);
+
const char *exe_name = kbasename(blob->path);
struct vfsmount *mnt;
int err;
@@ -222,8 +226,15 @@ void kunit_uapi_run_executable(struct kunit *test, const struct blob *blob)
if (IS_ERR(mnt))
return;
- err = kunit_uapi_write_file(mnt, exe_name, 0700, blob->data, blob_size(blob));
- KUNIT_EXPECT_EQ_MSG(test, 0, err, "Could not add test executable: %pe", ERR_PTR(err));
+ err = kunit_uapi_write_file(mnt, KUNIT_UAPI_PREINIT, 0755,
+ kunit_uapi_preinit.data, blob_size(&kunit_uapi_preinit));
+ KUNIT_EXPECT_EQ_MSG(test, 0, err, "Could not add preinit executable: %pe", ERR_PTR(err));
+
+ if (!err) {
+ err = kunit_uapi_write_file(mnt, exe_name, 0755, blob->data, blob_size(blob));
+ KUNIT_EXPECT_EQ_MSG(test, 0, err, "Could not add test executable: %pe",
+ ERR_PTR(err));
+ }
if (!err) {
err = kunit_uapi_run_executable_in_mount(test, exe_name, mnt);
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> --- lib/kunit/Makefile | 9 ++++++- lib/kunit/uapi-preinit.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/kunit/uapi.c | 17 +++++++++++--- 3 files changed, 83 insertions(+), 4 deletions(-)