linux/tools/testing/selftests/memfd/fuse_mnt.c
<<
>>
Prefs
   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
  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