Browse Source

make async_read optional again

pull/632/head
Antonio SJ Musumeci 5 years ago
parent
commit
ddf6a2f105
  1. 13
      README.md
  2. 5
      libfuse/include/fuse_common.h
  3. 11
      libfuse/lib/fuse_lowlevel.c
  4. 20
      man/mergerfs.1
  5. 8
      src/config.cpp
  6. 1
      src/config.hpp
  7. 2
      src/fuse_getxattr.cpp
  8. 33
      src/fuse_init.cpp
  9. 1
      src/fuse_listxattr.cpp
  10. 16
      src/option_parser.cpp

13
README.md

@ -82,6 +82,7 @@ mergerfs does **not** support the copy-on-write (CoW) behavior found in **aufs**
* **statfs=base|full**: Controls how statfs works. 'base' means it will always use all branches in statfs calculations. 'full' is in effect path preserving and only includes drives where the path exists. (default: base) * **statfs=base|full**: Controls how statfs works. 'base' means it will always use all branches in statfs calculations. 'full' is in effect path preserving and only includes drives where the path exists. (default: base)
* **statfs_ignore=none|ro|nc**: 'ro' will cause statfs calculations to ignore available space for branches mounted or tagged as 'read-only' or 'no create'. 'nc' will ignore available space for branches tagged as 'no create'. (default: none) * **statfs_ignore=none|ro|nc**: 'ro' will cause statfs calculations to ignore available space for branches mounted or tagged as 'read-only' or 'no create'. 'nc' will ignore available space for branches tagged as 'no create'. (default: none)
* **posix_acl=true|false:** enable POSIX ACL support (if supported by kernel and underlying filesystem). (default: false) * **posix_acl=true|false:** enable POSIX ACL support (if supported by kernel and underlying filesystem). (default: false)
* **async_read=true|false:** Perform reads asynchronously. If disabled or unavailable the kernel will ensure there is at most one pending read request per file handle and will attempt to order requests by offset. (default: true)
* **threads=num**: number of threads to use in multithreaded mode. When set to zero (the default) it will attempt to discover and use the number of logical cores. If the lookup fails it will fall back to using 4. If the thread count is set negative it will look up the number of cores then divide by the absolute value. ie. threads=-2 on an 8 core machine will result in 8 / 2 = 4 threads. There will always be at least 1 thread. NOTE: higher number of threads increases parallelism but usually decreases throughput. (default: number of cores) *NOTE2:* the option is unavailable when built with system libfuse. * **threads=num**: number of threads to use in multithreaded mode. When set to zero (the default) it will attempt to discover and use the number of logical cores. If the lookup fails it will fall back to using 4. If the thread count is set negative it will look up the number of cores then divide by the absolute value. ie. threads=-2 on an 8 core machine will result in 8 / 2 = 4 threads. There will always be at least 1 thread. NOTE: higher number of threads increases parallelism but usually decreases throughput. (default: number of cores) *NOTE2:* the option is unavailable when built with system libfuse.
* **fsname=name**: sets the name of the filesystem as seen in **mount**, **df**, etc. Defaults to a list of the source paths concatenated together with the longest common prefix removed. * **fsname=name**: sets the name of the filesystem as seen in **mount**, **df**, etc. Defaults to a list of the source paths concatenated together with the longest common prefix removed.
* **func.<func>=<policy>**: sets the specific FUSE function's policy. See below for the list of value types. Example: **func.getattr=newest** * **func.<func>=<policy>**: sets the specific FUSE function's policy. See below for the list of value types. Example: **func.getattr=newest**
@ -980,16 +981,18 @@ For non-Linux systems mergerfs uses a read-write lock and changes credentials on
NOTE: be sure to read about these features before changing them NOTE: be sure to read about these features before changing them
* add (or remove) `direct_io`
* add (or remove) `auto_cache`
* add (or remove) `kernel_cache`
* add (or remove) `splice_move`, `splice_read`, and `splice_write`
* enable (or disable) `direct_io`
* enable (or disable) `auto_cache`
* enable (or disable) `kernel_cache`
* enable (or disable) `splice_move`, `splice_read`, and `splice_write`
* increase cache timeouts `cache.attr`, `cache.entry`, `cache.negative_entry` * increase cache timeouts `cache.attr`, `cache.entry`, `cache.negative_entry`
* enable `cache.open` and/or `cache.statfs`
* enable `cache.open`
* enable `cache.statfs`
* enable `cache.symlinks` * enable `cache.symlinks`
* change the number opf worker threads * change the number opf worker threads
* disable `security_capability` and/or `xattr` * disable `security_capability` and/or `xattr`
* disable `posix_acl` * disable `posix_acl`
* disable `async_read`
* test theoretical performance using `nullrw` or mounting a ram disk * test theoretical performance using `nullrw` or mounting a ram disk
* use `symlinkify` if your data is largely static * use `symlinkify` if your data is largely static
* use tiered cache drives * use tiered cache drives

5
libfuse/include/fuse_common.h

@ -156,11 +156,6 @@ struct fuse_conn_info {
*/ */
unsigned proto_minor; unsigned proto_minor;
/**
* Is asynchronous read supported (read-write)
*/
unsigned async_read;
/** /**
* Maximum size of the write buffer * Maximum size of the write buffer
*/ */

11
libfuse/lib/fuse_lowlevel.c

@ -1766,8 +1766,6 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
} }
if (arg->minor >= 6) { if (arg->minor >= 6) {
if (f->conn.async_read)
f->conn.async_read = arg->flags & FUSE_ASYNC_READ;
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 (arg->flags & FUSE_ASYNC_READ)
@ -1793,7 +1791,7 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
if (arg->flags & FUSE_PARALLEL_DIROPS) if (arg->flags & FUSE_PARALLEL_DIROPS)
f->conn.capable |= FUSE_CAP_PARALLEL_DIROPS; f->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
} else { } else {
f->conn.async_read = 0;
f->conn.want &= ~FUSE_CAP_ASYNC_READ;
f->conn.max_readahead = 0; f->conn.max_readahead = 0;
} }
@ -1844,7 +1842,7 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
if (f->no_splice_move) if (f->no_splice_move)
f->conn.want &= ~FUSE_CAP_SPLICE_MOVE; f->conn.want &= ~FUSE_CAP_SPLICE_MOVE;
if (f->conn.async_read || (f->conn.want & FUSE_CAP_ASYNC_READ))
if (f->conn.want & FUSE_CAP_ASYNC_READ)
outarg.flags |= FUSE_ASYNC_READ; outarg.flags |= FUSE_ASYNC_READ;
if (f->conn.want & FUSE_CAP_POSIX_LOCKS) if (f->conn.want & FUSE_CAP_POSIX_LOCKS)
outarg.flags |= FUSE_POSIX_LOCKS; outarg.flags |= FUSE_POSIX_LOCKS;
@ -2497,8 +2495,6 @@ static const struct fuse_opt fuse_ll_opts[] = {
{ "max_background=%u", offsetof(struct fuse_ll, conn.max_background), 0 }, { "max_background=%u", offsetof(struct fuse_ll, conn.max_background), 0 },
{ "congestion_threshold=%u", { "congestion_threshold=%u",
offsetof(struct fuse_ll, conn.congestion_threshold), 0 }, offsetof(struct fuse_ll, conn.congestion_threshold), 0 },
{ "async_read", offsetof(struct fuse_ll, conn.async_read), 1 },
{ "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 },
{ "atomic_o_trunc", offsetof(struct fuse_ll, atomic_o_trunc), 1}, { "atomic_o_trunc", offsetof(struct fuse_ll, atomic_o_trunc), 1},
{ "no_remote_lock", offsetof(struct fuse_ll, no_remote_posix_lock), 1}, { "no_remote_lock", offsetof(struct fuse_ll, no_remote_posix_lock), 1},
{ "no_remote_lock", offsetof(struct fuse_ll, no_remote_flock), 1}, { "no_remote_lock", offsetof(struct fuse_ll, no_remote_flock), 1},
@ -2532,8 +2528,6 @@ static void fuse_ll_help(void)
" -o max_readahead=N set maximum readahead\n" " -o max_readahead=N set maximum readahead\n"
" -o max_background=N set number of maximum background requests\n" " -o max_background=N set number of maximum background requests\n"
" -o congestion_threshold=N set kernel's congestion threshold\n" " -o congestion_threshold=N set kernel's congestion threshold\n"
" -o async_read perform reads asynchronously (default)\n"
" -o sync_read perform reads synchronously\n"
" -o atomic_o_trunc enable atomic open+truncate support\n" " -o atomic_o_trunc enable atomic open+truncate support\n"
" -o big_writes enable larger than 4kB writes\n" " -o big_writes enable larger than 4kB writes\n"
" -o no_remote_lock disable remote file locking\n" " -o no_remote_lock disable remote file locking\n"
@ -2738,7 +2732,6 @@ struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
goto out; goto out;
} }
f->conn.async_read = 1;
f->conn.max_write = UINT_MAX; f->conn.max_write = UINT_MAX;
f->conn.max_readahead = UINT_MAX; f->conn.max_readahead = UINT_MAX;
f->atomic_o_trunc = 0; f->atomic_o_trunc = 0;

20
man/mergerfs.1

@ -181,6 +181,12 @@ create\[aq].
kernel and underlying filesystem). kernel and underlying filesystem).
(default: false) (default: false)
.IP \[bu] 2 .IP \[bu] 2
\f[B]async_read=true|false:\f[] Perform reads asynchronously.
If disabled or unavailable the kernel will ensure there is at most one
pending read request per file handle and will attempt to order requests
by offset.
(default: true)
.IP \[bu] 2
\f[B]threads=num\f[]: number of threads to use in multithreaded mode. \f[B]threads=num\f[]: number of threads to use in multithreaded mode.
When set to zero (the default) it will attempt to discover and use the When set to zero (the default) it will attempt to discover and use the
number of logical cores. number of logical cores.
@ -1965,19 +1971,21 @@ assuming there are few users.
.PP .PP
NOTE: be sure to read about these features before changing them NOTE: be sure to read about these features before changing them
.IP \[bu] 2 .IP \[bu] 2
add (or remove) \f[C]direct_io\f[]
enable (or disable) \f[C]direct_io\f[]
.IP \[bu] 2 .IP \[bu] 2
add (or remove) \f[C]auto_cache\f[]
enable (or disable) \f[C]auto_cache\f[]
.IP \[bu] 2 .IP \[bu] 2
add (or remove) \f[C]kernel_cache\f[]
enable (or disable) \f[C]kernel_cache\f[]
.IP \[bu] 2 .IP \[bu] 2
add (or remove) \f[C]splice_move\f[], \f[C]splice_read\f[], and
enable (or disable) \f[C]splice_move\f[], \f[C]splice_read\f[], and
\f[C]splice_write\f[] \f[C]splice_write\f[]
.IP \[bu] 2 .IP \[bu] 2
increase cache timeouts \f[C]cache.attr\f[], \f[C]cache.entry\f[], increase cache timeouts \f[C]cache.attr\f[], \f[C]cache.entry\f[],
\f[C]cache.negative_entry\f[] \f[C]cache.negative_entry\f[]
.IP \[bu] 2 .IP \[bu] 2
enable \f[C]cache.open\f[] and/or \f[C]cache.statfs\f[]
enable \f[C]cache.open\f[]
.IP \[bu] 2
enable \f[C]cache.statfs\f[]
.IP \[bu] 2 .IP \[bu] 2
enable \f[C]cache.symlinks\f[] enable \f[C]cache.symlinks\f[]
.IP \[bu] 2 .IP \[bu] 2
@ -1987,6 +1995,8 @@ disable \f[C]security_capability\f[] and/or \f[C]xattr\f[]
.IP \[bu] 2 .IP \[bu] 2
disable \f[C]posix_acl\f[] disable \f[C]posix_acl\f[]
.IP \[bu] 2 .IP \[bu] 2
disable \f[C]async_read\f[]
.IP \[bu] 2
test theoretical performance using \f[C]nullrw\f[] or mounting a ram test theoretical performance using \f[C]nullrw\f[] or mounting a ram
disk disk
.IP \[bu] 2 .IP \[bu] 2

8
src/config.cpp

@ -19,12 +19,12 @@
#include "fs.hpp" #include "fs.hpp"
#include "rwlock.hpp" #include "rwlock.hpp"
#include <unistd.h>
#include <sys/stat.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include <unistd.h>
#include <sys/stat.h>
#define MINFREESPACE_DEFAULT (4294967295ULL) #define MINFREESPACE_DEFAULT (4294967295ULL)
#define POLICYINIT(X) X(policies[FuseFunc::Enum::X]) #define POLICYINIT(X) X(policies[FuseFunc::Enum::X])
@ -50,6 +50,8 @@ Config::Config()
statfs_ignore(StatFSIgnore::NONE), statfs_ignore(StatFSIgnore::NONE),
posix_acl(false), posix_acl(false),
cache_symlinks(false), cache_symlinks(false),
cache_readdir(false),
async_read(true),
POLICYINIT(access), POLICYINIT(access),
POLICYINIT(chmod), POLICYINIT(chmod),
POLICYINIT(chown), POLICYINIT(chown),

1
src/config.hpp

@ -81,6 +81,7 @@ public:
bool posix_acl; bool posix_acl;
bool cache_symlinks; bool cache_symlinks;
bool cache_readdir; bool cache_readdir;
bool async_read;
public: public:
const Policy *policies[FuseFunc::Enum::END]; const Policy *policies[FuseFunc::Enum::END];

2
src/fuse_getxattr.cpp

@ -348,6 +348,8 @@ namespace l
l::getxattr_controlfile_bool(config.direct_io,attrvalue); l::getxattr_controlfile_bool(config.direct_io,attrvalue);
else if(attr[2] == "posix_acl") else if(attr[2] == "posix_acl")
l::getxattr_controlfile_bool(config.posix_acl,attrvalue); l::getxattr_controlfile_bool(config.posix_acl,attrvalue);
else if(attr[2] == "async_read")
l::getxattr_controlfile_bool(config.async_read,attrvalue);
break; break;
case 4: case 4:

33
src/fuse_init.cpp

@ -34,7 +34,7 @@ namespace l
capable(fuse_conn_info *conn_, capable(fuse_conn_info *conn_,
const int flag_) const int flag_)
{ {
return (conn_->capable & flag_);
return !!(conn_->capable & flag_);
} }
static static
@ -45,6 +45,21 @@ namespace l
if(capable(conn_,flag_)) if(capable(conn_,flag_))
want(conn_,flag_); want(conn_,flag_);
} }
static
void
want_if_capable(fuse_conn_info *conn_,
const int flag_,
bool *want_)
{
if(*want_ && l::capable(conn_,flag_))
{
l::want(conn_,flag_);
return;
}
*want_ = false;
}
} }
namespace FUSE namespace FUSE
@ -56,23 +71,15 @@ namespace FUSE
ugid::init(); ugid::init();
l::want_if_capable(conn_,FUSE_CAP_ASYNC_READ);
l::want_if_capable(conn_,FUSE_CAP_ASYNC_DIO);
l::want_if_capable(conn_,FUSE_CAP_ASYNC_READ,&c.async_read);
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,&c.cache_symlinks);
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_IOCTL_DIR); l::want_if_capable(conn_,FUSE_CAP_IOCTL_DIR);
l::want_if_capable(conn_,FUSE_CAP_ASYNC_DIO);
l::want_if_capable(conn_,FUSE_CAP_PARALLEL_DIROPS); l::want_if_capable(conn_,FUSE_CAP_PARALLEL_DIROPS);
if(c.posix_acl && l::capable(conn_,FUSE_CAP_POSIX_ACL))
l::want(conn_,FUSE_CAP_POSIX_ACL);
else
c.posix_acl = false;
if(c.cache_symlinks && l::capable(conn_,FUSE_CAP_CACHE_SYMLINKS))
l::want(conn_,FUSE_CAP_CACHE_SYMLINKS);
else
c.cache_symlinks = false;
l::want_if_capable(conn_,FUSE_CAP_POSIX_ACL,&c.posix_acl);
return &c; return &c;
} }

1
src/fuse_listxattr.cpp

@ -44,6 +44,7 @@ namespace l
string xattrs; string xattrs;
const vector<string> strs = const vector<string> strs =
buildvector<string> buildvector<string>
("user.mergerfs.async_read")
("user.mergerfs.branches") ("user.mergerfs.branches")
("user.mergerfs.cache.attr") ("user.mergerfs.cache.attr")
("user.mergerfs.cache.entry") ("user.mergerfs.cache.entry")

16
src/option_parser.cpp

@ -99,8 +99,6 @@ static
void void
set_default_options(fuse_args *args) set_default_options(fuse_args *args)
{ {
set_option(args,"atomic_o_trunc");
set_option(args,"big_writes");
set_option(args,"default_permissions"); set_option(args,"default_permissions");
} }
@ -256,6 +254,10 @@ parse_and_process_arg(Config &config,
return 0; return 0;
else if(arg == "direct_io") else if(arg == "direct_io")
return (config.direct_io=true,0); return (config.direct_io=true,0);
else if(arg == "async_read")
return (config.async_read=true,0);
else if(arg == "sync_read")
return (config.async_read=false,0);
return 1; return 1;
} }
@ -311,6 +313,10 @@ parse_and_process_kv_arg(Config &config,
rv = parse_and_process(value,config.fsname); rv = parse_and_process(value,config.fsname);
else if(key == "posix_acl") else if(key == "posix_acl")
rv = parse_and_process(value,config.posix_acl); rv = parse_and_process(value,config.posix_acl);
else if(key == "direct_io")
rv = parse_and_process(value,config.direct_io);
else if(key == "async_read")
rv = parse_and_process(value,config.async_read);
} }
if(rv == -1) if(rv == -1)
@ -444,7 +450,11 @@ usage(void)
" as 'read only' or 'no create'. 'nc' will ignore\n" " as 'read only' or 'no create'. 'nc' will ignore\n"
" available space for branches tagged as\n" " available space for branches tagged as\n"
" 'no create'. default = none\n" " 'no create'. default = none\n"
" -o posix_acl=<bool> enable POSIX ACL support\n"
" -o posix_acl=<bool> Enable POSIX ACL support. default = false\n"
" -o async_read=<bool> If disabled or unavailable the kernel will\n"
" ensure there is at most one pending read \n"
" request per file and will attempt to order\n"
" requests by offset. default = true\n"
<< std::endl; << std::endl;
} }

Loading…
Cancel
Save