mirror of
https://github.com/trapexit/mergerfs.git
synced 2024-11-22 11:02:35 +08:00
Add flushonclose feature
This commit is contained in:
parent
7d6c8e9333
commit
6aa6452d3e
26
README.md
26
README.md
|
@ -248,7 +248,10 @@ These options are the same regardless of whether you use them with the
|
|||
to the same as the process thread count. (default: 0)
|
||||
* **pin-threads=STR**: Selects a strategy to pin threads to CPUs
|
||||
(default: unset)
|
||||
* **scheduling-priority=INT**: Set mergerfs' scheduling
|
||||
* **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
|
||||
priority. Valid values range from -20 to 19. See `setpriority` man
|
||||
page for more details. (default: -10)
|
||||
* **fsname=STR**: Sets the name of the filesystem as seen in
|
||||
|
@ -926,6 +929,27 @@ The options `statfs` and `statfs_ignore` can be used to modify
|
|||
`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
|
||||
|
||||
POSIX filesystem functions offer a single return code meaning that
|
||||
|
|
|
@ -86,6 +86,8 @@ struct fuse_file_info_t
|
|||
|
||||
uint32_t parallel_direct_writes:1;
|
||||
|
||||
uint32_t noflush:1;
|
||||
|
||||
/** File handle. May be filled in by filesystem in open().
|
||||
Available in all other file operations */
|
||||
uint64_t fh;
|
||||
|
|
|
@ -275,6 +275,8 @@ fill_open(struct fuse_open_out *arg_,
|
|||
arg_->open_flags |= FOPEN_CACHE_DIR;
|
||||
if(ffi_->parallel_direct_writes)
|
||||
arg_->open_flags |= FOPEN_PARALLEL_DIRECT_WRITES;
|
||||
if(ffi_->noflush)
|
||||
arg_->open_flags |= FOPEN_NOFLUSH;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -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
|
||||
(default: unset)
|
||||
.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
|
||||
priority.
|
||||
Valid values range from -20 to 19.
|
||||
See \f[C]setpriority\f[R] man page for more details.
|
||||
(default: -10)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
\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.
|
||||
|
@ -1321,6 +1328,24 @@ be included when checking the mount\[cq]s stats.
|
|||
.PP
|
||||
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.
|
||||
.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
|
||||
.PP
|
||||
POSIX filesystem functions offer a single return code meaning that there
|
||||
|
|
|
@ -94,8 +94,9 @@ Config::Config()
|
|||
category(func),
|
||||
direct_io(false),
|
||||
dropcacheonclose(false),
|
||||
fsname(),
|
||||
flushonclose(FlushOnClose::ENUM::ALWAYS),
|
||||
follow_symlinks(FollowSymlinks::ENUM::NEVER),
|
||||
fsname(),
|
||||
func(),
|
||||
fuse_msg_size(FUSE_MAX_MAX_PAGES),
|
||||
ignorepponrename(false),
|
||||
|
@ -149,6 +150,7 @@ Config::Config()
|
|||
_map["category.search"] = &category.search;
|
||||
_map["direct_io"] = &direct_io;
|
||||
_map["dropcacheonclose"] = &dropcacheonclose;
|
||||
_map["flush-on-close"] = &flushonclose;
|
||||
_map["follow-symlinks"] = &follow_symlinks;
|
||||
_map["fsname"] = &fsname;
|
||||
_map["func.access"] = &func.access;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "branches.hpp"
|
||||
#include "category.hpp"
|
||||
#include "config_cachefiles.hpp"
|
||||
#include "config_flushonclose.hpp"
|
||||
#include "config_follow_symlinks.hpp"
|
||||
#include "config_inodecalc.hpp"
|
||||
#include "config_link_exdev.hpp"
|
||||
|
@ -116,8 +117,9 @@ public:
|
|||
Categories category;
|
||||
ConfigBOOL direct_io;
|
||||
ConfigBOOL dropcacheonclose;
|
||||
ConfigSTR fsname;
|
||||
FlushOnClose flushonclose;
|
||||
FollowSymlinks follow_symlinks;
|
||||
ConfigSTR fsname;
|
||||
Funcs func;
|
||||
ConfigUINT64 fuse_msg_size;
|
||||
ConfigBOOL ignorepponrename;
|
||||
|
|
54
src/config_flushonclose.cpp
Normal file
54
src/config_flushonclose.cpp
Normal file
|
@ -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
Normal file
31
src/config_flushonclose.hpp
Normal file
|
@ -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;
|
|
@ -51,6 +51,31 @@ namespace l
|
|||
*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
|
||||
void
|
||||
config_to_ffi_flags(Config::Read &cfg_,
|
||||
|
@ -200,6 +225,9 @@ namespace FUSE
|
|||
if(cfg->writeback_cache)
|
||||
l::tweak_flags_writeback_cache(&ffi_->flags);
|
||||
|
||||
ffi_->noflush = !l::calculate_flush(cfg->flushonclose,
|
||||
ffi_->flags);
|
||||
|
||||
rv = l::create(cfg->func.getattr.policy,
|
||||
cfg->func.create.policy,
|
||||
cfg->branches,
|
||||
|
|
|
@ -114,6 +114,24 @@ namespace l
|
|||
*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
|
||||
void
|
||||
config_to_ffi_flags(Config::Read &cfg_,
|
||||
|
@ -236,6 +254,9 @@ namespace FUSE
|
|||
if(cfg->writeback_cache)
|
||||
l::tweak_flags_writeback_cache(&ffi_->flags);
|
||||
|
||||
ffi_->noflush = !l::calculate_flush(cfg->flushonclose,
|
||||
ffi_->flags);
|
||||
|
||||
rv = l::open(cfg->func.open.policy,
|
||||
cfg->branches,
|
||||
fusepath_,
|
||||
|
|
|
@ -30,6 +30,8 @@ namespace FUSE
|
|||
|
||||
ffi_->fh = reinterpret_cast<uint64_t>(new DirInfo(fusepath_));
|
||||
|
||||
ffi_->noflush = true;
|
||||
|
||||
if(cfg->cache_readdir)
|
||||
{
|
||||
ffi_->keep_cache = 1;
|
||||
|
|
Loading…
Reference in New Issue
Block a user