Linux Audio

Check our new training course

Loading...
  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}