Last active
February 23, 2025 20:23
-
-
Save vassilit/e00d59135e3204aabcc4cca8c333c140 to your computer and use it in GitHub Desktop.
simple test program to bench when the FS is ready after returning from fuse_main()
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _DEFAULT_SOURCE | |
#define FUSE_USE_VERSION 31 | |
#include <fuse.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <sys/stat.h> | |
#include <sys/wait.h> | |
#include <sys/mman.h> | |
#include <errno.h> | |
#if __linux__ | |
#include <sys/mount.h> | |
#define UNMOUNT(mnt_point) umount(mnt_point) | |
#elif __FreeBSD__ | |
#include <sys/param.h> | |
#include <sys/mount.h> | |
#define UNMOUNT(mnt_point) unmount(mnt_point, 0) | |
#endif | |
#define likely(x) __builtin_expect(!!(x), 1) | |
#define unlikely(x) __builtin_expect(!!(x), 0) | |
#define NELS(array) (sizeof(array)/sizeof(array[0])) | |
#define AR_MNT_TPL "/tmp/tmpfXXXXXX" | |
#define AR_MNT_LEN NELS(AR_MNT_TPL) | |
#define TESTED_MODE (S_IFDIR | 0444) /* dr--r--r-- */ | |
#define TESTED_NLINK 2 | |
static char mnt_point[AR_MNT_LEN]; | |
static struct fuse_args args; | |
static int argc = 2; | |
static char *argv[] = { "f-test", mnt_point, NULL }; | |
static volatile char *sem; | |
static int dummy_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi __attribute__ ((unused))) { | |
int res = 0; | |
memset(stbuf, 0, sizeof (struct stat)); | |
if (strcmp(path, "/") == 0) { | |
stbuf->st_mode = TESTED_MODE; | |
stbuf->st_nlink = TESTED_NLINK; | |
} | |
else | |
res = -ENOENT; | |
return res; | |
} | |
static void *dummy_init(struct fuse_conn_info *conn __attribute__ ((unused)), struct fuse_config *cfg) { | |
*sem = 0; | |
__sync_synchronize(); | |
return NULL; | |
} | |
static struct fuse_operations my_ops = { | |
.init = dummy_init, | |
.getattr = dummy_getattr, | |
}; | |
static void mount_archive(void) { | |
static const char template[] = AR_MNT_TPL; | |
memcpy(mnt_point, template, AR_MNT_LEN - 1); | |
if (unlikely(mkdtemp(mnt_point) == NULL)) { | |
perror("test.c: mkdtemp failed"); | |
exit(EXIT_FAILURE); | |
} | |
args = (struct fuse_args) FUSE_ARGS_INIT(argc, argv); | |
if (unlikely(fuse_opt_parse(&args, NULL, NULL, NULL) < 0)) { | |
fputs("test.c: fuse_opt_parse failed\n", stderr); | |
exit(EXIT_FAILURE); | |
} | |
pid_t pid = fork(); | |
if (pid == 0) | |
_exit(fuse_main(args.argc, args.argv, &my_ops, NULL)); | |
else if (unlikely(pid < 0)) { | |
perror("test.c: fork failed"); | |
exit(EXIT_FAILURE); | |
} | |
else { | |
fuse_opt_free_args(&args); | |
int status; | |
for (;;) { | |
if (unlikely(waitpid(pid, &status, 0) < 0)) { | |
if (unlikely(errno == EINTR)) | |
continue; | |
fprintf(stderr, "test.c: waitpid %d failed\n", pid); | |
exit(EXIT_FAILURE); | |
} | |
if (likely(!status)) | |
return; | |
if (WIFEXITED(status)) { | |
if (unlikely(status = WEXITSTATUS(status))) { | |
fprintf(stderr, "test.c: fuse_main failed with status: %d\n", status); | |
status = -1; | |
} | |
break; | |
} | |
else if (WIFSIGNALED(status)) { | |
fprintf(stderr, "test.c: fuse_main died with signal: %d\n", WTERMSIG(status)); | |
status = -1; | |
break; | |
} | |
} | |
if (unlikely(status)) { | |
if (unlikely(rmdir(mnt_point) < 0)) | |
perror("test.c: removing mount point failed"); | |
exit(EXIT_FAILURE); | |
} | |
else | |
return; | |
} | |
} | |
static int umount_archive(void) { | |
int status = 0; | |
if (unlikely(UNMOUNT(mnt_point) < 0)) { | |
perror("test.c: u(n)mount: failed"); | |
status = -1; | |
} else if (unlikely(rmdir(mnt_point) < 0)) { | |
perror("test.c: removing mount point failed"); | |
status = -1; | |
} | |
return status; | |
} | |
int main(void) { | |
struct stat st; | |
if (unlikely((sem = mmap(0, sizeof (char), PROT_READ | PROT_WRITE, | |
MAP_SHARED | MAP_ANON | MAP_32BIT, -1, 0)) == MAP_FAILED)) { | |
perror("mmap"); | |
return -1; | |
} | |
for (int i = 200; *sem = 1, i > 0; i--) { | |
mount_archive(); | |
while (likely(*sem)) | |
__sync_synchronize(); | |
usleep(i); | |
if (unlikely(lstat(mnt_point, &st) < 0)) | |
perror("lstat"); | |
else if (st.st_mode != TESTED_MODE || st.st_nlink != TESTED_NLINK) { | |
printf("us_wait: %d, mode: %d, nlink: %ld\n", i, st.st_mode, st.st_nlink); | |
usleep(10000); /* for the umount to succeed, */ | |
} | |
if (unlikely(umount_archive() < 0)) | |
return 1; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment