mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-19 16:16:48 +00:00
Compare commits
100
Commits
rootfd
...
passthrough
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9943f0ca2b | ||
|
|
d2df77046d | ||
|
|
e5b4e49b44 | ||
|
|
524028dc2d | ||
|
|
c7c3f398a7 | ||
|
|
23a16ee709 | ||
|
|
bfc2400746 | ||
|
|
15e5e23aae | ||
|
|
a5a944d0be | ||
|
|
d020cfc2a6 | ||
|
|
55a8243a8e | ||
|
|
178b18804e | ||
|
|
265cd454d2 | ||
|
|
f652f08910 | ||
|
|
496ca26193 | ||
|
|
6d927bc642 | ||
|
|
f4a22895b6 | ||
|
|
712b51e388 | ||
|
|
9497871cae | ||
|
|
82806df54d | ||
|
|
ab193701de | ||
|
|
49bec8f981 | ||
|
|
922aac6a71 | ||
|
|
739559fa80 | ||
|
|
ee9a0f0735 | ||
|
|
64d0a97a6f | ||
|
|
620f9ac901 | ||
|
|
a706d86f94 | ||
|
|
2aeba8988d | ||
|
|
d2d80c78a9 | ||
|
|
5d48e92e11 | ||
|
|
bb6a0e30d1 | ||
|
|
e06c671de8 | ||
|
|
0f92992631 | ||
|
|
61d95e6b7b | ||
|
|
ed5fc2a83b | ||
|
|
5f9c7e5470 | ||
|
|
57f86aba8c | ||
|
|
4b397ab5dc | ||
|
|
eddfad36c3 | ||
|
|
48d0b6adf6 | ||
|
|
45767881ce | ||
|
|
87d9f23102 | ||
|
|
2d925d871f | ||
|
|
016b980199 | ||
|
|
b48509e767 | ||
|
|
8977800020 | ||
|
|
8ead297481 | ||
|
|
86c0d10902 | ||
|
|
4d64b8c9ad | ||
|
|
1907168452 | ||
|
|
ceee1f1cbb | ||
|
|
e7536e4bbc | ||
|
|
70d94339fd | ||
|
|
e539ecaded | ||
|
|
0686c18fe4 | ||
|
|
1252062f62 | ||
|
|
45dbec907b | ||
|
|
e2a640a6ea | ||
|
|
4dd86c5e43 | ||
|
|
e9185c3610 | ||
|
|
2136d95e33 | ||
|
|
c581a7d172 | ||
|
|
c173259a73 | ||
|
|
2cd26acd23 | ||
|
|
bf9c5726bc | ||
|
|
62e68eb800 | ||
|
|
b9433d2973 | ||
|
|
a22aee9991 | ||
|
|
7e3769d083 | ||
|
|
a6686a2ed4 | ||
|
|
5d2b862898 | ||
|
|
9b5108627e | ||
|
|
c45834af93 | ||
|
|
04c6b6d4a9 | ||
|
|
16f71392fd | ||
|
|
9e6b87ae65 | ||
|
|
71b00ca4b3 | ||
|
|
0cff2d7983 | ||
|
|
c3b580b3ff | ||
|
|
6a59c31e07 | ||
|
|
885a051f2d | ||
|
|
e973fd0851 | ||
|
|
9332e42e0a | ||
|
|
fb5add18f9 | ||
|
|
025300eaf6 | ||
|
|
3d1a9005c1 | ||
|
|
e5b647cb57 | ||
|
|
dce45e2ba9 | ||
|
|
7c4f14a7db | ||
|
|
893e0d4c94 | ||
|
|
d472fb1b12 | ||
|
|
30961779c2 | ||
|
|
2bac614a40 | ||
|
|
974e01a4b1 | ||
|
|
5c956fe2d5 | ||
|
|
4d9a390866 | ||
|
|
fb1e3afdb6 | ||
|
|
10e1b7229e | ||
|
|
c9b7ed5b8a |
@@ -167,7 +167,10 @@ These options are the same regardless of whether you use them with the
|
||||
longer need the data and it can drop its cache. Recommended when
|
||||
**cache.files=partial|full|auto-full|per-process** to limit double
|
||||
caching. (default: false)
|
||||
* **direct-io-allow-mmap=BOOL**: On newer kernels (>= 6.6) it is
|
||||
* **passthrough=off|ro|wo|rw**: On Linux 6.9 and above passthrough allows for
|
||||
near native IO performance. See below for more details. (default:
|
||||
off)
|
||||
* **direct-io-allow-mmap=BOOL**: On Linux 6.6 and above it is
|
||||
possible to disable file page caching while still allowing for
|
||||
shared mmap support. mergerfs will enable this feature if available
|
||||
but an option is provided to turn it off for testing and debugging
|
||||
@@ -411,6 +414,32 @@ fact it will not be automatically included.
|
||||
**fuse** package.
|
||||
|
||||
|
||||
### passthrough
|
||||
|
||||
With Linux 6.9 and above there is a feature in FUSE called
|
||||
"passthrough" which can improve performance by allowing a union or
|
||||
overlay filesystem (like mergerfs) to pass the file descriptor of a
|
||||
file opened on an underlying filesystem to the kernel to work on
|
||||
directly rather than calls always having to go to the FUSE server
|
||||
(mergerfs). As of Linux 6.9 the functions that can be passthroughed
|
||||
are regular file read/write IO and mmap. Other functions may be added
|
||||
in the future.
|
||||
|
||||
Passthrough requires `cache.files` to be enabled. `cache.files=off`
|
||||
(which enables FUSE direct-io feature) will override `passthrough` and
|
||||
read/write requests will still be sent to mergerfs.
|
||||
|
||||
If `cache.files=off` and `direct-io-allow-mmap=true` (the default)
|
||||
then regular read/write IO will be handled by mergerfs but mmap will
|
||||
be passthroughed.
|
||||
|
||||
NOTE: `moveonenospc` will not work when using `passthrough` as it
|
||||
removes mergerfs entirely from the read/write process. If an ENOSPC
|
||||
error occurs it will be returned to the caller app immediately. Since
|
||||
mergerfs won't be handling the IO it therefore won't be able to handle
|
||||
any error returned by said IO.
|
||||
|
||||
|
||||
### inodecalc
|
||||
|
||||
Inodes (st_ino) are unique identifiers within a filesystem. Each
|
||||
@@ -1664,6 +1693,8 @@ over the suggestions below (including the benchmarking section.)
|
||||
NOTE: be sure to read about these features before changing them to
|
||||
understand what behaviors it may impact
|
||||
|
||||
* test theoretical performance using `nullrw` or mounting a ram disk
|
||||
* enable `passthrough`
|
||||
* disable `security_capability` and/or `xattr`
|
||||
* increase cache timeouts `cache.attr`, `cache.entry`, `cache.negative_entry`
|
||||
* enable (or disable) page caching (`cache.files`)
|
||||
@@ -1675,7 +1706,6 @@ understand what behaviors it may impact
|
||||
* change the number of worker threads
|
||||
* disable `posix_acl`
|
||||
* disable `async_read`
|
||||
* test theoretical performance using `nullrw` or mounting a ram disk
|
||||
* use `symlinkify` if your data is largely static and read-only
|
||||
* use tiered cache devices
|
||||
* use LVM and LVM cache to place a SSD in front of your HDDs
|
||||
@@ -1879,7 +1909,7 @@ more details.
|
||||
#### rtorrent fails with ENODEV (No such device)
|
||||
|
||||
Be sure to set
|
||||
`cache.files=partial|full|auto-full|per-processe`. rtorrent and some
|
||||
`cache.files=partial|full|auto-full|per-process`. rtorrent and some
|
||||
other applications use [mmap](http://linux.die.net/man/2/mmap) to read
|
||||
and write to files and offer no fallback to traditional methods. FUSE
|
||||
does not currently support mmap while using `direct_io`. There may be
|
||||
|
||||
@@ -667,6 +667,8 @@ int fuse_loop_mt(struct fuse *f);
|
||||
*/
|
||||
struct fuse_context *fuse_get_context(void);
|
||||
|
||||
int fuse_get_dev_fuse_fd(const struct fuse_context *);
|
||||
|
||||
/**
|
||||
* Check if the current request has already been interrupted
|
||||
*
|
||||
@@ -779,6 +781,11 @@ void fuse_gc1();
|
||||
void fuse_gc();
|
||||
void fuse_invalidate_all_nodes();
|
||||
|
||||
int fuse_passthrough_open(const struct fuse_context *fc,
|
||||
const int fd);
|
||||
int fuse_passthrough_close(const struct fuse_context *fc,
|
||||
const int backing_id);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif /* _FUSE_H_ */
|
||||
|
||||
@@ -88,26 +88,18 @@ struct fuse_file_info_t
|
||||
|
||||
uint32_t noflush:1;
|
||||
|
||||
uint32_t passthrough:1;
|
||||
|
||||
/** File handle. May be filled in by filesystem in open().
|
||||
Available in all other file operations */
|
||||
uint64_t fh;
|
||||
|
||||
uint32_t backing_id;
|
||||
|
||||
/** Lock owner id. Available in locking operations and flush */
|
||||
uint64_t lock_owner;
|
||||
};
|
||||
|
||||
/**
|
||||
* Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want'
|
||||
*
|
||||
* FUSE_CAP_ASYNC_READ: filesystem supports asynchronous read requests
|
||||
* FUSE_CAP_POSIX_LOCKS: filesystem supports "remote" locking
|
||||
* FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag
|
||||
* FUSE_CAP_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
|
||||
* FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB
|
||||
* FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations
|
||||
* FUSE_CAP_IOCTL_DIR: ioctl support on directories
|
||||
* FUSE_CAP_CACHE_SYMLINKS: cache READLINK responses
|
||||
*/
|
||||
#define FUSE_CAP_ASYNC_READ (1ULL << 0)
|
||||
#define FUSE_CAP_POSIX_LOCKS (1ULL << 1)
|
||||
#define FUSE_CAP_ATOMIC_O_TRUNC (1ULL << 3)
|
||||
@@ -127,6 +119,9 @@ struct fuse_file_info_t
|
||||
#define FUSE_CAP_SETXATTR_EXT (1ULL << 22)
|
||||
#define FUSE_CAP_DIRECT_IO_ALLOW_MMAP (1ULL << 23)
|
||||
#define FUSE_CAP_CREATE_SUPP_GROUP (1ULL << 24)
|
||||
#define FUSE_CAP_PASSTHROUGH (1ULL << 25)
|
||||
#define FUSE_CAP_HANDLE_KILLPRIV (1ULL << 26)
|
||||
#define FUSE_CAP_HANDLE_KILLPRIV_V2 (1ULL << 27)
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -211,6 +211,12 @@
|
||||
* 7.39
|
||||
* - add FUSE_DIRECT_IO_ALLOW_MMAP
|
||||
* - add FUSE_STATX and related structures
|
||||
*
|
||||
* 7.40
|
||||
* - add max_stack_depth to fuse_init_out, add FUSE_PASSTHROUGH init flag
|
||||
* - add backing_id to fuse_open_out, add FOPEN_PASSTHROUGH open flag
|
||||
* - add FUSE_NO_EXPORT_SUPPORT init flag
|
||||
* - add FUSE_NOTIFY_RESEND, add FUSE_HAS_RESEND init flag
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FUSE_H
|
||||
@@ -246,7 +252,7 @@
|
||||
#define FUSE_KERNEL_VERSION 7
|
||||
|
||||
/** Minor version number of this interface */
|
||||
#define FUSE_KERNEL_MINOR_VERSION 39
|
||||
#define FUSE_KERNEL_MINOR_VERSION 40
|
||||
|
||||
/** The node ID of the root inode */
|
||||
#define FUSE_ROOT_ID 1
|
||||
@@ -353,6 +359,7 @@ struct fuse_file_lock {
|
||||
* FOPEN_STREAM: the file is stream-like (no file position at all)
|
||||
* FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_CACHE)
|
||||
* FOPEN_PARALLEL_DIRECT_WRITES: Allow concurrent direct writes on the same inode
|
||||
* FOPEN_PASSTHROUGH: passthrough read/write io for this open file
|
||||
*/
|
||||
#define FOPEN_DIRECT_IO (1 << 0)
|
||||
#define FOPEN_KEEP_CACHE (1 << 1)
|
||||
@@ -361,6 +368,7 @@ struct fuse_file_lock {
|
||||
#define FOPEN_STREAM (1 << 4)
|
||||
#define FOPEN_NOFLUSH (1 << 5)
|
||||
#define FOPEN_PARALLEL_DIRECT_WRITES (1 << 6)
|
||||
#define FOPEN_PASSTHROUGH (1 << 7)
|
||||
|
||||
/**
|
||||
* INIT request/reply flags
|
||||
@@ -410,6 +418,9 @@ struct fuse_file_lock {
|
||||
* symlink and mknod (single group that matches parent)
|
||||
* FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation
|
||||
* FUSE_DIRECT_IO_ALLOW_MMAP: allow shared mmap in FOPEN_DIRECT_IO mode.
|
||||
* FUSE_NO_EXPORT_SUPPORT: explicitly disable export support
|
||||
* FUSE_HAS_RESEND: kernel supports resending pending requests, and the high bit
|
||||
* of the request ID indicates resend requests
|
||||
*/
|
||||
#define FUSE_ASYNC_READ (1 << 0)
|
||||
#define FUSE_POSIX_LOCKS (1 << 1)
|
||||
@@ -449,6 +460,9 @@ struct fuse_file_lock {
|
||||
#define FUSE_CREATE_SUPP_GROUP (1ULL << 34)
|
||||
#define FUSE_HAS_EXPIRE_ONLY (1ULL << 35)
|
||||
#define FUSE_DIRECT_IO_ALLOW_MMAP (1ULL << 36)
|
||||
#define FUSE_PASSTHROUGH (1ULL << 37)
|
||||
#define FUSE_NO_EXPORT_SUPPORT (1ULL << 38)
|
||||
#define FUSE_HAS_RESEND (1ULL << 39)
|
||||
|
||||
/* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */
|
||||
#define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP
|
||||
@@ -635,6 +649,7 @@ enum fuse_notify_code {
|
||||
FUSE_NOTIFY_STORE = 4,
|
||||
FUSE_NOTIFY_RETRIEVE = 5,
|
||||
FUSE_NOTIFY_DELETE = 6,
|
||||
FUSE_NOTIFY_RESEND = 7,
|
||||
FUSE_NOTIFY_CODE_MAX,
|
||||
};
|
||||
|
||||
@@ -761,7 +776,7 @@ struct fuse_create_in {
|
||||
struct fuse_open_out {
|
||||
uint64_t fh;
|
||||
uint32_t open_flags;
|
||||
uint32_t padding;
|
||||
int32_t backing_id;
|
||||
};
|
||||
|
||||
struct fuse_release_in {
|
||||
@@ -877,7 +892,8 @@ struct fuse_init_out {
|
||||
uint16_t max_pages;
|
||||
uint16_t map_alignment;
|
||||
uint32_t flags2;
|
||||
uint32_t unused[7];
|
||||
uint32_t max_stack_depth;
|
||||
uint32_t unused[6];
|
||||
};
|
||||
|
||||
#define CUSE_INIT_INFO_MAX 4096
|
||||
@@ -960,6 +976,14 @@ struct fuse_fallocate_in {
|
||||
uint32_t padding;
|
||||
};
|
||||
|
||||
/**
|
||||
* FUSE request unique ID flag
|
||||
*
|
||||
* Indicates whether this is a resend request. The receiver should handle this
|
||||
* request accordingly.
|
||||
*/
|
||||
#define FUSE_UNIQUE_RESEND (1ULL << 63)
|
||||
|
||||
struct fuse_in_header {
|
||||
uint32_t len;
|
||||
uint32_t opcode;
|
||||
@@ -1049,9 +1073,18 @@ struct fuse_notify_retrieve_in {
|
||||
uint64_t dummy4;
|
||||
};
|
||||
|
||||
struct fuse_backing_map {
|
||||
int32_t fd;
|
||||
uint32_t flags;
|
||||
uint64_t padding;
|
||||
};
|
||||
|
||||
/* Device ioctls: */
|
||||
#define FUSE_DEV_IOC_MAGIC 229
|
||||
#define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t)
|
||||
#define FUSE_DEV_IOC_BACKING_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 1, \
|
||||
struct fuse_backing_map)
|
||||
#define FUSE_DEV_IOC_BACKING_CLOSE _IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t)
|
||||
|
||||
struct fuse_lseek_in {
|
||||
uint64_t fh;
|
||||
|
||||
+4
-1
@@ -199,6 +199,7 @@ fuse_flag_to_str(const uint64_t offset_)
|
||||
FUSE_INIT_FLAG_CASE(CREATE_SUPP_GROUP);
|
||||
FUSE_INIT_FLAG_CASE(HAS_EXPIRE_ONLY);
|
||||
FUSE_INIT_FLAG_CASE(DIRECT_IO_ALLOW_MMAP);
|
||||
FUSE_INIT_FLAG_CASE(PASSTHROUGH);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -804,13 +805,15 @@ debug_fuse_init_out(const uint64_t unique_,
|
||||
" time_gran=%u;"
|
||||
" max_pages=%u;"
|
||||
" map_alignment=%u;"
|
||||
" max_stack_depth=%u;"
|
||||
"\n",
|
||||
arg->max_background,
|
||||
arg->congestion_threshold,
|
||||
arg->max_write,
|
||||
arg->time_gran,
|
||||
arg->max_pages,
|
||||
arg->map_alignment);
|
||||
arg->map_alignment,
|
||||
arg->max_stack_depth);
|
||||
}
|
||||
|
||||
static
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifdef HAVE_MALLOC_TRIM
|
||||
#include <malloc.h>
|
||||
@@ -3682,6 +3683,12 @@ fuse_get_context(void)
|
||||
return &fuse_get_context_internal()->ctx;
|
||||
}
|
||||
|
||||
int
|
||||
fuse_get_dev_fuse_fd(const struct fuse_context *fc_)
|
||||
{
|
||||
return fuse_chan_fd(fc_->fuse->se->ch);
|
||||
}
|
||||
|
||||
enum {
|
||||
KEY_HELP,
|
||||
};
|
||||
@@ -4156,3 +4163,30 @@ fuse_log_metrics_get(void)
|
||||
{
|
||||
return g_LOG_METRICS;
|
||||
}
|
||||
|
||||
int
|
||||
fuse_passthrough_open(const struct fuse_context *fc_,
|
||||
const int fd_)
|
||||
{
|
||||
int rv;
|
||||
int dev_fuse_fd;
|
||||
struct fuse_backing_map bm = {0};
|
||||
|
||||
dev_fuse_fd = fuse_get_dev_fuse_fd(fc_);
|
||||
bm.fd = fd_;
|
||||
|
||||
rv = ioctl(dev_fuse_fd,FUSE_DEV_IOC_BACKING_OPEN,&bm);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
fuse_passthrough_close(const struct fuse_context *fc_,
|
||||
const int backing_id_)
|
||||
{
|
||||
int dev_fuse_fd;
|
||||
|
||||
dev_fuse_fd = fuse_get_dev_fuse_fd(fc_);
|
||||
|
||||
return ioctl(dev_fuse_fd, FUSE_DEV_IOC_BACKING_CLOSE, &backing_id_);
|
||||
}
|
||||
|
||||
@@ -277,6 +277,11 @@ fill_open(struct fuse_open_out *arg_,
|
||||
arg_->open_flags |= FOPEN_PARALLEL_DIRECT_WRITES;
|
||||
if(ffi_->noflush)
|
||||
arg_->open_flags |= FOPEN_NOFLUSH;
|
||||
if(ffi_->passthrough)
|
||||
{
|
||||
arg_->open_flags |= FOPEN_PASSTHROUGH;
|
||||
arg_->backing_id = ffi_->backing_id;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
@@ -1175,6 +1180,12 @@ do_init(fuse_req_t req,
|
||||
f->conn.capable |= FUSE_CAP_DIRECT_IO_ALLOW_MMAP;
|
||||
if(inargflags & FUSE_CREATE_SUPP_GROUP)
|
||||
f->conn.capable |= FUSE_CAP_CREATE_SUPP_GROUP;
|
||||
if(inargflags & FUSE_PASSTHROUGH)
|
||||
f->conn.capable |= FUSE_CAP_PASSTHROUGH;
|
||||
if(inargflags & FUSE_HANDLE_KILLPRIV)
|
||||
f->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
|
||||
if(inargflags & FUSE_HANDLE_KILLPRIV_V2)
|
||||
f->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV_V2;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1248,6 +1259,15 @@ do_init(fuse_req_t req,
|
||||
outargflags |= FUSE_CREATE_SUPP_GROUP;
|
||||
if(f->conn.want & FUSE_CAP_DIRECT_IO_ALLOW_MMAP)
|
||||
outargflags |= FUSE_DIRECT_IO_ALLOW_MMAP;
|
||||
if(f->conn.want & FUSE_CAP_HANDLE_KILLPRIV)
|
||||
outargflags |= FUSE_HANDLE_KILLPRIV;
|
||||
if(f->conn.want & FUSE_CAP_HANDLE_KILLPRIV_V2)
|
||||
outargflags |= FUSE_HANDLE_KILLPRIV_V2;
|
||||
if(f->conn.want & FUSE_CAP_PASSTHROUGH)
|
||||
{
|
||||
outargflags |= FUSE_PASSTHROUGH;
|
||||
outarg.max_stack_depth = 2;
|
||||
}
|
||||
|
||||
if(inargflags & FUSE_INIT_EXT)
|
||||
{
|
||||
|
||||
+1328
File diff suppressed because it is too large
Load Diff
@@ -62,6 +62,8 @@ namespace l
|
||||
IFERT("export-support");
|
||||
IFERT("fsname");
|
||||
IFERT("fuse_msg_size");
|
||||
IFERT("handle-killpriv");
|
||||
IFERT("handle-killpriv-v2");
|
||||
IFERT("mount");
|
||||
IFERT("nullrw");
|
||||
IFERT("pid");
|
||||
@@ -103,6 +105,8 @@ Config::Config()
|
||||
fsname(),
|
||||
func(),
|
||||
fuse_msg_size(FUSE_MAX_MAX_PAGES),
|
||||
handle_killpriv(true),
|
||||
handle_killpriv_v2(true),
|
||||
ignorepponrename(false),
|
||||
inodecalc("hybrid-hash"),
|
||||
lazy_umount_mountpoint(false),
|
||||
@@ -114,6 +118,7 @@ Config::Config()
|
||||
nfsopenhack(NFSOpenHack::ENUM::OFF),
|
||||
nullrw(false),
|
||||
parallel_direct_writes(false),
|
||||
passthrough(PassthroughEnum::off),
|
||||
posix_acl(false),
|
||||
readahead(0),
|
||||
readdir("seq"),
|
||||
@@ -180,6 +185,8 @@ Config::Config()
|
||||
_map["func.unlink"] = &func.unlink;
|
||||
_map["func.utimens"] = &func.utimens;
|
||||
_map["fuse_msg_size"] = &fuse_msg_size;
|
||||
_map["handle-killpriv"] = &handle_killpriv;
|
||||
_map["handle-killpriv-v2"] = &handle_killpriv_v2;
|
||||
_map["ignorepponrename"] = &ignorepponrename;
|
||||
_map["inodecalc"] = &inodecalc;
|
||||
_map["kernel_cache"] = &kernel_cache;
|
||||
@@ -194,6 +201,7 @@ Config::Config()
|
||||
_map["nullrw"] = &nullrw;
|
||||
_map["pid"] = &pid;
|
||||
_map["parallel-direct-writes"] = ¶llel_direct_writes;
|
||||
_map["passthrough"] = &passthrough;
|
||||
_map["pin-threads"] = &fuse_pin_threads;
|
||||
_map["posix_acl"] = &posix_acl;
|
||||
_map["readahead"] = &readahead;
|
||||
|
||||
+5
-1
@@ -21,12 +21,13 @@
|
||||
#include "config_cachefiles.hpp"
|
||||
#include "config_flushonclose.hpp"
|
||||
#include "config_follow_symlinks.hpp"
|
||||
#include "config_pid.hpp"
|
||||
#include "config_inodecalc.hpp"
|
||||
#include "config_link_exdev.hpp"
|
||||
#include "config_log_metrics.hpp"
|
||||
#include "config_moveonenospc.hpp"
|
||||
#include "config_nfsopenhack.hpp"
|
||||
#include "config_passthrough.hpp"
|
||||
#include "config_pid.hpp"
|
||||
#include "config_rename_exdev.hpp"
|
||||
#include "config_set.hpp"
|
||||
#include "config_statfs.hpp"
|
||||
@@ -125,6 +126,8 @@ public:
|
||||
ConfigSTR fsname;
|
||||
Funcs func;
|
||||
ConfigUINT64 fuse_msg_size;
|
||||
ConfigBOOL handle_killpriv;
|
||||
ConfigBOOL handle_killpriv_v2;
|
||||
ConfigBOOL ignorepponrename;
|
||||
InodeCalc inodecalc;
|
||||
ConfigBOOL kernel_cache;
|
||||
@@ -137,6 +140,7 @@ public:
|
||||
NFSOpenHack nfsopenhack;
|
||||
ConfigBOOL nullrw;
|
||||
ConfigBOOL parallel_direct_writes;
|
||||
Passthrough passthrough;
|
||||
ConfigGetPid pid;
|
||||
ConfigBOOL posix_acl;
|
||||
ConfigUINT64 readahead;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2024, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config_passthrough.hpp"
|
||||
#include "ef.hpp"
|
||||
#include "errno.hpp"
|
||||
|
||||
template<>
|
||||
std::string
|
||||
Passthrough::to_string() const
|
||||
{
|
||||
return _data._to_string();
|
||||
}
|
||||
|
||||
template<>
|
||||
int
|
||||
Passthrough::from_string(const std::string &s_)
|
||||
{
|
||||
better_enums::optional<PassthroughEnum> e;
|
||||
|
||||
e = PassthroughEnum::_from_string_nothrow(s_.c_str());
|
||||
if(!e)
|
||||
return -EINVAL;
|
||||
|
||||
_data = *e;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2024, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "better_enum.hpp"
|
||||
|
||||
#include "enum.hpp"
|
||||
|
||||
|
||||
BETTER_ENUM(PassthroughEnum, uint8_t, off, ro, wo, rw);
|
||||
|
||||
typedef Enum<PassthroughEnum> Passthrough;
|
||||
@@ -60,6 +60,12 @@ public:
|
||||
return _data;
|
||||
}
|
||||
|
||||
ENUM
|
||||
operator+() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
public:
|
||||
bool operator==(const ENUM data_) const
|
||||
{
|
||||
|
||||
@@ -31,12 +31,14 @@ public:
|
||||
bool const direct_io_)
|
||||
: FH(fusepath_),
|
||||
fd(fd_),
|
||||
backing_id(0),
|
||||
direct_io(direct_io_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
int fd;
|
||||
int backing_id;
|
||||
uint32_t direct_io:1;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
@@ -170,6 +170,29 @@ namespace l
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
passthrough(const fuse_context *fc_,
|
||||
fuse_file_info_t *ffi_)
|
||||
{
|
||||
int backing_id;
|
||||
FileInfo *fi;
|
||||
const ugid::SetRootGuard ugid;
|
||||
|
||||
fi = reinterpret_cast<FileInfo*>(ffi_->fh);
|
||||
|
||||
backing_id = fuse_passthrough_open(fc_,fi->fd);
|
||||
if(backing_id <= 0)
|
||||
return 0;
|
||||
|
||||
ffi_->passthrough = true;
|
||||
ffi_->keep_cache = false;
|
||||
fi->backing_id = backing_id;
|
||||
ffi_->backing_id = backing_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
create(const Policy::Search &searchFunc_,
|
||||
@@ -208,6 +231,15 @@ namespace l
|
||||
}
|
||||
}
|
||||
|
||||
constexpr
|
||||
const
|
||||
uint64_t
|
||||
_(const PassthroughEnum e,
|
||||
const uint64_t m)
|
||||
{
|
||||
return ((((uint64_t)e) << 32) | (m & O_ACCMODE));
|
||||
}
|
||||
|
||||
namespace FUSE
|
||||
{
|
||||
int
|
||||
@@ -247,6 +279,17 @@ namespace FUSE
|
||||
fc->umask);
|
||||
}
|
||||
|
||||
if(rv != 0)
|
||||
return rv;
|
||||
|
||||
switch(_(cfg->passthrough,ffi_->flags))
|
||||
{
|
||||
case _(PassthroughEnum::ro,O_RDONLY):
|
||||
case _(PassthroughEnum::wo,O_WRONLY):
|
||||
case _(PassthroughEnum::rw,O_RDWR):
|
||||
return l::passthrough(fc,ffi_);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,8 +147,11 @@ namespace FUSE
|
||||
l::want_if_capable(conn_,FUSE_CAP_DIRECT_IO_ALLOW_MMAP,&cfg->direct_io_allow_mmap);
|
||||
l::want_if_capable(conn_,FUSE_CAP_DONT_MASK);
|
||||
l::want_if_capable(conn_,FUSE_CAP_EXPORT_SUPPORT,&cfg->export_support);
|
||||
l::want_if_capable(conn_,FUSE_CAP_HANDLE_KILLPRIV,&cfg->handle_killpriv);
|
||||
l::want_if_capable(conn_,FUSE_CAP_HANDLE_KILLPRIV_V2,&cfg->handle_killpriv_v2);
|
||||
l::want_if_capable(conn_,FUSE_CAP_IOCTL_DIR);
|
||||
l::want_if_capable(conn_,FUSE_CAP_PARALLEL_DIROPS);
|
||||
l::want_if_capable(conn_,FUSE_CAP_PASSTHROUGH);
|
||||
l::want_if_capable(conn_,FUSE_CAP_POSIX_ACL,&cfg->posix_acl);
|
||||
l::want_if_capable(conn_,FUSE_CAP_READDIR_PLUS,&cfg->readdirplus);
|
||||
l::want_if_capable(conn_,FUSE_CAP_WRITEBACK_CACHE,&cfg->writeback_cache);
|
||||
|
||||
@@ -218,6 +218,29 @@ namespace l
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
passthrough(const fuse_context *fc_,
|
||||
fuse_file_info_t *ffi_)
|
||||
{
|
||||
int backing_id;
|
||||
FileInfo *fi;
|
||||
const ugid::SetRootGuard ugid;
|
||||
|
||||
fi = reinterpret_cast<FileInfo*>(ffi_->fh);
|
||||
|
||||
backing_id = fuse_passthrough_open(fc_,fi->fd);
|
||||
if(backing_id <= 0)
|
||||
return 0;
|
||||
|
||||
ffi_->passthrough = true;
|
||||
ffi_->keep_cache = false;
|
||||
fi->backing_id = backing_id;
|
||||
ffi_->backing_id = backing_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
open(const Policy::Search &searchFunc_,
|
||||
@@ -238,6 +261,15 @@ namespace l
|
||||
}
|
||||
}
|
||||
|
||||
constexpr
|
||||
const
|
||||
uint64_t
|
||||
_(const PassthroughEnum e,
|
||||
const uint64_t m)
|
||||
{
|
||||
return ((((uint64_t)e) << 32) | (m & O_ACCMODE));
|
||||
}
|
||||
|
||||
namespace FUSE
|
||||
{
|
||||
int
|
||||
@@ -264,6 +296,17 @@ namespace FUSE
|
||||
cfg->link_cow,
|
||||
cfg->nfsopenhack);
|
||||
|
||||
if(rv != 0)
|
||||
return rv;
|
||||
|
||||
switch(_(cfg->passthrough,ffi_->flags))
|
||||
{
|
||||
case _(PassthroughEnum::ro,O_RDONLY):
|
||||
case _(PassthroughEnum::wo,O_WRONLY):
|
||||
case _(PassthroughEnum::rw,O_RDWR):
|
||||
return l::passthrough(fc,ffi_);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "fileinfo.hpp"
|
||||
#include "fs_close.hpp"
|
||||
#include "fs_fadvise.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include "fuse.h"
|
||||
|
||||
@@ -40,6 +41,16 @@ namespace l
|
||||
fs::fadvise_dontneed(fi_->fd);
|
||||
}
|
||||
|
||||
if(fi_->backing_id)
|
||||
{
|
||||
const fuse_context *fc;
|
||||
const ugid::SetRootGuard ugid;
|
||||
|
||||
fc = fuse_get_context();
|
||||
|
||||
fuse_passthrough_close(fc,fi_->backing_id);
|
||||
}
|
||||
|
||||
fs::close(fi_->fd);
|
||||
|
||||
delete fi_;
|
||||
|
||||
Reference in New Issue
Block a user