linux/tools/testing/selftests/memfd/fuse_mnt.c
<<
>>
Prefs
   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
  23static const char memfd_content[] = "memfd-example-content";
  24static const char memfd_path[] = "/memfd";
  25
  26static 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
  44static 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
  60static 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
  74static 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
 100static struct fuse_operations memfd_ops = {
 101        .getattr        = memfd_getattr,
 102        .readdir        = memfd_readdir,
 103        .open           = memfd_open,
 104        .read           = memfd_read,
 105};
 106
 107int main(int argc, char *argv[])
 108{
 109        return fuse_main(argc, argv, &memfd_ops, NULL);
 110}
 111