Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / tools / testing / selftests / memfd / fuse_mnt.c
diff --git a/kernel/tools/testing/selftests/memfd/fuse_mnt.c b/kernel/tools/testing/selftests/memfd/fuse_mnt.c
new file mode 100644 (file)
index 0000000..feacf12
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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);
+}