| /* | |
| * 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); | |
| } |