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);
							 | 
						||
| 
								 | 
							
								}
							 |