Browse Source

Merge pull request #1275 from trapexit/noflush

Add flushonclose feature
pull/1276/head
trapexit 1 year ago
committed by GitHub
parent
commit
7890a4996c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      README.md
  2. 2
      libfuse/include/fuse_common.h
  3. 2
      libfuse/lib/fuse_lowlevel.c
  4. 25
      man/mergerfs.1
  5. 4
      src/config.cpp
  6. 4
      src/config.hpp
  7. 54
      src/config_flushonclose.cpp
  8. 31
      src/config_flushonclose.hpp
  9. 28
      src/fuse_create.cpp
  10. 21
      src/fuse_open.cpp
  11. 2
      src/fuse_opendir.cpp

24
README.md

@ -248,6 +248,9 @@ These options are the same regardless of whether you use them with the
to the same as the process thread count. (default: 0) to the same as the process thread count. (default: 0)
* **pin-threads=STR**: Selects a strategy to pin threads to CPUs * **pin-threads=STR**: Selects a strategy to pin threads to CPUs
(default: unset) (default: unset)
* **flush-on-close=never|always|opened-for-write**: Flush data cache
on file close. Mostly for when writeback is enabled or merging
network filesystems. (default: opened-for-write)
* **scheduling-priority=INT**: Set mergerfs' scheduling * **scheduling-priority=INT**: Set mergerfs' scheduling
priority. Valid values range from -20 to 19. See `setpriority` man priority. Valid values range from -20 to 19. See `setpriority` man
page for more details. (default: -10) page for more details. (default: -10)
@ -926,6 +929,27 @@ The options `statfs` and `statfs_ignore` can be used to modify
`statfs` behavior. `statfs` behavior.
#### flush-on-close
https://lkml.kernel.org/linux-fsdevel/20211024132607.1636952-1-amir73il@gmail.com/T/
By default FUSE would issue a flush before the release of a file
descriptor. This was considered a bit aggressive and a feature added
to give the FUSE server the ability to choose when that happens.
Options:
* always
* never
* opened-for-write
For now it defaults to "opened-for-write" which is less aggressive
than the behavior before this feature was added. It should not be a
problem because the flush is really only relevant when a file is
written to. Given flush is irrelevant for many filesystems in the
future a branch specific flag may be added so only files opened on a
specific branch would be flushed on close.
# ERROR HANDLING # ERROR HANDLING
POSIX filesystem functions offer a single return code meaning that POSIX filesystem functions offer a single return code meaning that

2
libfuse/include/fuse_common.h

@ -86,6 +86,8 @@ struct fuse_file_info_t
uint32_t parallel_direct_writes:1; uint32_t parallel_direct_writes:1;
uint32_t noflush:1;
/** File handle. May be filled in by filesystem in open(). /** File handle. May be filled in by filesystem in open().
Available in all other file operations */ Available in all other file operations */
uint64_t fh; uint64_t fh;

2
libfuse/lib/fuse_lowlevel.c

@ -275,6 +275,8 @@ fill_open(struct fuse_open_out *arg_,
arg_->open_flags |= FOPEN_CACHE_DIR; arg_->open_flags |= FOPEN_CACHE_DIR;
if(ffi_->parallel_direct_writes) if(ffi_->parallel_direct_writes)
arg_->open_flags |= FOPEN_PARALLEL_DIRECT_WRITES; arg_->open_flags |= FOPEN_PARALLEL_DIRECT_WRITES;
if(ffi_->noflush)
arg_->open_flags |= FOPEN_NOFLUSH;
} }
int int

25
man/mergerfs.1

@ -321,11 +321,18 @@ by the number of process threads plus read thread count.
\f[B]pin-threads=STR\f[R]: Selects a strategy to pin threads to CPUs \f[B]pin-threads=STR\f[R]: Selects a strategy to pin threads to CPUs
(default: unset) (default: unset)
.IP \[bu] 2 .IP \[bu] 2
\f[B]flush-on-close=never|always|opened-for-write\f[R]: Flush data cache
on file close.
Mostly for when writeback is enabled or merging network filesystems.
(default: opened-for-write)
.RS 2
.IP \[bu] 2
\f[B]scheduling-priority=INT\f[R]: Set mergerfs\[cq] scheduling \f[B]scheduling-priority=INT\f[R]: Set mergerfs\[cq] scheduling
priority. priority.
Valid values range from -20 to 19. Valid values range from -20 to 19.
See \f[C]setpriority\f[R] man page for more details. See \f[C]setpriority\f[R] man page for more details.
(default: -10) (default: -10)
.RE
.IP \[bu] 2 .IP \[bu] 2
\f[B]fsname=STR\f[R]: Sets the name of the filesystem as seen in \f[B]fsname=STR\f[R]: Sets the name of the filesystem as seen in
\f[B]mount\f[R], \f[B]df\f[R], etc. \f[B]mount\f[R], \f[B]df\f[R], etc.
@ -1321,6 +1328,24 @@ be included when checking the mount\[cq]s stats.
.PP .PP
The options \f[C]statfs\f[R] and \f[C]statfs_ignore\f[R] can be used to The options \f[C]statfs\f[R] and \f[C]statfs_ignore\f[R] can be used to
modify \f[C]statfs\f[R] behavior. modify \f[C]statfs\f[R] behavior.
.SS flush-on-close
.PP
https://lkml.kernel.org/linux-fsdevel/20211024132607.1636952-1-amir73il\[at]gmail.com/T/
.PP
By default FUSE would issue a flush before the release of a file
descriptor.
This was considered a bit aggressive and a feature added to give the
FUSE server the ability to choose when that happens.
.PP
Options: * always * never * opened-for-write
.PP
For now it defaults to \[lq]opened-for-write\[rq] which is less
aggressive than the behavior before this feature was added.
It should not be a problem because the flush is really only relevant
when a file is written to.
Given flush is irrelevant for many filesystems in the future a branch
specific flag may be added so only files opened on a specific branch
would be flushed on close.
.SH ERROR HANDLING .SH ERROR HANDLING
.PP .PP
POSIX filesystem functions offer a single return code meaning that there POSIX filesystem functions offer a single return code meaning that there

4
src/config.cpp

@ -94,8 +94,9 @@ Config::Config()
category(func), category(func),
direct_io(false), direct_io(false),
dropcacheonclose(false), dropcacheonclose(false),
fsname(),
flushonclose(FlushOnClose::ENUM::ALWAYS),
follow_symlinks(FollowSymlinks::ENUM::NEVER), follow_symlinks(FollowSymlinks::ENUM::NEVER),
fsname(),
func(), func(),
fuse_msg_size(FUSE_MAX_MAX_PAGES), fuse_msg_size(FUSE_MAX_MAX_PAGES),
ignorepponrename(false), ignorepponrename(false),
@ -149,6 +150,7 @@ Config::Config()
_map["category.search"] = &category.search; _map["category.search"] = &category.search;
_map["direct_io"] = &direct_io; _map["direct_io"] = &direct_io;
_map["dropcacheonclose"] = &dropcacheonclose; _map["dropcacheonclose"] = &dropcacheonclose;
_map["flush-on-close"] = &flushonclose;
_map["follow-symlinks"] = &follow_symlinks; _map["follow-symlinks"] = &follow_symlinks;
_map["fsname"] = &fsname; _map["fsname"] = &fsname;
_map["func.access"] = &func.access; _map["func.access"] = &func.access;

4
src/config.hpp

@ -19,6 +19,7 @@
#include "branches.hpp" #include "branches.hpp"
#include "category.hpp" #include "category.hpp"
#include "config_cachefiles.hpp" #include "config_cachefiles.hpp"
#include "config_flushonclose.hpp"
#include "config_follow_symlinks.hpp" #include "config_follow_symlinks.hpp"
#include "config_inodecalc.hpp" #include "config_inodecalc.hpp"
#include "config_link_exdev.hpp" #include "config_link_exdev.hpp"
@ -116,8 +117,9 @@ public:
Categories category; Categories category;
ConfigBOOL direct_io; ConfigBOOL direct_io;
ConfigBOOL dropcacheonclose; ConfigBOOL dropcacheonclose;
ConfigSTR fsname;
FlushOnClose flushonclose;
FollowSymlinks follow_symlinks; FollowSymlinks follow_symlinks;
ConfigSTR fsname;
Funcs func; Funcs func;
ConfigUINT64 fuse_msg_size; ConfigUINT64 fuse_msg_size;
ConfigBOOL ignorepponrename; ConfigBOOL ignorepponrename;

54
src/config_flushonclose.cpp

@ -0,0 +1,54 @@
/*
ISC License
Copyright (c) 2023, 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_flushonclose.hpp"
#include "ef.hpp"
#include "errno.hpp"
template<>
std::string
FlushOnClose::to_string() const
{
switch(_data)
{
case FlushOnClose::ENUM::NEVER:
return "never";
case FlushOnClose::ENUM::OPENED_FOR_WRITE:
return "opened-for-write";
case FlushOnClose::ENUM::ALWAYS:
return "always";
}
return {};
}
template<>
int
FlushOnClose::from_string(const std::string &s_)
{
if(s_ == "never")
_data = FlushOnClose::ENUM::NEVER;
ef(s_ == "opened-for-write")
_data = FlushOnClose::ENUM::OPENED_FOR_WRITE;
ef(s_ == "always")
_data = FlushOnClose::ENUM::ALWAYS;
else
return -EINVAL;
return 0;
}

31
src/config_flushonclose.hpp

@ -0,0 +1,31 @@
/*
ISC License
Copyright (c) 2023, 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 "enum.hpp"
enum class FlushOnCloseEnum
{
NEVER,
OPENED_FOR_WRITE,
ALWAYS
};
typedef Enum<FlushOnCloseEnum> FlushOnClose;

28
src/fuse_create.cpp

@ -51,6 +51,31 @@ namespace l
*flags_ &= ~O_APPEND; *flags_ &= ~O_APPEND;
} }
static
bool
rdonly(const int flags_)
{
return ((flags_ & O_ACCMODE) == O_RDONLY);
}
static
bool
calculate_flush(FlushOnClose const flushonclose_,
int const flags_)
{
switch(flushonclose_)
{
case FlushOnCloseEnum::NEVER:
return false;
case FlushOnCloseEnum::OPENED_FOR_WRITE:
return !l::rdonly(flags_);
case FlushOnCloseEnum::ALWAYS:
return true;
}
return true;
}
static static
void void
config_to_ffi_flags(Config::Read &cfg_, config_to_ffi_flags(Config::Read &cfg_,
@ -200,6 +225,9 @@ namespace FUSE
if(cfg->writeback_cache) if(cfg->writeback_cache)
l::tweak_flags_writeback_cache(&ffi_->flags); l::tweak_flags_writeback_cache(&ffi_->flags);
ffi_->noflush = !l::calculate_flush(cfg->flushonclose,
ffi_->flags);
rv = l::create(cfg->func.getattr.policy, rv = l::create(cfg->func.getattr.policy,
cfg->func.create.policy, cfg->func.create.policy,
cfg->branches, cfg->branches,

21
src/fuse_open.cpp

@ -114,6 +114,24 @@ namespace l
*flags_ &= ~O_APPEND; *flags_ &= ~O_APPEND;
} }
static
bool
calculate_flush(FlushOnClose const flushonclose_,
int const flags_)
{
switch(flushonclose_)
{
case FlushOnCloseEnum::NEVER:
return false;
case FlushOnCloseEnum::OPENED_FOR_WRITE:
return !l::rdonly(flags_);
case FlushOnCloseEnum::ALWAYS:
return true;
}
return true;
}
static static
void void
config_to_ffi_flags(Config::Read &cfg_, config_to_ffi_flags(Config::Read &cfg_,
@ -236,6 +254,9 @@ namespace FUSE
if(cfg->writeback_cache) if(cfg->writeback_cache)
l::tweak_flags_writeback_cache(&ffi_->flags); l::tweak_flags_writeback_cache(&ffi_->flags);
ffi_->noflush = !l::calculate_flush(cfg->flushonclose,
ffi_->flags);
rv = l::open(cfg->func.open.policy, rv = l::open(cfg->func.open.policy,
cfg->branches, cfg->branches,
fusepath_, fusepath_,

2
src/fuse_opendir.cpp

@ -30,6 +30,8 @@ namespace FUSE
ffi_->fh = reinterpret_cast<uint64_t>(new DirInfo(fusepath_)); ffi_->fh = reinterpret_cast<uint64_t>(new DirInfo(fusepath_));
ffi_->noflush = true;
if(cfg->cache_readdir) if(cfg->cache_readdir)
{ {
ffi_->keep_cache = 1; ffi_->keep_cache = 1;

Loading…
Cancel
Save