111 lines
		
	
	
	
		
			2.2 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			111 lines
		
	
	
	
		
			2.2 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * memfd test file-system | ||
|  |  * This file uses FUSE to create a dummy file-system with only one file /memfd. | ||
|  |  * This file is read-only and takes 1s per read. | ||
|  |  * | ||
|  |  * This file-system is used by the memfd test-cases to force the kernel to pin | ||
|  |  * pages during reads(). Due to the 1s delay of this file-system, this is a | ||
|  |  * nice way to test race-conditions against get_user_pages() in the kernel. | ||
|  |  * | ||
|  |  * We use direct_io==1 to force the kernel to use direct-IO for this | ||
|  |  * file-system. | ||
|  |  */ | ||
|  | 
 | ||
|  | #define FUSE_USE_VERSION 26
 | ||
|  | 
 | ||
|  | #include <fuse.h>
 | ||
|  | #include <stdio.h>
 | ||
|  | #include <string.h>
 | ||
|  | #include <errno.h>
 | ||
|  | #include <fcntl.h>
 | ||
|  | #include <unistd.h>
 | ||
|  | 
 | ||
|  | static const char memfd_content[] = "memfd-example-content"; | ||
|  | static const char memfd_path[] = "/memfd"; | ||
|  | 
 | ||
|  | static int memfd_getattr(const char *path, struct stat *st) | ||
|  | { | ||
|  | 	memset(st, 0, sizeof(*st)); | ||
|  | 
 | ||
|  | 	if (!strcmp(path, "/")) { | ||
|  | 		st->st_mode = S_IFDIR | 0755; | ||
|  | 		st->st_nlink = 2; | ||
|  | 	} else if (!strcmp(path, memfd_path)) { | ||
|  | 		st->st_mode = S_IFREG | 0444; | ||
|  | 		st->st_nlink = 1; | ||
|  | 		st->st_size = strlen(memfd_content); | ||
|  | 	} else { | ||
|  | 		return -ENOENT; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int memfd_readdir(const char *path, | ||
|  | 			 void *buf, | ||
|  | 			 fuse_fill_dir_t filler, | ||
|  | 			 off_t offset, | ||
|  | 			 struct fuse_file_info *fi) | ||
|  | { | ||
|  | 	if (strcmp(path, "/")) | ||
|  | 		return -ENOENT; | ||
|  | 
 | ||
|  | 	filler(buf, ".", NULL, 0); | ||
|  | 	filler(buf, "..", NULL, 0); | ||
|  | 	filler(buf, memfd_path + 1, NULL, 0); | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int memfd_open(const char *path, struct fuse_file_info *fi) | ||
|  | { | ||
|  | 	if (strcmp(path, memfd_path)) | ||
|  | 		return -ENOENT; | ||
|  | 
 | ||
|  | 	if ((fi->flags & 3) != O_RDONLY) | ||
|  | 		return -EACCES; | ||
|  | 
 | ||
|  | 	/* force direct-IO */ | ||
|  | 	fi->direct_io = 1; | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int memfd_read(const char *path, | ||
|  | 		      char *buf, | ||
|  | 		      size_t size, | ||
|  | 		      off_t offset, | ||
|  | 		      struct fuse_file_info *fi) | ||
|  | { | ||
|  | 	size_t len; | ||
|  | 
 | ||
|  | 	if (strcmp(path, memfd_path) != 0) | ||
|  | 		return -ENOENT; | ||
|  | 
 | ||
|  | 	sleep(1); | ||
|  | 
 | ||
|  | 	len = strlen(memfd_content); | ||
|  | 	if (offset < len) { | ||
|  | 		if (offset + size > len) | ||
|  | 			size = len - offset; | ||
|  | 
 | ||
|  | 		memcpy(buf, memfd_content + offset, size); | ||
|  | 	} else { | ||
|  | 		size = 0; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return size; | ||
|  | } | ||
|  | 
 | ||
|  | static struct fuse_operations memfd_ops = { | ||
|  | 	.getattr	= memfd_getattr, | ||
|  | 	.readdir	= memfd_readdir, | ||
|  | 	.open		= memfd_open, | ||
|  | 	.read		= memfd_read, | ||
|  | }; | ||
|  | 
 | ||
|  | int main(int argc, char *argv[]) | ||
|  | { | ||
|  | 	return fuse_main(argc, argv, &memfd_ops, NULL); | ||
|  | } |