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