diff --git a/src/branches.cpp b/src/branches.cpp index 4ab59707..bc942be0 100644 --- a/src/branches.cpp +++ b/src/branches.cpp @@ -28,8 +28,10 @@ #include "str.hpp" #include "syslog.hpp" -#include +#include #include +#include +#include #include @@ -437,24 +439,44 @@ Branches::from_string(const std::string_view str_) Branches::Ptr impl; Branches::Ptr new_impl; - impl = std::atomic_load(&_impl); - new_impl = std::make_shared(&minfreespace); - *new_impl = *impl; - rv = new_impl->from_string(str_); - if(rv < 0) - return rv; + for(;;) + { + { + std::shared_lock lk(_mutex); + impl = _impl; + } - std::atomic_store(&_impl,new_impl); + *new_impl = *impl; - return 0; + rv = new_impl->from_string(str_); + if(rv < 0) + return rv; + + { + std::unique_lock lk(_mutex); + if(impl != _impl) + continue; + + _impl = std::move(new_impl); + } + + return 0; + } } std::string Branches::to_string(void) const { - return std::atomic_load(&_impl)->to_string(); + Branches::Ptr impl; + + { + std::shared_lock lk(_mutex); + impl = _impl; + } + + return impl->to_string(); } void @@ -462,32 +484,50 @@ Branches::find_and_set_mode_ro() { Branches::Ptr impl; Branches::Ptr new_impl; + std::vector ro_paths; - impl = std::atomic_load(&_impl); new_impl = std::make_shared(&minfreespace); - *new_impl = *impl; - - bool changed = false; - for(auto &branch : *new_impl) + for(;;) { - if(branch.mode != Branch::Mode::RW) - continue; + ro_paths.clear(); - if(!fs::is_rofs_but_not_mounted_ro(branch.path)) - continue; + { + std::shared_lock lk(_mutex); + impl = _impl; + } - SysLog::warning("branch `{}` found to be readonly - setting its mode=RO", - branch.path.string()); + *new_impl = *impl; - branch.mode = Branch::Mode::RO; - changed = true; + for(auto &branch : *new_impl) + { + if(branch.mode != Branch::Mode::RW) + continue; + + if(!fs::is_rofs_but_not_mounted_ro(branch.path)) + continue; + + branch.mode = Branch::Mode::RO; + ro_paths.emplace_back(branch.path); + } + + if(ro_paths.empty()) + return; + + { + std::unique_lock lk(_mutex); + if(impl != _impl) + continue; + + _impl = std::move(new_impl); + } + + for(const auto &path : ro_paths) + SysLog::warning("branch `{}` found to be readonly - setting its mode=RO", + path.string()); + + return; } - - if(not changed) - return; - - std::atomic_store(&_impl,new_impl); } SrcMounts::SrcMounts(Branches &b_) diff --git a/src/branches.hpp b/src/branches.hpp index 54f85959..dae01822 100644 --- a/src/branches.hpp +++ b/src/branches.hpp @@ -23,9 +23,9 @@ #include "strvec.hpp" #include "tofrom_string.hpp" -#include #include #include +#include #include #include @@ -69,7 +69,8 @@ public: u64 minfreespace = MINFREESPACE_DEFAULT; private: - mutable std::shared_ptr _impl; + Branches::Ptr _impl; + mutable std::shared_mutex _mutex; public: Branches() @@ -82,8 +83,17 @@ public: std::string to_string(void) const final; public: - operator Ptr() const { return std::atomic_load(&_impl); } - Ptr operator->() const { return std::atomic_load(&_impl); } + operator Ptr() const + { + std::shared_lock lk(_mutex); + return _impl; + } + + Ptr operator->() const + { + std::shared_lock lk(_mutex); + return _impl; + } public: void find_and_set_mode_ro();