Skip to content

Commit

Permalink
Merge pull request #1275 from trapexit/noflush
Browse files Browse the repository at this point in the history
Add flushonclose feature
  • Loading branch information
trapexit authored Oct 29, 2023
2 parents 7d6c8e9 + 6aa6452 commit 7890a49
Show file tree
Hide file tree
Showing 11 changed files with 196 additions and 3 deletions.
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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/[email protected]/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
Expand Down
2 changes: 2 additions & 0 deletions libfuse/include/fuse_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions libfuse/lib/fuse_lowlevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions man/mergerfs.1
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion src/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -116,8 +117,9 @@ class Config
Categories category;
ConfigBOOL direct_io;
ConfigBOOL dropcacheonclose;
ConfigSTR fsname;
FlushOnClose flushonclose;
FollowSymlinks follow_symlinks;
ConfigSTR fsname;
Funcs func;
ConfigUINT64 fuse_msg_size;
ConfigBOOL ignorepponrename;
Expand Down
54 changes: 54 additions & 0 deletions src/config_flushonclose.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
ISC License
Copyright (c) 2023, Antonio SJ Musumeci <[email protected]>
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 changes: 31 additions & 0 deletions src/config_flushonclose.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
ISC License
Copyright (c) 2023, Antonio SJ Musumeci <[email protected]>
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 changes: 28 additions & 0 deletions src/fuse_create.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_,
Expand Down Expand Up @@ -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,
Expand Down
21 changes: 21 additions & 0 deletions src/fuse_open.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_,
Expand Down Expand Up @@ -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_,
Expand Down
2 changes: 2 additions & 0 deletions src/fuse_opendir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 7890a49

Please sign in to comment.