License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[sfrench/cifs-2.6.git] / tools / testing / selftests / memfd / fuse_mnt.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * memfd test file-system
4  * 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 pin
8  * pages during reads(). Due to the 1s delay of this file-system, this is a
9  * 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 this
12  * file-system.
13  */
14
15 #define FUSE_USE_VERSION 26
16
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
24 static const char memfd_content[] = "memfd-example-content";
25 static const char memfd_path[] = "/memfd";
26
27 static 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
45 static 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
61 static 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
75 static 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
101 static struct fuse_operations memfd_ops = {
102         .getattr        = memfd_getattr,
103         .readdir        = memfd_readdir,
104         .open           = memfd_open,
105         .read           = memfd_read,
106 };
107
108 int main(int argc, char *argv[])
109 {
110         return fuse_main(argc, argv, &memfd_ops, NULL);
111 }