On Fri, Sep 4, 2026 at 12:38 PM Luis Henriques <[email protected]> wrote:
>
> In order to reduce new tests setup/teardown code duplication, factor-out
> these functions from the existing acl_cache test into a new fuse_common.c
> file that can be reused in other tests.
>
> Signed-off-by: Luis Henriques <[email protected]>
> ---
> .../selftests/filesystems/fuse/Makefile | 8 ++-
> .../filesystems/fuse/fuse_acl_cache_test.c | 62 +++----------------
> .../selftests/filesystems/fuse/fuse_common.c | 60 ++++++++++++++++++
> .../selftests/filesystems/fuse/fuse_common.h | 25 ++++++++
> 4 files changed, 100 insertions(+), 55 deletions(-)
> create mode 100644 tools/testing/selftests/filesystems/fuse/fuse_common.c
> create mode 100644 tools/testing/selftests/filesystems/fuse/fuse_common.h
>
> diff --git a/tools/testing/selftests/filesystems/fuse/Makefile
> b/tools/testing/selftests/filesystems/fuse/Makefile
> index a3ee9b3a2f5d..7744f796eb06 100644
> --- a/tools/testing/selftests/filesystems/fuse/Makefile
> +++ b/tools/testing/selftests/filesystems/fuse/Makefile
> @@ -21,8 +21,12 @@ ifeq ($(VAR_LDLIBS),)
> VAR_LDLIBS := -lfuse3 -pthread
> endif
>
> +CFLAGS += $(VAR_CFLAGS)
> +LDLIBS += $(VAR_LDLIBS)
> +
> $(OUTPUT)/fuse_mnt: CFLAGS += $(VAR_CFLAGS)
> $(OUTPUT)/fuse_mnt: LDLIBS += $(VAR_LDLIBS)
>
> -$(OUTPUT)/fuse_acl_cache_test: CFLAGS += $(VAR_CFLAGS)
> -$(OUTPUT)/fuse_acl_cache_test: LDLIBS += $(VAR_LDLIBS)
> +$(OUTPUT)/fuse_acl_cache_test: fuse_common.c fuse_acl_cache_test.c
> +
> +EXTRA_CLEAN := fuse_common.o
> diff --git a/tools/testing/selftests/filesystems/fuse/fuse_acl_cache_test.c
> b/tools/testing/selftests/filesystems/fuse/fuse_acl_cache_test.c
> index 2411a6e285f1..12cbf9753d03 100644
> --- a/tools/testing/selftests/filesystems/fuse/fuse_acl_cache_test.c
> +++ b/tools/testing/selftests/filesystems/fuse/fuse_acl_cache_test.c
> @@ -33,23 +33,15 @@
> */
>
> #define _GNU_SOURCE
> -#include <errno.h>
> #include <fcntl.h>
> #include <linux/limits.h>
> -#include <pthread.h>
> #include <stdint.h>
> -#include <stdio.h>
> -#include <stdlib.h>
> -#include <string.h>
> -#include <sys/stat.h>
> #include <sys/xattr.h>
> -#include <unistd.h>
> -
> -#define FUSE_USE_VERSION 31
> -#include <fuse_lowlevel.h>
>
> #include "kselftest_harness.h"
>
> +#include "fuse_common.h"
> +
> /* ---- ACL binary encoding ------------------------------------------------
> */
> /*
> * POSIX ACL v2 xattr format (little-endian):
> @@ -176,69 +168,33 @@ static const struct fuse_lowlevel_ops fs_ops = {
> .getxattr = fs_getxattr,
> };
>
> -/* ---- Daemon thread
> ------------------------------------------------------- */
> -
> -static void *run_daemon(void *arg)
> -{
> - fuse_session_loop((struct fuse_session *)arg);
> - return NULL;
> -}
> -
> /* ---- kselftest harness
> --------------------------------------------------- */
>
> FIXTURE(acl_cache) {
> struct fuse_session *se;
> - char mountpoint[PATH_MAX];
> + char mountpoint[MOUNTPOINT_SZ];
> char file_path[PATH_MAX];
> pthread_t thread;
> };
Nice!
I think it would be even nicer to have struct fuse_common_ctx
with the common members embedded in the per test state,
but I'll let you decide if you want to do that or not.
Thanks,
Amir.
>
> FIXTURE_SETUP(acl_cache)
> {
> - char *fuse_argv[] = { "fuse_acl_cache_test", NULL };
> - struct fuse_args args = FUSE_ARGS_INIT(1, fuse_argv);
> + char err[MAX_ERR_MSG];
>
> - g_ds.acl = acl_a;
> - g_ds.acl_size = sizeof(acl_a);
> + g_ds.acl = acl_a;
> + g_ds.acl_size = sizeof(acl_a);
> g_ds.getxattr_count = 0;
>
> - strcpy(self->mountpoint, "/tmp/acl_cache_test_XXXXXX");
> - if (!mkdtemp(self->mountpoint))
> - SKIP(return, "mkdtemp: %s", strerror(errno));
> + if (fs_setup(&self->se, self->mountpoint, &fs_ops, &self->thread,
> err))
> + SKIP(return, err);
>
> snprintf(self->file_path, sizeof(self->file_path),
> "%s/" FILE_NAME, self->mountpoint);
> -
> - self->se = fuse_session_new(&args, &fs_ops, sizeof(fs_ops), NULL);
> - if (!self->se) {
> - rmdir(self->mountpoint);
> - SKIP(return, "fuse_session_new failed");
> - }
> -
> - if (fuse_session_mount(self->se, self->mountpoint)) {
> - fuse_session_destroy(self->se);
> - rmdir(self->mountpoint);
> - SKIP(return, "fuse_session_mount failed "
> - "(missing fusermount3 or insufficient
> privileges)");
> - }
> -
> - if (pthread_create(&self->thread, NULL, run_daemon, self->se)) {
> - fuse_session_unmount(self->se);
> - fuse_session_destroy(self->se);
> - rmdir(self->mountpoint);
> - SKIP(return, "pthread_create: %s", strerror(errno));
> - }
> -
> - fuse_opt_free_args(&args);
> }
>
> FIXTURE_TEARDOWN(acl_cache)
> {
> - fuse_session_exit(self->se);
> - fuse_session_unmount(self->se);
> - pthread_join(self->thread, NULL);
> - fuse_session_destroy(self->se);
> - rmdir(self->mountpoint);
> + fs_teardown(self->se, self->thread, self->mountpoint);
> }
>
> static int do_force_statx(const char *path)
> diff --git a/tools/testing/selftests/filesystems/fuse/fuse_common.c
> b/tools/testing/selftests/filesystems/fuse/fuse_common.c
> new file mode 100644
> index 000000000000..3a91cac25b81
> --- /dev/null
> +++ b/tools/testing/selftests/filesystems/fuse/fuse_common.c
> @@ -0,0 +1,60 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include "fuse_common.h"
> +
> +static void *run_daemon(void *arg)
> +{
> + fuse_session_loop((struct fuse_session *)arg);
> + return NULL;
> +}
> +
> +int fs_setup(struct fuse_session **se, char *mountpoint,
> + const struct fuse_lowlevel_ops *fs_ops,
> + pthread_t *thread, char *err)
> +{
> + char *fuse_argv[] = { "fuse_test", NULL };
> + struct fuse_args args = FUSE_ARGS_INIT(1, fuse_argv);
> +
> + strcpy(mountpoint, MOUNTPOINT_TEMPLATE);
> + if (!mkdtemp(mountpoint)) {
> + snprintf(err, MAX_ERR_MSG, "mkdtemp: %s", strerror(errno));
> + return -1;
> + }
> +
> + *se = fuse_session_new(&args, fs_ops, sizeof(*fs_ops), NULL);
> + if (!*se) {
> + rmdir(mountpoint);
> + snprintf(err, MAX_ERR_MSG, "fuse_session_new failed");
> + return -1;
> + }
> +
> + if (fuse_session_mount(*se, mountpoint)) {
> + fuse_session_destroy(*se);
> + rmdir(mountpoint);
> + snprintf(err, MAX_ERR_MSG, "fuse_session_mount failed "
> + "(missing fusermount3 or insufficient privileges)");
> + return -1;
> + }
> +
> + if (pthread_create(thread, NULL, run_daemon, *se)) {
> + fuse_session_unmount(*se);
> + fuse_session_destroy(*se);
> + rmdir(mountpoint);
> + snprintf(err, MAX_ERR_MSG, "pthread_create: %s",
> strerror(errno));
> + return -1;
> + }
> +
> + fuse_opt_free_args(&args);
> +
> + return 0;
> +}
> +
> +void fs_teardown(struct fuse_session *se, pthread_t thread, char *mountpoint)
> +{
> + fuse_session_exit(se);
> + fuse_session_unmount(se);
> + pthread_join(thread, NULL);
> + fuse_session_destroy(se);
> + rmdir(mountpoint);
> +}
> +
> diff --git a/tools/testing/selftests/filesystems/fuse/fuse_common.h
> b/tools/testing/selftests/filesystems/fuse/fuse_common.h
> new file mode 100644
> index 000000000000..77d5eb58550d
> --- /dev/null
> +++ b/tools/testing/selftests/filesystems/fuse/fuse_common.h
> @@ -0,0 +1,25 @@
> +#ifndef __SELFTEST_FUSE_COMMON_H__
> +#define __SELFTEST_FUSE_COMMON_H__
> +
> +#define _GNU_SOURCE
> +#include <errno.h>
> +#include <pthread.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#define FUSE_USE_VERSION 31
> +#include <fuse_lowlevel.h>
> +
> +#define MAX_ERR_MSG 256
> +
> +#define MOUNTPOINT_TEMPLATE "/tmp/fuse_test_XXXXXX"
> +#define MOUNTPOINT_SZ 64
> +
> +int fs_setup(struct fuse_session **se, char *mountpoint,
> + const struct fuse_lowlevel_ops *fs_ops,
> + pthread_t *thread, char *err);
> +void fs_teardown(struct fuse_session *se, pthread_t thread, char
> *mountpoint);
> +
> +#endif /* __SELFTEST_FUSE_COMMON_H__ */