mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-26 02:48:59 -04:00
branches: re-link default_minfreespace pointer on copy/move; atomically publish branch mode changes
Branches using the default minfreespace held a reference to their owning Impl's _default_minfreespace. After a copy or move the pointer still referenced the source Impl, which could become invalid or diverge after further configuration changes. Switch to a pointer and re-link it to the destination Impl on copy/move. While here, convert set_branch_mode to do an atomic_store of a newly constructed Impl rather than mutating the shared pointer target in place. Readers holding an atomic_load snapshot are no longer affected by a concurrent mode change.
This commit is contained in:
parent
deba02e3d3
commit
da3cb9ae56
2 changed files with 46 additions and 11 deletions
|
|
@ -34,7 +34,7 @@
|
|||
#include <fnmatch.h>
|
||||
|
||||
|
||||
Branches::Impl::Impl(const u64 &default_minfreespace_)
|
||||
Branches::Impl::Impl(const u64 *default_minfreespace_)
|
||||
: _default_minfreespace(default_minfreespace_)
|
||||
{
|
||||
}
|
||||
|
|
@ -48,6 +48,16 @@ Branches::Impl::operator=(Branches::Impl &rval_)
|
|||
|
||||
*this_base = *rval_base;
|
||||
|
||||
// Branches using the default minfreespace hold a pointer to their
|
||||
// owning Impl's _default_minfreespace. After copy/move those
|
||||
// pointers still reference the source Impl, so re-link them to this
|
||||
// Impl's _default_minfreespace.
|
||||
for(auto &branch : *this)
|
||||
{
|
||||
if(std::holds_alternative<const u64*>(branch._minfreespace))
|
||||
branch._minfreespace = _default_minfreespace;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -60,6 +70,16 @@ Branches::Impl::operator=(Branches::Impl &&rval_)
|
|||
|
||||
*this_base = std::move(*rval_base);
|
||||
|
||||
// Branches using the default minfreespace hold a pointer to their
|
||||
// owning Impl's _default_minfreespace. After copy/move those
|
||||
// pointers still reference the source Impl, so re-link them to this
|
||||
// Impl's _default_minfreespace.
|
||||
for(auto &branch : *this)
|
||||
{
|
||||
if(std::holds_alternative<const u64*>(branch._minfreespace))
|
||||
branch._minfreespace = _default_minfreespace;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +87,7 @@ const
|
|||
u64&
|
||||
Branches::Impl::minfreespace(void) const
|
||||
{
|
||||
return _default_minfreespace;
|
||||
return *_default_minfreespace;
|
||||
}
|
||||
|
||||
namespace l
|
||||
|
|
@ -148,7 +168,7 @@ namespace l
|
|||
case 2:
|
||||
*glob_ = v[0];
|
||||
options = v[1];
|
||||
v = str::split(options,',');
|
||||
v = str::split(options,',');
|
||||
switch(v.size())
|
||||
{
|
||||
case 2:
|
||||
|
|
@ -229,7 +249,7 @@ namespace l
|
|||
{
|
||||
int rv;
|
||||
StrVec paths;
|
||||
Branches::Impl tmp_branches(branches_->minfreespace());
|
||||
Branches::Impl tmp_branches(&branches_->minfreespace());
|
||||
|
||||
paths = str::split(str_,':');
|
||||
for(auto &path : paths)
|
||||
|
|
@ -251,7 +271,7 @@ namespace l
|
|||
{
|
||||
int rv;
|
||||
std::vector<std::string> paths;
|
||||
Branches::Impl tmp_branches(branches_->minfreespace());
|
||||
Branches::Impl tmp_branches(&branches_->minfreespace());
|
||||
|
||||
paths = str::split(str_,':');
|
||||
for(auto &path : paths)
|
||||
|
|
@ -275,7 +295,7 @@ namespace l
|
|||
{
|
||||
int rv;
|
||||
StrVec paths;
|
||||
Branches::Impl tmp_branches(branches_->minfreespace());
|
||||
Branches::Impl tmp_branches(&branches_->minfreespace());
|
||||
|
||||
paths = str::split(str_,':');
|
||||
for(auto &path : paths)
|
||||
|
|
@ -419,7 +439,7 @@ Branches::from_string(const std::string_view str_)
|
|||
|
||||
impl = std::atomic_load(&_impl);
|
||||
|
||||
new_impl = std::make_shared<Branches::Impl>(impl->minfreespace());
|
||||
new_impl = std::make_shared<Branches::Impl>(&minfreespace);
|
||||
*new_impl = *impl;
|
||||
|
||||
rv = new_impl->from_string(str_);
|
||||
|
|
@ -440,7 +460,16 @@ Branches::to_string(void) const
|
|||
void
|
||||
Branches::find_and_set_mode_ro()
|
||||
{
|
||||
for(auto &branch : *_impl)
|
||||
Branches::Ptr impl;
|
||||
Branches::Ptr new_impl;
|
||||
|
||||
impl = std::atomic_load(&_impl);
|
||||
new_impl = std::make_shared<Branches::Impl>(&minfreespace);
|
||||
|
||||
*new_impl = *impl;
|
||||
|
||||
bool changed = false;
|
||||
for(auto &branch : *new_impl)
|
||||
{
|
||||
if(branch.mode != Branch::Mode::RW)
|
||||
continue;
|
||||
|
|
@ -452,7 +481,13 @@ Branches::find_and_set_mode_ro()
|
|||
branch.path.string());
|
||||
|
||||
branch.mode = Branch::Mode::RO;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if(not changed)
|
||||
return;
|
||||
|
||||
std::atomic_store(&_impl,new_impl);
|
||||
}
|
||||
|
||||
SrcMounts::SrcMounts(Branches &b_)
|
||||
|
|
|
|||
|
|
@ -39,13 +39,13 @@ public:
|
|||
public std::vector<Branch>
|
||||
{
|
||||
private:
|
||||
const u64 &_default_minfreespace;
|
||||
const u64 *_default_minfreespace;
|
||||
|
||||
public:
|
||||
using Ptr = std::shared_ptr<Impl>;
|
||||
|
||||
public:
|
||||
Impl(const u64 &default_minfreespace);
|
||||
Impl(const u64 *default_minfreespace);
|
||||
|
||||
public:
|
||||
int from_string(const std::string_view str) final;
|
||||
|
|
@ -73,7 +73,7 @@ private:
|
|||
|
||||
public:
|
||||
Branches()
|
||||
: _impl(std::make_shared<Impl>(minfreespace))
|
||||
: _impl(std::make_shared<Impl>(&minfreespace))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue