mirror of
https://github.com/trapexit/mergerfs.git
synced 2025-02-17 01:52:46 +08:00
Add support for 'direct-io-allow-mmap' if supported by kernel
This commit is contained in:
parent
977d04229f
commit
f0444a1ca9
10
README.md
10
README.md
|
@ -91,6 +91,11 @@ start with one of the following option sets.
|
||||||
|
|
||||||
`cache.files=auto-full,dropcacheonclose=true,category.create=mfs`
|
`cache.files=auto-full,dropcacheonclose=true,category.create=mfs`
|
||||||
|
|
||||||
|
or if you are on a Linux kernel >= 6.6.x mergerfs will enable a mode
|
||||||
|
that allows shared mmap when `cache.files=off`. To be sure of the best
|
||||||
|
performance between `cache.files=off` and `cache.files=auto-full`
|
||||||
|
you'll need to do your own benchmarking but often `off` is faster.
|
||||||
|
|
||||||
#### You don't need `mmap`
|
#### You don't need `mmap`
|
||||||
|
|
||||||
`cache.files=off,dropcacheonclose=true,category.create=mfs`
|
`cache.files=off,dropcacheonclose=true,category.create=mfs`
|
||||||
|
@ -162,6 +167,11 @@ 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
|
longer need the data and it can drop its cache. Recommended when
|
||||||
**cache.files=partial|full|auto-full|per-process** to limit double
|
**cache.files=partial|full|auto-full|per-process** to limit double
|
||||||
caching. (default: false)
|
caching. (default: false)
|
||||||
|
* **direct-io-allow-mmap=BOOL**: On newer kernels (>= 6.6) 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
|
||||||
|
purposes. (default: true)
|
||||||
* **symlinkify=BOOL**: When enabled and a file is not writable and its
|
* **symlinkify=BOOL**: When enabled and a file is not writable and its
|
||||||
mtime or ctime is older than **symlinkify_timeout** files will be
|
mtime or ctime is older than **symlinkify_timeout** files will be
|
||||||
reported as symlinks to the original files. Please read more below
|
reported as symlinks to the original files. Please read more below
|
||||||
|
|
|
@ -108,23 +108,26 @@ struct fuse_file_info_t
|
||||||
* FUSE_CAP_IOCTL_DIR: ioctl support on directories
|
* FUSE_CAP_IOCTL_DIR: ioctl support on directories
|
||||||
* FUSE_CAP_CACHE_SYMLINKS: cache READLINK responses
|
* FUSE_CAP_CACHE_SYMLINKS: cache READLINK responses
|
||||||
*/
|
*/
|
||||||
#define FUSE_CAP_ASYNC_READ (1 << 0)
|
#define FUSE_CAP_ASYNC_READ (1ULL << 0)
|
||||||
#define FUSE_CAP_POSIX_LOCKS (1 << 1)
|
#define FUSE_CAP_POSIX_LOCKS (1ULL << 1)
|
||||||
#define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3)
|
#define FUSE_CAP_ATOMIC_O_TRUNC (1ULL << 3)
|
||||||
#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
|
#define FUSE_CAP_EXPORT_SUPPORT (1ULL << 4)
|
||||||
#define FUSE_CAP_BIG_WRITES (1 << 5)
|
#define FUSE_CAP_BIG_WRITES (1ULL << 5)
|
||||||
#define FUSE_CAP_DONT_MASK (1 << 6)
|
#define FUSE_CAP_DONT_MASK (1ULL << 6)
|
||||||
#define FUSE_CAP_FLOCK_LOCKS (1 << 10)
|
#define FUSE_CAP_FLOCK_LOCKS (1ULL << 10)
|
||||||
#define FUSE_CAP_IOCTL_DIR (1 << 11)
|
#define FUSE_CAP_IOCTL_DIR (1ULL << 11)
|
||||||
#define FUSE_CAP_READDIR_PLUS (1 << 13)
|
#define FUSE_CAP_READDIR_PLUS (1ULL << 13)
|
||||||
#define FUSE_CAP_READDIR_PLUS_AUTO (1 << 14)
|
#define FUSE_CAP_READDIR_PLUS_AUTO (1ULL << 14)
|
||||||
#define FUSE_CAP_ASYNC_DIO (1 << 15)
|
#define FUSE_CAP_ASYNC_DIO (1ULL << 15)
|
||||||
#define FUSE_CAP_WRITEBACK_CACHE (1 << 16)
|
#define FUSE_CAP_WRITEBACK_CACHE (1ULL << 16)
|
||||||
#define FUSE_CAP_PARALLEL_DIROPS (1 << 18)
|
#define FUSE_CAP_PARALLEL_DIROPS (1ULL << 18)
|
||||||
#define FUSE_CAP_POSIX_ACL (1 << 19)
|
#define FUSE_CAP_POSIX_ACL (1ULL << 19)
|
||||||
#define FUSE_CAP_CACHE_SYMLINKS (1 << 20)
|
#define FUSE_CAP_CACHE_SYMLINKS (1ULL << 20)
|
||||||
#define FUSE_CAP_MAX_PAGES (1 << 21)
|
#define FUSE_CAP_MAX_PAGES (1ULL << 21)
|
||||||
#define FUSE_CAP_SETXATTR_EXT (1 << 22)
|
#define FUSE_CAP_SETXATTR_EXT (1ULL << 22)
|
||||||
|
#define FUSE_CAP_DIRECT_IO_ALLOW_MMAP (1ULL << 23)
|
||||||
|
#define FUSE_CAP_CREATE_SUPP_GROUP (1ULL << 24)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ioctl flags
|
* Ioctl flags
|
||||||
|
@ -150,56 +153,17 @@ struct fuse_file_info_t
|
||||||
* indicate the value requested by the filesystem. The requested
|
* indicate the value requested by the filesystem. The requested
|
||||||
* value must usually be smaller than the indicated value.
|
* value must usually be smaller than the indicated value.
|
||||||
*/
|
*/
|
||||||
struct fuse_conn_info {
|
struct fuse_conn_info
|
||||||
/**
|
{
|
||||||
* Major version of the protocol (read-only)
|
|
||||||
*/
|
|
||||||
unsigned proto_major;
|
unsigned proto_major;
|
||||||
|
|
||||||
/**
|
|
||||||
* Minor version of the protocol (read-only)
|
|
||||||
*/
|
|
||||||
unsigned proto_minor;
|
unsigned proto_minor;
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum size of the write buffer
|
|
||||||
*/
|
|
||||||
unsigned max_write;
|
unsigned max_write;
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum readahead
|
|
||||||
*/
|
|
||||||
unsigned max_readahead;
|
unsigned max_readahead;
|
||||||
|
uint64_t capable;
|
||||||
/**
|
uint64_t want;
|
||||||
* Capability flags, that the kernel supports
|
|
||||||
*/
|
|
||||||
unsigned capable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capability flags, that the filesystem wants to enable
|
|
||||||
*/
|
|
||||||
unsigned want;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum number of backgrounded requests
|
|
||||||
*/
|
|
||||||
unsigned max_background;
|
unsigned max_background;
|
||||||
|
|
||||||
/**
|
|
||||||
* Kernel congestion threshold parameter
|
|
||||||
*/
|
|
||||||
unsigned congestion_threshold;
|
unsigned congestion_threshold;
|
||||||
|
|
||||||
/**
|
|
||||||
* Max pages
|
|
||||||
*/
|
|
||||||
uint16_t max_pages;
|
uint16_t max_pages;
|
||||||
|
|
||||||
/**
|
|
||||||
* For future use.
|
|
||||||
*/
|
|
||||||
unsigned reserved[22];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fuse_session;
|
struct fuse_session;
|
||||||
|
|
|
@ -158,9 +158,9 @@ open_flag_to_str(const uint64_t offset_)
|
||||||
static
|
static
|
||||||
const
|
const
|
||||||
char*
|
char*
|
||||||
fuse_flag_to_str(const uint32_t offset_)
|
fuse_flag_to_str(const uint64_t offset_)
|
||||||
{
|
{
|
||||||
switch(1 << offset_)
|
switch(1ULL << offset_)
|
||||||
{
|
{
|
||||||
FUSE_INIT_FLAG_CASE(ASYNC_READ);
|
FUSE_INIT_FLAG_CASE(ASYNC_READ);
|
||||||
FUSE_INIT_FLAG_CASE(POSIX_LOCKS);
|
FUSE_INIT_FLAG_CASE(POSIX_LOCKS);
|
||||||
|
@ -189,6 +189,16 @@ fuse_flag_to_str(const uint32_t offset_)
|
||||||
FUSE_INIT_FLAG_CASE(NO_OPENDIR_SUPPORT);
|
FUSE_INIT_FLAG_CASE(NO_OPENDIR_SUPPORT);
|
||||||
FUSE_INIT_FLAG_CASE(EXPLICIT_INVAL_DATA);
|
FUSE_INIT_FLAG_CASE(EXPLICIT_INVAL_DATA);
|
||||||
FUSE_INIT_FLAG_CASE(MAP_ALIGNMENT);
|
FUSE_INIT_FLAG_CASE(MAP_ALIGNMENT);
|
||||||
|
FUSE_INIT_FLAG_CASE(SUBMOUNTS);
|
||||||
|
FUSE_INIT_FLAG_CASE(HANDLE_KILLPRIV_V2);
|
||||||
|
FUSE_INIT_FLAG_CASE(SETXATTR_EXT);
|
||||||
|
FUSE_INIT_FLAG_CASE(INIT_EXT);
|
||||||
|
FUSE_INIT_FLAG_CASE(INIT_RESERVED);
|
||||||
|
FUSE_INIT_FLAG_CASE(SECURITY_CTX);
|
||||||
|
FUSE_INIT_FLAG_CASE(HAS_INODE_DAX);
|
||||||
|
FUSE_INIT_FLAG_CASE(CREATE_SUPP_GROUP);
|
||||||
|
FUSE_INIT_FLAG_CASE(HAS_EXPIRE_ONLY);
|
||||||
|
FUSE_INIT_FLAG_CASE(DIRECT_IO_ALLOW_MMAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -200,7 +210,7 @@ static
|
||||||
void
|
void
|
||||||
debug_open_flags(const uint32_t flags_)
|
debug_open_flags(const uint32_t flags_)
|
||||||
{
|
{
|
||||||
fprintf(stderr,"%s,",open_accmode_to_str(flags_));
|
fprintf(stderr,"%s, ",open_accmode_to_str(flags_));
|
||||||
for(int i = 0; i < (sizeof(flags_) * 8); i++)
|
for(int i = 0; i < (sizeof(flags_) * 8); i++)
|
||||||
{
|
{
|
||||||
const char *str;
|
const char *str;
|
||||||
|
@ -212,7 +222,7 @@ debug_open_flags(const uint32_t flags_)
|
||||||
if(str == NULL)
|
if(str == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
fprintf(stderr,"%s,",str);
|
fprintf(stderr,"%s, ",str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,28 +727,31 @@ debug_fuse_fallocate_in(const void *arg_)
|
||||||
void
|
void
|
||||||
debug_fuse_init_in(const struct fuse_init_in *arg_)
|
debug_fuse_init_in(const struct fuse_init_in *arg_)
|
||||||
{
|
{
|
||||||
|
uint64_t flags;
|
||||||
|
|
||||||
|
flags = (((uint64_t)arg_->flags) | ((uint64_t)arg_->flags2) << 32);
|
||||||
fprintf(g_OUTPUT,
|
fprintf(g_OUTPUT,
|
||||||
"FUSE_INIT_IN: "
|
"FUSE_INIT_IN: "
|
||||||
" major=%u;"
|
" major=%u;"
|
||||||
" minor=%u;"
|
" minor=%u;"
|
||||||
" max_readahead=%u;"
|
" max_readahead=%u;"
|
||||||
" flags=0x%08X (",
|
" flags=0x%016lx (",
|
||||||
arg_->major,
|
arg_->major,
|
||||||
arg_->minor,
|
arg_->minor,
|
||||||
arg_->max_readahead,
|
arg_->max_readahead,
|
||||||
arg_->flags);
|
flags);
|
||||||
for(uint64_t i = 0; i < (sizeof(arg_->flags)*8); i++)
|
for(uint64_t i = 0; i < (sizeof(flags)*8); i++)
|
||||||
{
|
{
|
||||||
const char *str;
|
const char *str;
|
||||||
|
|
||||||
if(!(arg_->flags & (1ULL << i)))
|
if(!(flags & (1ULL << i)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
str = fuse_flag_to_str(i);
|
str = fuse_flag_to_str(i);
|
||||||
if(str == NULL)
|
if(str == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
fprintf(g_OUTPUT,"%s,",str);
|
fprintf(g_OUTPUT,"%s, ",str);
|
||||||
}
|
}
|
||||||
fprintf(g_OUTPUT,")\n");
|
fprintf(g_OUTPUT,")\n");
|
||||||
}
|
}
|
||||||
|
@ -748,7 +761,10 @@ debug_fuse_init_out(const uint64_t unique_,
|
||||||
const struct fuse_init_out *arg_,
|
const struct fuse_init_out *arg_,
|
||||||
const uint64_t argsize_)
|
const uint64_t argsize_)
|
||||||
{
|
{
|
||||||
|
uint64_t flags;
|
||||||
const struct fuse_init_out *arg = arg_;
|
const struct fuse_init_out *arg = arg_;
|
||||||
|
|
||||||
|
flags = (((uint64_t)arg->flags) | ((uint64_t)arg->flags2) << 32);
|
||||||
fprintf(g_OUTPUT,
|
fprintf(g_OUTPUT,
|
||||||
/* "unique=0x%016"PRIx64";" */
|
/* "unique=0x%016"PRIx64";" */
|
||||||
/* " opcode=RESPONSE;" */
|
/* " opcode=RESPONSE;" */
|
||||||
|
@ -758,27 +774,27 @@ debug_fuse_init_out(const uint64_t unique_,
|
||||||
" major=%u;"
|
" major=%u;"
|
||||||
" minor=%u;"
|
" minor=%u;"
|
||||||
" max_readahead=%u;"
|
" max_readahead=%u;"
|
||||||
" flags=0x%08X ("
|
" flags=0x%016lx ("
|
||||||
,
|
,
|
||||||
/* unique_, */
|
/* unique_, */
|
||||||
/* sizeof(struct fuse_out_header) + argsize_, */
|
/* sizeof(struct fuse_out_header) + argsize_, */
|
||||||
arg->major,
|
arg->major,
|
||||||
arg->minor,
|
arg->minor,
|
||||||
arg->max_readahead,
|
arg->max_readahead,
|
||||||
arg->flags);
|
flags);
|
||||||
|
|
||||||
for(uint64_t i = 0; i < (sizeof(arg->flags)*8); i++)
|
for(uint64_t i = 0; i < (sizeof(flags)*8); i++)
|
||||||
{
|
{
|
||||||
const char *str;
|
const char *str;
|
||||||
|
|
||||||
if(!(arg->flags & (1ULL << i)))
|
if(!(flags & (1ULL << i)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
str = fuse_flag_to_str(i);
|
str = fuse_flag_to_str(i);
|
||||||
if(str == NULL)
|
if(str == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
fprintf(g_OUTPUT,"%s,",str);
|
fprintf(g_OUTPUT,"%s, ",str);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(g_OUTPUT,
|
fprintf(g_OUTPUT,
|
||||||
|
|
|
@ -1097,6 +1097,11 @@ do_init(fuse_req_t req,
|
||||||
struct fuse_init_in *arg = (struct fuse_init_in *) &hdr_[1];
|
struct fuse_init_in *arg = (struct fuse_init_in *) &hdr_[1];
|
||||||
struct fuse_ll *f = req->f;
|
struct fuse_ll *f = req->f;
|
||||||
size_t bufsize = fuse_chan_bufsize(req->ch);
|
size_t bufsize = fuse_chan_bufsize(req->ch);
|
||||||
|
uint64_t inargflags;
|
||||||
|
uint64_t outargflags;
|
||||||
|
|
||||||
|
inargflags = 0;
|
||||||
|
outargflags = 0;
|
||||||
|
|
||||||
if(f->debug)
|
if(f->debug)
|
||||||
debug_fuse_init_in(arg);
|
debug_fuse_init_in(arg);
|
||||||
|
@ -1127,40 +1132,49 @@ do_init(fuse_req_t req,
|
||||||
|
|
||||||
if(arg->minor >= 6)
|
if(arg->minor >= 6)
|
||||||
{
|
{
|
||||||
|
inargflags = arg->flags;
|
||||||
|
if(inargflags & FUSE_INIT_EXT)
|
||||||
|
inargflags |= (((uint64_t)arg->flags2) << 32);
|
||||||
|
|
||||||
if(arg->max_readahead < f->conn.max_readahead)
|
if(arg->max_readahead < f->conn.max_readahead)
|
||||||
f->conn.max_readahead = arg->max_readahead;
|
f->conn.max_readahead = arg->max_readahead;
|
||||||
if(arg->flags & FUSE_ASYNC_READ)
|
|
||||||
|
if(inargflags & FUSE_ASYNC_READ)
|
||||||
f->conn.capable |= FUSE_CAP_ASYNC_READ;
|
f->conn.capable |= FUSE_CAP_ASYNC_READ;
|
||||||
if(arg->flags & FUSE_POSIX_LOCKS)
|
if(inargflags & FUSE_POSIX_LOCKS)
|
||||||
f->conn.capable |= FUSE_CAP_POSIX_LOCKS;
|
f->conn.capable |= FUSE_CAP_POSIX_LOCKS;
|
||||||
if(arg->flags & FUSE_ATOMIC_O_TRUNC)
|
if(inargflags & FUSE_ATOMIC_O_TRUNC)
|
||||||
f->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
|
f->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
|
||||||
if(arg->flags & FUSE_EXPORT_SUPPORT)
|
if(inargflags & FUSE_EXPORT_SUPPORT)
|
||||||
f->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
|
f->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
|
||||||
if(arg->flags & FUSE_BIG_WRITES)
|
if(inargflags & FUSE_BIG_WRITES)
|
||||||
f->conn.capable |= FUSE_CAP_BIG_WRITES;
|
f->conn.capable |= FUSE_CAP_BIG_WRITES;
|
||||||
if(arg->flags & FUSE_DONT_MASK)
|
if(inargflags & FUSE_DONT_MASK)
|
||||||
f->conn.capable |= FUSE_CAP_DONT_MASK;
|
f->conn.capable |= FUSE_CAP_DONT_MASK;
|
||||||
if(arg->flags & FUSE_FLOCK_LOCKS)
|
if(inargflags & FUSE_FLOCK_LOCKS)
|
||||||
f->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
|
f->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
|
||||||
if(arg->flags & FUSE_POSIX_ACL)
|
if(inargflags & FUSE_POSIX_ACL)
|
||||||
f->conn.capable |= FUSE_CAP_POSIX_ACL;
|
f->conn.capable |= FUSE_CAP_POSIX_ACL;
|
||||||
if(arg->flags & FUSE_CACHE_SYMLINKS)
|
if(inargflags & FUSE_CACHE_SYMLINKS)
|
||||||
f->conn.capable |= FUSE_CAP_CACHE_SYMLINKS;
|
f->conn.capable |= FUSE_CAP_CACHE_SYMLINKS;
|
||||||
if(arg->flags & FUSE_ASYNC_DIO)
|
if(inargflags & FUSE_ASYNC_DIO)
|
||||||
f->conn.capable |= FUSE_CAP_ASYNC_DIO;
|
f->conn.capable |= FUSE_CAP_ASYNC_DIO;
|
||||||
if(arg->flags & FUSE_PARALLEL_DIROPS)
|
if(inargflags & FUSE_PARALLEL_DIROPS)
|
||||||
f->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
|
f->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
|
||||||
if(arg->flags & FUSE_MAX_PAGES)
|
if(inargflags & FUSE_MAX_PAGES)
|
||||||
f->conn.capable |= FUSE_CAP_MAX_PAGES;
|
f->conn.capable |= FUSE_CAP_MAX_PAGES;
|
||||||
if(arg->flags & FUSE_WRITEBACK_CACHE)
|
if(inargflags & FUSE_WRITEBACK_CACHE)
|
||||||
f->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
|
f->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
|
||||||
if(arg->flags & FUSE_DO_READDIRPLUS)
|
if(inargflags & FUSE_DO_READDIRPLUS)
|
||||||
f->conn.capable |= FUSE_CAP_READDIR_PLUS;
|
f->conn.capable |= FUSE_CAP_READDIR_PLUS;
|
||||||
if(arg->flags & FUSE_READDIRPLUS_AUTO)
|
if(inargflags & FUSE_READDIRPLUS_AUTO)
|
||||||
f->conn.capable |= FUSE_CAP_READDIR_PLUS_AUTO;
|
f->conn.capable |= FUSE_CAP_READDIR_PLUS_AUTO;
|
||||||
if(arg->flags & FUSE_SETXATTR_EXT)
|
if(inargflags & FUSE_SETXATTR_EXT)
|
||||||
f->conn.capable |= FUSE_CAP_SETXATTR_EXT;
|
f->conn.capable |= FUSE_CAP_SETXATTR_EXT;
|
||||||
|
if(inargflags & FUSE_DIRECT_IO_ALLOW_MMAP)
|
||||||
|
f->conn.capable |= FUSE_CAP_DIRECT_IO_ALLOW_MMAP;
|
||||||
|
if(inargflags & FUSE_CREATE_SUPP_GROUP)
|
||||||
|
f->conn.capable |= FUSE_CAP_CREATE_SUPP_GROUP;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1191,44 +1205,57 @@ do_init(fuse_req_t req,
|
||||||
if(f->op.init)
|
if(f->op.init)
|
||||||
f->op.init(f->userdata, &f->conn);
|
f->op.init(f->userdata, &f->conn);
|
||||||
|
|
||||||
if((arg->flags & FUSE_MAX_PAGES) && (f->conn.want & FUSE_CAP_MAX_PAGES))
|
outargflags = outarg.flags;
|
||||||
|
if((inargflags & FUSE_MAX_PAGES) && (f->conn.want & FUSE_CAP_MAX_PAGES))
|
||||||
{
|
{
|
||||||
outarg.flags |= FUSE_MAX_PAGES;
|
outargflags |= FUSE_MAX_PAGES;
|
||||||
outarg.max_pages = f->conn.max_pages;
|
outarg.max_pages = f->conn.max_pages;
|
||||||
|
|
||||||
msgbuf_set_bufsize(outarg.max_pages + 1);
|
msgbuf_set_bufsize(outarg.max_pages + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(f->conn.want & FUSE_CAP_ASYNC_READ)
|
if(f->conn.want & FUSE_CAP_ASYNC_READ)
|
||||||
outarg.flags |= FUSE_ASYNC_READ;
|
outargflags |= FUSE_ASYNC_READ;
|
||||||
if(f->conn.want & FUSE_CAP_POSIX_LOCKS)
|
if(f->conn.want & FUSE_CAP_POSIX_LOCKS)
|
||||||
outarg.flags |= FUSE_POSIX_LOCKS;
|
outargflags |= FUSE_POSIX_LOCKS;
|
||||||
if(f->conn.want & FUSE_CAP_ATOMIC_O_TRUNC)
|
if(f->conn.want & FUSE_CAP_ATOMIC_O_TRUNC)
|
||||||
outarg.flags |= FUSE_ATOMIC_O_TRUNC;
|
outargflags |= FUSE_ATOMIC_O_TRUNC;
|
||||||
if(f->conn.want & FUSE_CAP_EXPORT_SUPPORT)
|
if(f->conn.want & FUSE_CAP_EXPORT_SUPPORT)
|
||||||
outarg.flags |= FUSE_EXPORT_SUPPORT;
|
outargflags |= FUSE_EXPORT_SUPPORT;
|
||||||
if(f->conn.want & FUSE_CAP_BIG_WRITES)
|
if(f->conn.want & FUSE_CAP_BIG_WRITES)
|
||||||
outarg.flags |= FUSE_BIG_WRITES;
|
outargflags |= FUSE_BIG_WRITES;
|
||||||
if(f->conn.want & FUSE_CAP_DONT_MASK)
|
if(f->conn.want & FUSE_CAP_DONT_MASK)
|
||||||
outarg.flags |= FUSE_DONT_MASK;
|
outargflags |= FUSE_DONT_MASK;
|
||||||
if(f->conn.want & FUSE_CAP_FLOCK_LOCKS)
|
if(f->conn.want & FUSE_CAP_FLOCK_LOCKS)
|
||||||
outarg.flags |= FUSE_FLOCK_LOCKS;
|
outargflags |= FUSE_FLOCK_LOCKS;
|
||||||
if(f->conn.want & FUSE_CAP_POSIX_ACL)
|
if(f->conn.want & FUSE_CAP_POSIX_ACL)
|
||||||
outarg.flags |= FUSE_POSIX_ACL;
|
outargflags |= FUSE_POSIX_ACL;
|
||||||
if(f->conn.want & FUSE_CAP_CACHE_SYMLINKS)
|
if(f->conn.want & FUSE_CAP_CACHE_SYMLINKS)
|
||||||
outarg.flags |= FUSE_CACHE_SYMLINKS;
|
outargflags |= FUSE_CACHE_SYMLINKS;
|
||||||
if(f->conn.want & FUSE_CAP_ASYNC_DIO)
|
if(f->conn.want & FUSE_CAP_ASYNC_DIO)
|
||||||
outarg.flags |= FUSE_ASYNC_DIO;
|
outargflags |= FUSE_ASYNC_DIO;
|
||||||
if(f->conn.want & FUSE_CAP_PARALLEL_DIROPS)
|
if(f->conn.want & FUSE_CAP_PARALLEL_DIROPS)
|
||||||
outarg.flags |= FUSE_PARALLEL_DIROPS;
|
outargflags |= FUSE_PARALLEL_DIROPS;
|
||||||
if(f->conn.want & FUSE_CAP_WRITEBACK_CACHE)
|
if(f->conn.want & FUSE_CAP_WRITEBACK_CACHE)
|
||||||
outarg.flags |= FUSE_WRITEBACK_CACHE;
|
outargflags |= FUSE_WRITEBACK_CACHE;
|
||||||
if(f->conn.want & FUSE_CAP_READDIR_PLUS)
|
if(f->conn.want & FUSE_CAP_READDIR_PLUS)
|
||||||
outarg.flags |= FUSE_DO_READDIRPLUS;
|
outargflags |= FUSE_DO_READDIRPLUS;
|
||||||
if(f->conn.want & FUSE_CAP_READDIR_PLUS_AUTO)
|
if(f->conn.want & FUSE_CAP_READDIR_PLUS_AUTO)
|
||||||
outarg.flags |= FUSE_READDIRPLUS_AUTO;
|
outargflags |= FUSE_READDIRPLUS_AUTO;
|
||||||
if(f->conn.want & FUSE_CAP_SETXATTR_EXT)
|
if(f->conn.want & FUSE_CAP_SETXATTR_EXT)
|
||||||
outarg.flags |= FUSE_SETXATTR_EXT;
|
outargflags |= FUSE_SETXATTR_EXT;
|
||||||
|
if(f->conn.want & FUSE_CAP_CREATE_SUPP_GROUP)
|
||||||
|
outargflags |= FUSE_CREATE_SUPP_GROUP;
|
||||||
|
if(f->conn.want & FUSE_CAP_DIRECT_IO_ALLOW_MMAP)
|
||||||
|
outargflags |= FUSE_DIRECT_IO_ALLOW_MMAP;
|
||||||
|
|
||||||
|
if(inargflags & FUSE_INIT_EXT)
|
||||||
|
{
|
||||||
|
outargflags |= FUSE_INIT_EXT;
|
||||||
|
outarg.flags2 = (outargflags >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
outarg.flags = outargflags;
|
||||||
|
|
||||||
outarg.max_readahead = f->conn.max_readahead;
|
outarg.max_readahead = f->conn.max_readahead;
|
||||||
outarg.max_write = f->conn.max_write;
|
outarg.max_write = f->conn.max_write;
|
||||||
|
@ -1247,6 +1274,9 @@ do_init(fuse_req_t req,
|
||||||
outarg.congestion_threshold = f->conn.congestion_threshold;
|
outarg.congestion_threshold = f->conn.congestion_threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(f->conn.proto_minor >= 23)
|
||||||
|
outarg.time_gran = 1;
|
||||||
|
|
||||||
size_t outargsize;
|
size_t outargsize;
|
||||||
if(arg->minor < 5)
|
if(arg->minor < 5)
|
||||||
outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
|
outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
|
||||||
|
|
|
@ -106,16 +106,22 @@ If you don\[cq]t already know that you have a special use case then just
|
||||||
start with one of the following option sets.
|
start with one of the following option sets.
|
||||||
.SS You need \f[C]mmap\f[R] (used by rtorrent and many sqlite3 base software)
|
.SS You need \f[C]mmap\f[R] (used by rtorrent and many sqlite3 base software)
|
||||||
.PP
|
.PP
|
||||||
\f[C]cache.files=partial,dropcacheonclose=true,category.create=mfs\f[R]
|
\f[C]cache.files=auto-full,dropcacheonclose=true,category.create=mfs\f[R]
|
||||||
|
.PP
|
||||||
|
or if you are on a Linux kernel >= 6.6.x mergerfs will enable a mode
|
||||||
|
that allows shared mmap when \f[C]cache.files=off\f[R].
|
||||||
|
To be sure of the best performance between \f[C]cache.files=off\f[R] and
|
||||||
|
\f[C]cache.files=auto-full\f[R] you\[cq]ll need to do your own
|
||||||
|
benchmarking but often \f[C]off\f[R] is faster.
|
||||||
.SS You don\[cq]t need \f[C]mmap\f[R]
|
.SS You don\[cq]t need \f[C]mmap\f[R]
|
||||||
.PP
|
.PP
|
||||||
\f[C]cache.files=off,dropcacheonclose=true,category.create=mfs\f[R]
|
\f[C]cache.files=off,dropcacheonclose=true,category.create=mfs\f[R]
|
||||||
.SS Command Line
|
.SS Command Line
|
||||||
.PP
|
.PP
|
||||||
\f[C]mergerfs -o cache.files=partial,dropcacheonclose=true,category.create=mfs /mnt/hdd0:/mnt/hdd1 /media\f[R]
|
\f[C]mergerfs -o cache.files=auto-full,dropcacheonclose=true,category.create=mfs /mnt/hdd0:/mnt/hdd1 /media\f[R]
|
||||||
.SS /etc/fstab
|
.SS /etc/fstab
|
||||||
.PP
|
.PP
|
||||||
\f[C]/mnt/hdd0:/mnt/hdd1 /media mergerfs cache.files=partial,dropcacheonclose=true,category.create=mfs 0 0\f[R]
|
\f[C]/mnt/hdd0:/mnt/hdd1 /media mergerfs cache.files=auto-full,dropcacheonclose=true,category.create=mfs 0 0\f[R]
|
||||||
.SS systemd mount
|
.SS systemd mount
|
||||||
.PP
|
.PP
|
||||||
https://github.com/trapexit/mergerfs/wiki/systemd
|
https://github.com/trapexit/mergerfs/wiki/systemd
|
||||||
|
@ -130,7 +136,7 @@ Type=simple
|
||||||
KillMode=none
|
KillMode=none
|
||||||
ExecStart=/usr/bin/mergerfs \[rs]
|
ExecStart=/usr/bin/mergerfs \[rs]
|
||||||
-f \[rs]
|
-f \[rs]
|
||||||
-o cache.files=partial \[rs]
|
-o cache.files=auto-full \[rs]
|
||||||
-o dropcacheonclose=true \[rs]
|
-o dropcacheonclose=true \[rs]
|
||||||
-o category.create=mfs \[rs]
|
-o category.create=mfs \[rs]
|
||||||
/mnt/hdd0:/mnt/hdd1 \[rs]
|
/mnt/hdd0:/mnt/hdd1 \[rs]
|
||||||
|
@ -185,6 +191,13 @@ Recommended when
|
||||||
caching.
|
caching.
|
||||||
(default: false)
|
(default: false)
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
|
\f[B]direct-io-allow-mmap=BOOL\f[R]: On newer kernels (>= 6.6) 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 purposes.
|
||||||
|
(default: true)
|
||||||
|
.IP \[bu] 2
|
||||||
\f[B]symlinkify=BOOL\f[R]: When enabled and a file is not writable and
|
\f[B]symlinkify=BOOL\f[R]: When enabled and a file is not writable and
|
||||||
its mtime or ctime is older than \f[B]symlinkify_timeout\f[R] files will
|
its mtime or ctime is older than \f[B]symlinkify_timeout\f[R] files will
|
||||||
be reported as symlinks to the original files.
|
be reported as symlinks to the original files.
|
||||||
|
@ -2396,8 +2409,8 @@ Take a look at the section on NFS in the #remote-filesystems for more
|
||||||
details.
|
details.
|
||||||
.SS rtorrent fails with ENODEV (No such device)
|
.SS rtorrent fails with ENODEV (No such device)
|
||||||
.PP
|
.PP
|
||||||
Be sure to set \f[C]cache.files=partial|full|auto-full|per-processe\f[R]
|
Be sure to set
|
||||||
or turn off \f[C]direct_io\f[R].
|
\f[C]cache.files=partial|full|auto-full|per-processe\f[R].
|
||||||
rtorrent and some other applications use
|
rtorrent and some other applications use
|
||||||
mmap (http://linux.die.net/man/2/mmap) to read and write to files and
|
mmap (http://linux.die.net/man/2/mmap) to read and write to files and
|
||||||
offer no fallback to traditional methods.
|
offer no fallback to traditional methods.
|
||||||
|
|
|
@ -58,6 +58,7 @@ namespace l
|
||||||
IFERT("branches-mount-timeout");
|
IFERT("branches-mount-timeout");
|
||||||
IFERT("cache.symlinks");
|
IFERT("cache.symlinks");
|
||||||
IFERT("cache.writeback");
|
IFERT("cache.writeback");
|
||||||
|
IFERT("direct-io-allow-mmap");
|
||||||
IFERT("export-support");
|
IFERT("export-support");
|
||||||
IFERT("fsname");
|
IFERT("fsname");
|
||||||
IFERT("fuse_msg_size");
|
IFERT("fuse_msg_size");
|
||||||
|
@ -94,6 +95,7 @@ Config::Config()
|
||||||
cache_symlinks(false),
|
cache_symlinks(false),
|
||||||
category(func),
|
category(func),
|
||||||
direct_io(false),
|
direct_io(false),
|
||||||
|
direct_io_allow_mmap(true),
|
||||||
dropcacheonclose(false),
|
dropcacheonclose(false),
|
||||||
export_support(true),
|
export_support(true),
|
||||||
flushonclose(FlushOnClose::ENUM::OPENED_FOR_WRITE),
|
flushonclose(FlushOnClose::ENUM::OPENED_FOR_WRITE),
|
||||||
|
@ -150,6 +152,7 @@ Config::Config()
|
||||||
_map["category.create"] = &category.create;
|
_map["category.create"] = &category.create;
|
||||||
_map["category.search"] = &category.search;
|
_map["category.search"] = &category.search;
|
||||||
_map["direct_io"] = &direct_io;
|
_map["direct_io"] = &direct_io;
|
||||||
|
_map["direct-io-allow-mmap"] = &direct_io_allow_mmap;
|
||||||
_map["dropcacheonclose"] = &dropcacheonclose;
|
_map["dropcacheonclose"] = &dropcacheonclose;
|
||||||
_map["export-support"] = &export_support;
|
_map["export-support"] = &export_support;
|
||||||
_map["flush-on-close"] = &flushonclose;
|
_map["flush-on-close"] = &flushonclose;
|
||||||
|
|
|
@ -117,6 +117,7 @@ public:
|
||||||
ConfigBOOL cache_symlinks;
|
ConfigBOOL cache_symlinks;
|
||||||
Categories category;
|
Categories category;
|
||||||
ConfigBOOL direct_io;
|
ConfigBOOL direct_io;
|
||||||
|
ConfigBOOL direct_io_allow_mmap;
|
||||||
ConfigBOOL dropcacheonclose;
|
ConfigBOOL dropcacheonclose;
|
||||||
ConfigBOOL export_support;
|
ConfigBOOL export_support;
|
||||||
FlushOnClose flushonclose;
|
FlushOnClose flushonclose;
|
||||||
|
|
|
@ -144,14 +144,15 @@ namespace FUSE
|
||||||
l::want_if_capable(conn_,FUSE_CAP_ATOMIC_O_TRUNC);
|
l::want_if_capable(conn_,FUSE_CAP_ATOMIC_O_TRUNC);
|
||||||
l::want_if_capable(conn_,FUSE_CAP_BIG_WRITES);
|
l::want_if_capable(conn_,FUSE_CAP_BIG_WRITES);
|
||||||
l::want_if_capable(conn_,FUSE_CAP_CACHE_SYMLINKS,&cfg->cache_symlinks);
|
l::want_if_capable(conn_,FUSE_CAP_CACHE_SYMLINKS,&cfg->cache_symlinks);
|
||||||
|
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_DONT_MASK);
|
||||||
l::want_if_capable(conn_,FUSE_CAP_EXPORT_SUPPORT,&cfg->export_support);
|
l::want_if_capable(conn_,FUSE_CAP_EXPORT_SUPPORT,&cfg->export_support);
|
||||||
l::want_if_capable(conn_,FUSE_CAP_IOCTL_DIR);
|
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_PARALLEL_DIROPS);
|
||||||
l::want_if_capable(conn_,FUSE_CAP_POSIX_ACL,&cfg->posix_acl);
|
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_READDIR_PLUS,&cfg->readdirplus);
|
||||||
// l::want_if_capable(conn_,FUSE_CAP_READDIR_PLUS_AUTO);
|
|
||||||
l::want_if_capable(conn_,FUSE_CAP_WRITEBACK_CACHE,&cfg->writeback_cache);
|
l::want_if_capable(conn_,FUSE_CAP_WRITEBACK_CACHE,&cfg->writeback_cache);
|
||||||
|
// l::want_if_capable(conn_,FUSE_CAP_READDIR_PLUS_AUTO);
|
||||||
l::want_if_capable_max_pages(conn_,cfg);
|
l::want_if_capable_max_pages(conn_,cfg);
|
||||||
conn_->want &= ~FUSE_CAP_POSIX_LOCKS;
|
conn_->want &= ~FUSE_CAP_POSIX_LOCKS;
|
||||||
conn_->want &= ~FUSE_CAP_FLOCK_LOCKS;
|
conn_->want &= ~FUSE_CAP_FLOCK_LOCKS;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user