|
|
@ -17,96 +17,116 @@ |
|
|
|
*/ |
|
|
|
|
|
|
|
#include "fs_wait_for_mount.hpp"
|
|
|
|
#include "syslog.hpp"
|
|
|
|
|
|
|
|
#include <thread>
|
|
|
|
#include <unordered_set>
|
|
|
|
|
|
|
|
|
|
|
|
namespace fs |
|
|
|
{ |
|
|
|
typedef std::unordered_set<fs::Path> PathSet; |
|
|
|
} |
|
|
|
|
|
|
|
constexpr std::chrono::milliseconds SLEEP_DURATION = std::chrono::milliseconds(333); |
|
|
|
|
|
|
|
template<> |
|
|
|
struct std::hash<fs::Path> |
|
|
|
{ |
|
|
|
std::size_t |
|
|
|
operator()(fs::Path const &path_) const noexcept |
|
|
|
{ |
|
|
|
return std::hash<std::string>{}(path_.string()); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
bool |
|
|
|
fs::wait_for_mount(const struct stat &src_st_, |
|
|
|
const ghc::filesystem::path &tgtpath_, |
|
|
|
const std::chrono::milliseconds &timeout_) |
|
|
|
static |
|
|
|
void |
|
|
|
_check_mounted(const struct stat &src_st_, |
|
|
|
const fs::PathSet &tgt_paths_, |
|
|
|
fs::PathVector *successes_, |
|
|
|
fs::PathVector *failures_) |
|
|
|
{ |
|
|
|
int rv; |
|
|
|
std::chrono::duration<double> time_diff; |
|
|
|
std::chrono::time_point<std::chrono::steady_clock> start_time; |
|
|
|
fs::PathVector &successes = *successes_; |
|
|
|
fs::PathVector &failures = *failures_; |
|
|
|
|
|
|
|
start_time = std::chrono::steady_clock::now(); |
|
|
|
while(true) |
|
|
|
for(auto const &tgt_path : tgt_paths_) |
|
|
|
{ |
|
|
|
int rv; |
|
|
|
struct stat tgt_st; |
|
|
|
|
|
|
|
rv = fs::stat(tgtpath_,&tgt_st); |
|
|
|
rv = fs::stat(tgt_path,&tgt_st); |
|
|
|
if(rv == 0) |
|
|
|
{ |
|
|
|
if(tgt_st.st_dev != src_st_.st_dev) |
|
|
|
return true; |
|
|
|
successes.push_back(tgt_path); |
|
|
|
else |
|
|
|
failures.push_back(tgt_path); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
failures.push_back(tgt_path); |
|
|
|
} |
|
|
|
|
|
|
|
time_diff = (std::chrono::steady_clock::now() - start_time); |
|
|
|
if(time_diff > timeout_) |
|
|
|
return false; |
|
|
|
|
|
|
|
std::this_thread::sleep_for(SLEEP_DURATION); |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static |
|
|
|
void |
|
|
|
_wait_for_mount(const struct stat &src_st_, |
|
|
|
const fs::PathVector &tgtpaths_, |
|
|
|
const std::chrono::milliseconds &timeout_, |
|
|
|
fs::PathVector &failed_paths_) |
|
|
|
const fs::PathVector &tgt_paths_, |
|
|
|
const std::chrono::milliseconds &timeout_) |
|
|
|
{ |
|
|
|
bool rv; |
|
|
|
fs::PathVector::const_iterator i; |
|
|
|
std::chrono::milliseconds timeout; |
|
|
|
std::chrono::milliseconds diff; |
|
|
|
fs::PathVector successes; |
|
|
|
fs::PathVector failures; |
|
|
|
std::unordered_set<fs::Path> tgt_paths; |
|
|
|
std::chrono::time_point<std::chrono::steady_clock> now; |
|
|
|
std::chrono::time_point<std::chrono::steady_clock> start_time; |
|
|
|
std::chrono::time_point<std::chrono::steady_clock> deadline; |
|
|
|
|
|
|
|
timeout = timeout_; |
|
|
|
now = start_time = std::chrono::steady_clock::now(); |
|
|
|
for(auto i = tgtpaths_.begin(); i != tgtpaths_.end(); ++i) |
|
|
|
{ |
|
|
|
diff = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time); |
|
|
|
timeout -= diff; |
|
|
|
tgt_paths.insert(tgt_paths_.begin(),tgt_paths_.end()); |
|
|
|
now = std::chrono::steady_clock::now(); |
|
|
|
deadline = now + timeout_; |
|
|
|
|
|
|
|
rv = fs::wait_for_mount(src_st_,*i,timeout); |
|
|
|
if(rv == false) |
|
|
|
failed_paths_.push_back(*i); |
|
|
|
while(true) |
|
|
|
{ |
|
|
|
if(tgt_paths.empty()) |
|
|
|
break; |
|
|
|
if(now >= deadline) |
|
|
|
break; |
|
|
|
|
|
|
|
successes.clear(); |
|
|
|
failures.clear(); |
|
|
|
::_check_mounted(src_st_,tgt_paths,&successes,&failures); |
|
|
|
for(auto const &path : successes) |
|
|
|
{ |
|
|
|
tgt_paths.erase(path); |
|
|
|
syslog_info("%s is mounted",path.string().c_str()); |
|
|
|
} |
|
|
|
|
|
|
|
std::this_thread::sleep_for(SLEEP_DURATION); |
|
|
|
now = std::chrono::steady_clock::now(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
fs::wait_for_mount(const struct stat &src_st_, |
|
|
|
const fs::PathVector &tgtpaths_, |
|
|
|
const std::chrono::milliseconds &timeout_, |
|
|
|
fs::PathVector &failed_paths_) |
|
|
|
{ |
|
|
|
if(tgtpaths_.empty()) |
|
|
|
return; |
|
|
|
|
|
|
|
_wait_for_mount(src_st_,tgtpaths_,timeout_,failed_paths_); |
|
|
|
for(auto const &path : failures) |
|
|
|
syslog_notice("%s not mounted within timeout",path.string().c_str()); |
|
|
|
if(!failures.empty()) |
|
|
|
syslog_warning("Continuing to mount mergerfs despite %u branches not " |
|
|
|
"being different from the mountpoint filesystem", |
|
|
|
failures.size()); |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
fs::wait_for_mount(const ghc::filesystem::path &srcpath_, |
|
|
|
const fs::PathVector &tgtpaths_, |
|
|
|
const std::chrono::milliseconds &timeout_, |
|
|
|
fs::PathVector &failed_paths_) |
|
|
|
fs::wait_for_mount(const fs::Path &src_path_, |
|
|
|
const fs::PathVector &tgt_paths_, |
|
|
|
const std::chrono::milliseconds &timeout_) |
|
|
|
{ |
|
|
|
int rv; |
|
|
|
struct stat src_st; |
|
|
|
|
|
|
|
rv = fs::stat(srcpath_,&src_st); |
|
|
|
rv = fs::stat(src_path_,&src_st); |
|
|
|
if(rv == -1) |
|
|
|
return; |
|
|
|
return syslog_error("Error stat'ing mount path: %s (%s)", |
|
|
|
src_path_.c_str(), |
|
|
|
strerror(errno)); |
|
|
|
|
|
|
|
fs::wait_for_mount(src_st,tgtpaths_,timeout_,failed_paths_); |
|
|
|
::_wait_for_mount(src_st,tgt_paths_,timeout_); |
|
|
|
} |