mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
2.2 KiB
111 lines
2.2 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
/* |
|
* 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); |
|
}
|
|
|