From 87b2795f2b59c54ce9450dd195a85e756a3f8aff Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Wed, 9 Jan 2019 00:01:52 -0500 Subject: [PATCH] set direct_io per open/create, now runtime configurable --- libfuse/lib/fuse.c | 7 -- src/create.cpp | 167 ++++++++++++++++++++------------------- src/fs_path.hpp | 10 +++ src/getxattr.cpp | 24 +++--- src/listxattr.cpp | 1 + src/mergerfs.cpp | 13 +--- src/open.cpp | 92 +++++++++++----------- src/opendir.cpp | 10 +-- src/option_parser.cpp | 32 ++++---- src/read.cpp | 107 ++++++++++++------------- src/setxattr.cpp | 20 +++-- src/write.cpp | 177 +++++++++++++++++++++--------------------- 12 files changed, 331 insertions(+), 329 deletions(-) diff --git a/libfuse/lib/fuse.c b/libfuse/lib/fuse.c index 74a9dcc3..540f0731 100644 --- a/libfuse/lib/fuse.c +++ b/libfuse/lib/fuse.c @@ -70,7 +70,6 @@ struct fuse_config { int set_mode; int set_uid; int set_gid; - int direct_io; int kernel_cache; int auto_cache; int intr; @@ -3138,8 +3137,6 @@ static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent, fuse_fs_release(f->fs, path, fi); forget_node(f, e.ino, 1); } else { - if (f->conf.direct_io) - fi->direct_io = 1; if (f->conf.kernel_cache) fi->keep_cache = 1; @@ -3215,8 +3212,6 @@ static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino, fuse_prepare_interrupt(f, req, &d); err = fuse_fs_open(f->fs, path, fi); if (!err) { - if (f->conf.direct_io) - fi->direct_io = 1; if (f->conf.kernel_cache) fi->keep_cache = 1; @@ -4385,7 +4380,6 @@ static const struct fuse_opt fuse_lib_opts[] = { FUSE_LIB_OPT("hard_remove", hard_remove, 1), FUSE_LIB_OPT("use_ino", use_ino, 1), FUSE_LIB_OPT("readdir_ino", readdir_ino, 1), - FUSE_LIB_OPT("direct_io", direct_io, 1), FUSE_LIB_OPT("kernel_cache", kernel_cache, 1), FUSE_LIB_OPT("auto_cache", auto_cache, 1), FUSE_LIB_OPT("noauto_cache", auto_cache, 0), @@ -4416,7 +4410,6 @@ static void fuse_lib_help(void) " -o hard_remove immediate removal (don't hide files)\n" " -o use_ino let filesystem set inode numbers\n" " -o readdir_ino try to fill in d_ino in readdir\n" -" -o direct_io use direct I/O\n" " -o kernel_cache cache files in kernel\n" " -o [no]auto_cache enable caching based on modification times (off)\n" " -o umask=M set file permissions (octal)\n" diff --git a/src/create.cpp b/src/create.cpp index 6edbbc0b..78a94b21 100644 --- a/src/create.cpp +++ b/src/create.cpp @@ -14,11 +14,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - -#include -#include - #include "config.hpp" #include "errno.hpp" #include "fileinfo.hpp" @@ -29,81 +24,92 @@ #include "rwlock.hpp" #include "ugid.hpp" +#include + +#include +#include + using std::string; using std::vector; using namespace mergerfs; -static -int -_create_core(const string &fullpath, - mode_t mode, - const mode_t umask, - const int flags) +namespace local { - if(!fs::acl::dir_has_defaults(fullpath)) - mode &= ~umask; - - return fs::open(fullpath,flags,mode); -} - -static -int -_create_core(const string &createpath, - const char *fusepath, - const mode_t mode, - const mode_t umask, - const int flags, - uint64_t &fh) -{ - int rv; - string fullpath; - - fs::path::make(&createpath,fusepath,fullpath); - - rv = _create_core(fullpath,mode,umask,flags); - if(rv == -1) - return -errno; - - fh = reinterpret_cast(new FileInfo(rv,fusepath)); + static + int + create_core(const string &fullpath_, + mode_t mode_, + const mode_t umask_, + const int flags_) + { + if(!fs::acl::dir_has_defaults(fullpath_)) + mode_ &= ~umask_; - return 0; -} + return fs::open(fullpath_,flags_,mode_); + } -static -int -_create(Policy::Func::Search searchFunc, - Policy::Func::Create createFunc, - const Branches &branches_, - const uint64_t minfreespace, - const char *fusepath, - const mode_t mode, - const mode_t umask, - const int flags, - uint64_t &fh) -{ - int rv; - string fullpath; - string fusedirpath; - vector createpaths; - vector existingpaths; + static + int + create_core(const string &createpath_, + const char *fusepath_, + const mode_t mode_, + const mode_t umask_, + const int flags_, + uint64_t *fh_) + { + int rv; + string fullpath; - fusedirpath = fs::path::dirname(fusepath); + fs::path::make(&createpath_,fusepath_,fullpath); - rv = searchFunc(branches_,fusedirpath,minfreespace,existingpaths); - if(rv == -1) - return -errno; + rv = local::create_core(fullpath,mode_,umask_,flags_); + if(rv == -1) + return -errno; - rv = createFunc(branches_,fusedirpath,minfreespace,createpaths); - if(rv == -1) - return -errno; + *fh_ = reinterpret_cast(new FileInfo(rv,fusepath_)); - rv = fs::clonepath_as_root(*existingpaths[0],*createpaths[0],fusedirpath); - if(rv == -1) - return -errno; + return 0; + } - return _create_core(*createpaths[0], - fusepath, - mode,umask,flags,fh); + static + int + create(Policy::Func::Search searchFunc_, + Policy::Func::Create createFunc_, + const Branches &branches_, + const uint64_t minfreespace_, + const char *fusepath_, + const mode_t mode_, + const mode_t umask_, + const int flags_, + uint64_t *fh_) + { + int rv; + string fullpath; + string fusedirpath; + vector createpaths; + vector existingpaths; + + fusedirpath = fs::path::dirname(fusepath_); + + rv = searchFunc_(branches_,fusedirpath,minfreespace_,existingpaths); + if(rv == -1) + return -errno; + + rv = createFunc_(branches_,fusedirpath,minfreespace_,createpaths); + if(rv == -1) + return -errno; + + rv = fs::clonepath_as_root(*existingpaths[0],*createpaths[0],fusedirpath); + if(rv == -1) + return -errno; + + return local::create_core(*createpaths[0], + fusepath_, + mode_, + umask_, + flags_, + fh_); + } } namespace mergerfs @@ -111,24 +117,25 @@ namespace mergerfs namespace fuse { int - create(const char *fusepath, - mode_t mode, - fuse_file_info *ffi) + create(const char *fusepath_, + mode_t mode_, + fuse_file_info *ffi_) { const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); const rwlock::ReadGuard readlock(&config.branches_lock); - return _create(config.getattr, - config.create, - config.branches, - config.minfreespace, - fusepath, - mode, - fc->umask, - ffi->flags, - ffi->fh); + ffi_->direct_io = config.direct_io; + return local::create(config.getattr, + config.create, + config.branches, + config.minfreespace, + fusepath_, + mode_, + fc->umask, + ffi_->flags, + &ffi_->fh); } } } diff --git a/src/fs_path.hpp b/src/fs_path.hpp index bf1c5b7d..1f82a970 100644 --- a/src/fs_path.hpp +++ b/src/fs_path.hpp @@ -46,6 +46,16 @@ namespace fs base += suffix; } + inline + void + make(const string &base_, + const char *suffix_, + string *output_) + { + *output_ = base_; + *output_ += suffix_; + } + inline void make(const string *base, diff --git a/src/getxattr.cpp b/src/getxattr.cpp index e7dca26d..c0d0ec9c 100644 --- a/src/getxattr.cpp +++ b/src/getxattr.cpp @@ -14,17 +14,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - -#include -#include - -#include -#include -#include -#include -#include - #include "config.hpp" #include "errno.hpp" #include "fs_base_getxattr.hpp" @@ -34,6 +23,17 @@ #include "ugid.hpp" #include "version.hpp" +#include + +#include +#include +#include +#include +#include + +#include +#include + static const char SECURITY_CAPABILITY[] = "security.capability"; using std::string; @@ -297,6 +297,8 @@ _getxattr_controlfile(const Config &config, _getxattr_controlfile_version(attrvalue); else if(attr[2] == "pid") _getxattr_pid(attrvalue); + else if(attr[2] == "direct_io") + _getxattr_controlfile_bool(config.direct_io,attrvalue); break; case 4: diff --git a/src/listxattr.cpp b/src/listxattr.cpp index ce2a64a7..09239f0f 100644 --- a/src/listxattr.cpp +++ b/src/listxattr.cpp @@ -57,6 +57,7 @@ _listxattr_controlfile(char *list, ("user.mergerfs.xattr") ("user.mergerfs.statfs") ("user.mergerfs.statfs_ignore") + ("user.mergerfs.direct_io") ("user.mergerfs.policies") ("user.mergerfs.version") ("user.mergerfs.pid"); diff --git a/src/mergerfs.cpp b/src/mergerfs.cpp index 435d61d3..80a64a58 100644 --- a/src/mergerfs.cpp +++ b/src/mergerfs.cpp @@ -70,7 +70,6 @@ namespace local static void get_fuse_operations(struct fuse_operations &ops, - const bool direct_io, const bool nullrw) { ops.flag_nullpath_ok = true; @@ -105,9 +104,7 @@ namespace local ops.poll = NULL; ops.read = (nullrw ? mergerfs::fuse::read_null : - (direct_io ? - mergerfs::fuse::read_direct_io : - mergerfs::fuse::read)); + mergerfs::fuse::read); ops.read_buf = (nullrw ? NULL : mergerfs::fuse::read_buf); @@ -127,9 +124,7 @@ namespace local ops.utimens = mergerfs::fuse::utimens; ops.write = (nullrw ? mergerfs::fuse::write_null : - (direct_io ? - mergerfs::fuse::write_direct_io : - mergerfs::fuse::write)); + mergerfs::fuse::write); ops.write_buf = (nullrw ? mergerfs::fuse::write_buf_null : mergerfs::fuse::write_buf); @@ -168,9 +163,7 @@ namespace mergerfs mergerfs::options::parse(args,config); local::setup_resources(); - local::get_fuse_operations(ops, - config.direct_io, - config.nullrw); + local::get_fuse_operations(ops,config.nullrw); return fuse_main(args.argc, args.argv, diff --git a/src/open.cpp b/src/open.cpp index 9f7bd4e7..39b53e9b 100644 --- a/src/open.cpp +++ b/src/open.cpp @@ -14,8 +14,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - #include "config.hpp" #include "errno.hpp" #include "fileinfo.hpp" @@ -25,58 +23,63 @@ #include "rwlock.hpp" #include "ugid.hpp" -#include +#include #include #include +#include + using std::string; using std::vector; using mergerfs::Policy; -static -int -_open_core(const string *basepath_, - const char *fusepath_, - const int flags_, - const bool link_cow_, - uint64_t &fh_) +namespace local { - int fd; - string fullpath; + static + int + open_core(const string &basepath_, + const char *fusepath_, + const int flags_, + const bool link_cow_, + uint64_t *fh_) + { + int fd; + string fullpath; - fs::path::make(basepath_,fusepath_,fullpath); + fs::path::make(basepath_,fusepath_,&fullpath); - if(link_cow_ && fs::cow::is_eligible(fullpath.c_str(),flags_)) - fs::cow::break_link(fullpath.c_str()); + if(link_cow_ && fs::cow::is_eligible(fullpath.c_str(),flags_)) + fs::cow::break_link(fullpath.c_str()); - fd = fs::open(fullpath,flags_); - if(fd == -1) - return -errno; + fd = fs::open(fullpath,flags_); + if(fd == -1) + return -errno; - fh_ = reinterpret_cast(new FileInfo(fd,fusepath_)); + *fh_ = reinterpret_cast(new FileInfo(fd,fusepath_)); - return 0; -} + return 0; + } -static -int -_open(Policy::Func::Search searchFunc_, - const Branches &branches_, - const uint64_t minfreespace_, - const char *fusepath_, - const int flags_, - const bool link_cow_, - uint64_t &fh_) -{ - int rv; - vector basepaths; + static + int + open(Policy::Func::Search searchFunc_, + const Branches &branches_, + const uint64_t minfreespace_, + const char *fusepath_, + const int flags_, + const bool link_cow_, + uint64_t *fh_) + { + int rv; + vector basepaths; - rv = searchFunc_(branches_,fusepath_,minfreespace_,basepaths); - if(rv == -1) - return -errno; + rv = searchFunc_(branches_,fusepath_,minfreespace_,basepaths); + if(rv == -1) + return -errno; - return _open_core(basepaths[0],fusepath_,flags_,link_cow_,fh_); + return local::open_core(*basepaths[0],fusepath_,flags_,link_cow_,fh_); + } } namespace mergerfs @@ -92,13 +95,14 @@ namespace mergerfs const ugid::Set ugid(fc->uid,fc->gid); const rwlock::ReadGuard readlock(&config.branches_lock); - return _open(config.open, - config.branches, - config.minfreespace, - fusepath_, - ffi_->flags, - config.link_cow, - ffi_->fh); + ffi_->direct_io = config.direct_io; + return local::open(config.open, + config.branches, + config.minfreespace, + fusepath_, + ffi_->flags, + config.link_cow, + &ffi_->fh); } } } diff --git a/src/opendir.cpp b/src/opendir.cpp index d97fcdf5..d9d02ee6 100644 --- a/src/opendir.cpp +++ b/src/opendir.cpp @@ -14,19 +14,19 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - #include "dirinfo.hpp" +#include + namespace mergerfs { namespace fuse { int - opendir(const char *fusepath, - fuse_file_info *ffi) + opendir(const char *fusepath_, + fuse_file_info *ffi_) { - ffi->fh = reinterpret_cast(new DirInfo(fusepath)); + ffi_->fh = reinterpret_cast(new DirInfo(fusepath_)); return 0; } diff --git a/src/option_parser.cpp b/src/option_parser.cpp index b49a6e2e..8edf6364 100644 --- a/src/option_parser.cpp +++ b/src/option_parser.cpp @@ -14,20 +14,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - #include "config.hpp" #include "errno.hpp" #include "fs_glob.hpp" @@ -36,6 +22,20 @@ #include "str.hpp" #include "version.hpp" +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + using std::string; using std::vector; using namespace mergerfs; @@ -211,7 +211,7 @@ parse_and_process_arg(Config &config, if(arg == "defaults") return (set_default_options(*outargs),0); else if(arg == "direct_io") - return (config.direct_io=true,1); + return (config.direct_io=true,0); return 1; } @@ -336,7 +336,7 @@ usage(void) " splice_write, splice_move\n" " -o func.=

Set function to policy

\n" " -o category.=

Set functions in category to

\n" - " -o direct_io Bypass additional caching, increases write\n" + " -o direct_io Bypass page caching, may increase write\n" " speeds at the cost of reads. Please read docs\n" " for more details as there are tradeoffs.\n" " -o use_ino Have mergerfs generate inode values rather than\n" diff --git a/src/read.cpp b/src/read.cpp index d59d35bf..668f92d9 100644 --- a/src/read.cpp +++ b/src/read.cpp @@ -14,50 +14,49 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - -#include - -#include - #include "errno.hpp" #include "fileinfo.hpp" #include "fs_base_read.hpp" -static -inline -int -_read(const int fd, - void *buf, - const size_t count, - const off_t offset) +#include + +namespace local { - int rv; + static + inline + int + read_regular(const int fd_, + void *buf_, + const size_t count_, + const off_t offset_) + { + int rv; - rv = fs::pread(fd,buf,count,offset); - if(rv == -1) - return -errno; - if(rv == 0) - return 0; + rv = fs::pread(fd_,buf_,count_,offset_); + if(rv == -1) + return -errno; + if(rv == 0) + return 0; - return count; -} + return count_; + } -static -inline -int -_read_direct_io(const int fd, - void *buf, - const size_t count, - const off_t offset) -{ - int rv; + static + inline + int + read_direct_io(const int fd_, + void *buf_, + const size_t count_, + const off_t offset_) + { + int rv; - rv = fs::pread(fd,buf,count,offset); - if(rv == -1) - return -errno; + rv = fs::pread(fd_,buf_,count_,offset_); + if(rv == -1) + return -errno; - return rv; + return rv; + } } namespace mergerfs @@ -65,38 +64,30 @@ namespace mergerfs namespace fuse { int - read(const char *fusepath, - char *buf, - size_t count, - off_t offset, - fuse_file_info *ffi) + read(const char *fusepath_, + char *buf_, + size_t count_, + off_t offset_, + fuse_file_info *ffi_) { - FileInfo *fi = reinterpret_cast(ffi->fh); + FileInfo *fi; - return ::_read(fi->fd,buf,count,offset); - } - - int - read_direct_io(const char *fusepath, - char *buf, - size_t count, - off_t offset, - fuse_file_info *ffi) - { - FileInfo *fi = reinterpret_cast(ffi->fh); + fi = reinterpret_cast(ffi_->fh); - return ::_read_direct_io(fi->fd,buf,count,offset); + if(ffi_->direct_io) + return local::read_direct_io(fi->fd,buf_,count_,offset_); + return local::read_regular(fi->fd,buf_,count_,offset_); } int - read_null(const char *fusepath, - char *buf, - size_t count, - off_t offset, - fuse_file_info *ffi) + read_null(const char *fusepath_, + char *buf_, + size_t count_, + off_t offset_, + fuse_file_info *ffi_) { - return count; + return count_; } } } diff --git a/src/setxattr.cpp b/src/setxattr.cpp index 47551bb4..2d521c4a 100644 --- a/src/setxattr.cpp +++ b/src/setxattr.cpp @@ -14,14 +14,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - -#include - -#include -#include -#include - #include "config.hpp" #include "errno.hpp" #include "fs_base_setxattr.hpp" @@ -33,6 +25,14 @@ #include "str.hpp" #include "ugid.hpp" +#include + +#include +#include +#include + +#include + static const char SECURITY_CAPABILITY[] = "security.capability"; using std::string; @@ -323,6 +323,10 @@ _setxattr_controlfile(Config &config, return _setxattr_statfsignore(attrval, flags, config.statfs_ignore); + else if(attr[2] == "direct_io") + return _setxattr_bool(attrval, + flags, + config.direct_io); break; case 4: diff --git a/src/write.cpp b/src/write.cpp index 1dd73eac..512da185 100644 --- a/src/write.cpp +++ b/src/write.cpp @@ -33,119 +33,116 @@ using std::vector; typedef int (*WriteFunc)(const int,const void*,const size_t,const off_t); -static -bool -_out_of_space(const int error) +namespace local { - return ((error == ENOSPC) || - (error == EDQUOT)); -} + static + bool + out_of_space(const int error_) + { + return ((error_ == ENOSPC) || + (error_ == EDQUOT)); + } -static -inline -int -_write(const int fd, - const void *buf, - const size_t count, - const off_t offset) -{ - int rv; + static + int + write_regular(const int fd_, + const void *buf_, + const size_t count_, + const off_t offset_) + { + int rv; - rv = fs::pwrite(fd,buf,count,offset); - if(rv == -1) - return -errno; - if(rv == 0) - return 0; + rv = fs::pwrite(fd_,buf_,count_,offset_); + if(rv == -1) + return -errno; + if(rv == 0) + return 0; - return count; -} + return count_; + } -static -inline -int -_write_direct_io(const int fd, - const void *buf, - const size_t count, - const off_t offset) -{ - int rv; + static + int + write_direct_io(const int fd_, + const void *buf_, + const size_t count_, + const off_t offset_) + { + int rv; - rv = fs::pwrite(fd,buf,count,offset); - if(rv == -1) - return -errno; + rv = fs::pwrite(fd_,buf_,count_,offset_); + if(rv == -1) + return -errno; - return rv; -} + return rv; + } -namespace mergerfs -{ - namespace fuse + static + int + write(WriteFunc func_, + const char *buf_, + const size_t count_, + const off_t offset_, + fuse_file_info *ffi_) { - static - inline - int - write(WriteFunc func, - const char *buf, - const size_t count, - const off_t offset, - fuse_file_info *ffi) - { - int rv; - FileInfo* fi = reinterpret_cast(ffi->fh); + int rv; + FileInfo* fi; - rv = func(fi->fd,buf,count,offset); - if(_out_of_space(-rv)) - { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); + fi = reinterpret_cast(ffi_->fh); - if(config.moveonenospc) - { - vector paths; - const ugid::Set ugid(0,0); - const rwlock::ReadGuard readlock(&config.branches_lock); + rv = func_(fi->fd,buf_,count_,offset_); + if(local::out_of_space(-rv)) + { + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); - config.branches.to_paths(paths); + if(config.moveonenospc) + { + vector paths; + const ugid::Set ugid(0,0); + const rwlock::ReadGuard readlock(&config.branches_lock); - rv = fs::movefile(paths,fi->fusepath,count,fi->fd); - if(rv == -1) - return -ENOSPC; + config.branches.to_paths(paths); - rv = func(fi->fd,buf,count,offset); - } - } + rv = fs::movefile(paths,fi->fusepath,count_,fi->fd); + if(rv == -1) + return -ENOSPC; - return rv; - } + rv = func_(fi->fd,buf_,count_,offset_); + } + } + return rv; + } +} +namespace mergerfs +{ + namespace fuse + { int - write(const char *fusepath, - const char *buf, - size_t count, - off_t offset, - fuse_file_info *ffi) + write(const char *fusepath_, + const char *buf_, + size_t count_, + off_t offset_, + fuse_file_info *ffi_) { - return write(_write,buf,count,offset,ffi); - } + WriteFunc wf; - int - write_direct_io(const char *fusepath, - const char *buf, - size_t count, - off_t offset, - fuse_file_info *ffi) - { - return write(_write_direct_io,buf,count,offset,ffi); + wf = ((ffi_->direct_io) ? + local::write_direct_io : + local::write_regular); + + return local::write(wf,buf_,count_,offset_,ffi_); } int - write_null(const char *fusepath, - const char *buf, - size_t count, - off_t offset, - fuse_file_info *ffi) + write_null(const char *fusepath_, + const char *buf_, + size_t count_, + off_t offset_, + fuse_file_info *ffi_) { - return count; + return count_; } } }