1 /* 2 * memfd test file-system 3 * This file uses FUSE to create a dummy file-system with only one file /memfd. 4 * This file is read-only and takes 1s per read. 5 * 6 * This file-system is used by the memfd test-cases to force the kernel to pin 7 * pages during reads(). Due to the 1s delay of this file-system, this is a 8 * nice way to test race-conditions against get_user_pages() in the kernel. 9 * 10 * We use direct_io==1 to force the kernel to use direct-IO for this 11 * file-system. 12 */ 13 14 #define FUSE_USE_VERSION 26 15 16 #include <fuse.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <errno.h> 20 #include <fcntl.h> 21 #include <unistd.h> 22 23 static const char memfd_content[] = "memfd-example-content"; 24 static const char memfd_path[] = "/memfd"; 25 26 static int memfd_getattr(const char *path, struct stat *st) 27 { 28 memset(st, 0, sizeof(*st)); 29 30 if (!strcmp(path, "/")) { 31 st->st_mode = S_IFDIR | 0755; 32 st->st_nlink = 2; 33 } else if (!strcmp(path, memfd_path)) { 34 st->st_mode = S_IFREG | 0444; 35 st->st_nlink = 1; 36 st->st_size = strlen(memfd_content); 37 } else { 38 return -ENOENT; 39 } 40 41 return 0; 42 } 43 44 static int memfd_readdir(const char *path, 45 void *buf, 46 fuse_fill_dir_t filler, 47 off_t offset, 48 struct fuse_file_info *fi) 49 { 50 if (strcmp(path, "/")) 51 return -ENOENT; 52 53 filler(buf, ".", NULL, 0); 54 filler(buf, "..", NULL, 0); 55 filler(buf, memfd_path + 1, NULL, 0); 56 57 return 0; 58 } 59 60 static int memfd_open(const char *path, struct fuse_file_info *fi) 61 { 62 if (strcmp(path, memfd_path)) 63 return -ENOENT; 64 65 if ((fi->flags & 3) != O_RDONLY) 66 return -EACCES; 67 68 /* force direct-IO */ 69 fi->direct_io = 1; 70 71 return 0; 72 } 73 74 static int memfd_read(const char *path, 75 char *buf, 76 size_t size, 77 off_t offset, 78 struct fuse_file_info *fi) 79 { 80 size_t len; 81 82 if (strcmp(path, memfd_path) != 0) 83 return -ENOENT; 84 85 sleep(1); 86 87 len = strlen(memfd_content); 88 if (offset < len) { 89 if (offset + size > len) 90 size = len - offset; 91 92 memcpy(buf, memfd_content + offset, size); 93 } else { 94 size = 0; 95 } 96 97 return size; 98 } 99 100 static struct fuse_operations memfd_ops = { 101 .getattr = memfd_getattr, 102 .readdir = memfd_readdir, 103 .open = memfd_open, 104 .read = memfd_read, 105 }; 106 107 int main(int argc, char *argv[]) 108 { 109 return fuse_main(argc, argv, &memfd_ops, NULL); 110 } 111