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