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.an...@collabora.com> > > Signed-off-by: Thomas Weißschuh <thomas.weisssc...@linutronix.de> > Reviewed-by: David Gow <david...@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 <pbonz...@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.weisssc...@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)); Positive error values are passed to strerror() without the - sign in userspace. Probably - needs to be removed from strerror() here. > + 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; > +} >