[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <dc205138-3f68-4073-aeb3-3e2e67c15da4@collabora.com>
Date: Sat, 12 Jul 2025 14:49:38 +0500
From: Muhammad Usama Anjum <usama.anjum@...labora.com>
To: Thomas Weißschuh <thomas.weissschuh@...utronix.de>,
Masahiro Yamada <masahiroy@...nel.org>, Nathan Chancellor
<nathan@...nel.org>, Andrew Morton <akpm@...ux-foundation.org>,
Willy Tarreau <w@....eu>, Thomas Weißschuh
<linux@...ssschuh.net>, Brendan Higgins <brendan.higgins@...ux.dev>,
David Gow <davidgow@...gle.com>, Rae Moar <rmoar@...gle.com>,
Shuah Khan <shuah@...nel.org>, Jonathan Corbet <corbet@....net>,
Nicolas Schier <nicolas.schier@...ux.dev>
Cc: Christophe Leroy <christophe.leroy@...roup.eu>,
linux-kbuild@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-kselftest@...r.kernel.org, kunit-dev@...glegroups.com,
linux-doc@...r.kernel.org, workflows@...r.kernel.org
Subject: Re: [PATCH v4 14/15] kunit: uapi: Introduce preinit executable
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.anjum@...labora.com>
>
> Signed-off-by: Thomas Weißschuh <thomas.weissschuh@...utronix.de>
> Reviewed-by: David Gow <davidgow@...gle.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@...hat.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@...utronix.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;
> +}
>
Powered by blists - more mailing lists