fuse_mnt.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  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. #define FUSE_USE_VERSION 26
  15. #include <fuse.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <errno.h>
  19. #include <fcntl.h>
  20. #include <unistd.h>
  21. static const char memfd_content[] = "memfd-example-content";
  22. static const char memfd_path[] = "/memfd";
  23. static int memfd_getattr(const char *path, struct stat *st)
  24. {
  25. memset(st, 0, sizeof(*st));
  26. if (!strcmp(path, "/")) {
  27. st->st_mode = S_IFDIR | 0755;
  28. st->st_nlink = 2;
  29. } else if (!strcmp(path, memfd_path)) {
  30. st->st_mode = S_IFREG | 0444;
  31. st->st_nlink = 1;
  32. st->st_size = strlen(memfd_content);
  33. } else {
  34. return -ENOENT;
  35. }
  36. return 0;
  37. }
  38. static int memfd_readdir(const char *path,
  39. void *buf,
  40. fuse_fill_dir_t filler,
  41. off_t offset,
  42. struct fuse_file_info *fi)
  43. {
  44. if (strcmp(path, "/"))
  45. return -ENOENT;
  46. filler(buf, ".", NULL, 0);
  47. filler(buf, "..", NULL, 0);
  48. filler(buf, memfd_path + 1, NULL, 0);
  49. return 0;
  50. }
  51. static int memfd_open(const char *path, struct fuse_file_info *fi)
  52. {
  53. if (strcmp(path, memfd_path))
  54. return -ENOENT;
  55. if ((fi->flags & 3) != O_RDONLY)
  56. return -EACCES;
  57. /* force direct-IO */
  58. fi->direct_io = 1;
  59. return 0;
  60. }
  61. static int memfd_read(const char *path,
  62. char *buf,
  63. size_t size,
  64. off_t offset,
  65. struct fuse_file_info *fi)
  66. {
  67. size_t len;
  68. if (strcmp(path, memfd_path) != 0)
  69. return -ENOENT;
  70. sleep(1);
  71. len = strlen(memfd_content);
  72. if (offset < len) {
  73. if (offset + size > len)
  74. size = len - offset;
  75. memcpy(buf, memfd_content + offset, size);
  76. } else {
  77. size = 0;
  78. }
  79. return size;
  80. }
  81. static struct fuse_operations memfd_ops = {
  82. .getattr = memfd_getattr,
  83. .readdir = memfd_readdir,
  84. .open = memfd_open,
  85. .read = memfd_read,
  86. };
  87. int main(int argc, char *argv[])
  88. {
  89. return fuse_main(argc, argv, &memfd_ops, NULL);
  90. }