// SPDX-License-Identifier: GPL-2.0 /* * memfd test file-system * This file uses FUSE to create a dummy file-system with only one file /memfd. * This file is read-only and takes 1s per read. * * This file-system is used by the memfd test-cases to force the kernel to pin * pages during reads(). Due to the 1s delay of this file-system, this is a * nice way to test race-conditions against get_user_pages() in the kernel. * * We use direct_io==1 to force the kernel to use direct-IO for this * file-system. */ #define FUSE_USE_VERSION 26 #include <fuse.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> static const char memfd_content[] = "memfd-example-content"; static const char memfd_path[] = "/memfd"; static int memfd_getattr(const char *path, struct stat *st) { memset(st, 0, sizeof(*st)); if (!strcmp(path, "/")) { st->st_mode = S_IFDIR | 0755; st->st_nlink = 2; } else if (!strcmp(path, memfd_path)) { st->st_mode = S_IFREG | 0444; st->st_nlink = 1; st->st_size = strlen(memfd_content); } else { return -ENOENT; } return 0; } static int memfd_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { if (strcmp(path, "/")) return -ENOENT; filler(buf, ".", NULL, 0); filler(buf, "..", NULL, 0); filler(buf, memfd_path + 1, NULL, 0); return 0; } static int memfd_open(const char *path, struct fuse_file_info *fi) { if (strcmp(path, memfd_path)) return -ENOENT; if ((fi->flags & 3) != O_RDONLY) return -EACCES; /* force direct-IO */ fi->direct_io = 1; return 0; } static int memfd_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { size_t len; if (strcmp(path, memfd_path) != 0) return -ENOENT; sleep(1); len = strlen(memfd_content); if (offset < len) { if (offset + size > len) size = len - offset; memcpy(buf, memfd_content + offset, size); } else { size = 0; } return size; } static struct fuse_operations memfd_ops = { .getattr = memfd_getattr, .readdir = memfd_readdir, .open = memfd_open, .read = memfd_read, }; int main(int argc, char *argv[]) { return fuse_main(argc, argv, &memfd_ops, NULL); }