config: make fuse runtime flags atomic

This commit is contained in:
Antonio SJ Musumeci 2026-05-03 23:40:52 -05:00
parent fae31d68c2
commit 230b194291
8 changed files with 117 additions and 13 deletions

View file

@ -137,8 +137,8 @@ Config::Config()
_mountpoint(mountpoint),
_never_forget_nodes(),
_noforget(),
_remember(fuse_cfg.remember_nodes),
_remember_nodes(fuse_cfg.remember_nodes),
_remember(),
_remember_nodes(),
_srcmounts(branches),
_threads(fuse_cfg.read_thread_count),
_uid(fuse_cfg.uid),

View file

@ -55,6 +55,7 @@
#include "base_types.h"
#include <atomic>
#include <map>
#include <memory>
#include <string>
@ -176,8 +177,8 @@ private:
TFSRef<fs::path> _mountpoint;
CfgNoforget _never_forget_nodes;
CfgNoforget _noforget;
TFSRef<s64> _remember;
TFSRef<s64> _remember_nodes;
CfgRememberNodes _remember;
CfgRememberNodes _remember_nodes;
SrcMounts _srcmounts;
TFSRef<int> _threads;
TFSRef<s64> _uid;

View file

@ -28,13 +28,13 @@
Debug::Debug(const bool v_)
{
fuse_cfg.debug = v_;
fuse_cfg.debug.store(v_,std::memory_order_relaxed);
}
std::string
Debug::to_string(void) const
{
return str::to(fuse_cfg.debug);
return str::to(fuse_cfg.debug.load(std::memory_order_relaxed));
}
int
@ -47,7 +47,7 @@ Debug::from_string(const std::string_view s_)
if(rv < 0)
return rv;
fuse_cfg.debug = val;
fuse_cfg.debug.store(val,std::memory_order_relaxed);
// If debug is being enabled, ensure output file is set
if(val)

View file

@ -20,9 +20,40 @@
#include "tofrom_string.hpp"
#include "from_string.hpp"
#include "to_string.hpp"
#include "fuse_cfg.hpp"
#include <errno.h>
class CfgRememberNodes : public ToFromString
{
public:
int
from_string(const std::string_view s_)
{
int rv;
s64 v;
rv = str::from(s_,&v);
if(rv < 0)
return rv;
if(v < -1)
return -EINVAL;
fuse_cfg.remember_nodes.store(v,std::memory_order_relaxed);
return 0;
}
std::string
to_string() const
{
return str::to(fuse_cfg.remember_nodes.load(std::memory_order_relaxed));
}
};
class CfgNoforget : public ToFromString
{
@ -36,14 +67,14 @@ public:
rv = str::from(s_,&b);
if((b == true) || s_.empty())
{
fuse_cfg.remember_nodes = -1;
fuse_cfg.remember_nodes.store(-1,std::memory_order_relaxed);
return 0;
}
if(rv)
return rv;
fuse_cfg.remember_nodes = 0;
fuse_cfg.remember_nodes.store(0,std::memory_order_relaxed);
return 0;
}
@ -51,7 +82,7 @@ public:
std::string
to_string() const
{
if(fuse_cfg.remember_nodes == -1)
if(fuse_cfg.remember_nodes.load(std::memory_order_relaxed) == -1)
return "true";
return "false";
}

View file

@ -206,7 +206,7 @@ _option_processor(void *data_,
return OPT_DISCARD;
case MERGERFS_OPT_DEBUG:
fuse_cfg.debug = true;
fuse_cfg.debug.store(true,std::memory_order_relaxed);
return OPT_DISCARD;
case MERGERFS_OPT_HELP:

View file

@ -22,6 +22,8 @@
#include "from_string.hpp"
#include "tofrom_string.hpp"
#include <atomic>
template<typename T>
class TFSRef : public ToFromString
@ -48,3 +50,38 @@ public:
private:
T &_data;
};
template<typename T>
class TFSRef<std::atomic<T>> : public ToFromString
{
public:
int
from_string(const std::string_view s_) final
{
T value;
int rv;
rv = str::from(s_,&value);
if(rv < 0)
return rv;
_data.store(value,std::memory_order_relaxed);
return 0;
}
std::string
to_string(void) const final
{
return str::to(_data.load(std::memory_order_relaxed));
}
public:
TFSRef(std::atomic<T> &data_)
: _data(data_)
{
}
private:
std::atomic<T> &_data;
};

View file

@ -2657,6 +2657,39 @@ test_config_get_set_roundtrip()
TEST_CHECK(val == "myfs");
}
void
test_config_remember_nodes()
{
Config cfg;
std::string val;
TEST_CHECK(cfg.set("remember-nodes","30") == 0);
TEST_CHECK(cfg.get("remember-nodes",&val) == 0);
TEST_CHECK(val == "30");
TEST_CHECK(cfg.set("remember","-1") == 0);
TEST_CHECK(cfg.get("remember-nodes",&val) == 0);
TEST_CHECK(val == "-1");
TEST_CHECK(cfg.set("remember-nodes","-2") == -EINVAL);
TEST_CHECK(cfg.get("remember-nodes",&val) == 0);
TEST_CHECK(val == "-1");
TEST_CHECK(cfg.set("noforget","false") == 0);
TEST_CHECK(cfg.get("noforget",&val) == 0);
TEST_CHECK(val == "false");
TEST_CHECK(cfg.get("remember-nodes",&val) == 0);
TEST_CHECK(val == "0");
TEST_CHECK(cfg.set("noforget","true") == 0);
TEST_CHECK(cfg.get("noforget",&val) == 0);
TEST_CHECK(val == "true");
TEST_CHECK(cfg.get("remember-nodes",&val) == 0);
TEST_CHECK(val == "-1");
TEST_CHECK(cfg.set("remember-nodes","0") == 0);
}
void
test_config_get_unknown_key()
{
@ -3677,6 +3710,7 @@ TEST_LIST =
{"config_keys_listxattr_fill",test_config_keys_listxattr_fill},
{"config_keys_listxattr_erange",test_config_keys_listxattr_erange},
{"config_get_set_roundtrip",test_config_get_set_roundtrip},
{"config_remember_nodes",test_config_remember_nodes},
{"config_get_unknown_key",test_config_get_unknown_key},
{"config_set_unknown_key",test_config_set_unknown_key},
{"config_set_invalid_value",test_config_set_invalid_value},

View file

@ -2,6 +2,7 @@
#include "base_types.h"
#include <atomic>
#include <climits>
#include <cstdio>
#include <memory>
@ -25,9 +26,9 @@ struct fuse_cfg_t
s64 umask = FUSE_CFG_INVALID_UMASK;
bool valid_umask() const;
s64 remember_nodes = 0;
std::atomic<s64> remember_nodes = 0;
bool debug = false;
std::atomic<bool> debug = false;
std::shared_ptr<FILE> log_file() const;
void log_file(std::shared_ptr<FILE>);
std::shared_ptr<std::string> log_filepath() const;