Improve mount waiting

Adds user.mergerfs.branch and user.mergerfs.branch_mounts_here
Adds .mergerfs.branch and .mergerfs.branch_mounts_here files.
This commit is contained in:
Antonio SJ Musumeci 2025-04-18 01:08:41 -05:00
parent 212681ddc5
commit 6ead015a1b
4 changed files with 112 additions and 17 deletions

37
src/fs_mounts.cpp Normal file
View File

@ -0,0 +1,37 @@
#include "fs_mounts.hpp"
#include <cstdio>
#include <mntent.h>
#ifdef __linux__
void
fs::mounts(std::vector<fs::mount_t> &mounts_)
{
FILE *f;
f = setmntent("/proc/mounts","r");
if(f == NULL)
return;
struct mntent *entry;
while((entry = getmntent(f)) != NULL)
{
fs::mount_t m;
m.dir = entry->mnt_dir;
m.fsname = entry->mnt_fsname;
m.type = entry->mnt_type;
m.opts = entry->mnt_opts;
mounts_.emplace_back(std::move(m));
}
endmntent(f);
}
#else
void
fs::mounts(std::vector<fs::mount_t> &mounts_)
{
}
#endif

18
src/fs_mounts.hpp Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include "ghc/filesystem.hpp"
#include <vector>
namespace fs
{
struct mount_t
{
ghc::filesystem::path dir;
std::string fsname;
std::string type;
std::string opts;
};
void mounts(std::vector<fs::mount_t> &mount);
}

View File

@ -19,6 +19,10 @@
#include "fs_wait_for_mount.hpp"
#include "syslog.hpp"
#include "fs_exists.hpp"
#include "fs_lstat.hpp"
#include "fs_lgetxattr.hpp"
#include <functional>
#include <thread>
#include <unordered_set>
@ -44,6 +48,40 @@ namespace std
};
}
static
bool
_branch_is_mounted(const struct stat &src_st_,
const fs::Path &branch_path_)
{
int rv;
struct stat st;
fs::Path filepath;
rv = fs::lgetxattr(branch_path_,"user.mergerfs.branch",NULL,0);
if(rv != -1)
return true;
filepath = branch_path_ / ".mergerfs.branch";
rv = fs::exists(filepath);
if(rv)
return true;
rv = fs::lgetxattr(branch_path_,"user.mergerfs.branch_mounts_here",NULL,0);
if(rv != -1)
return false;
filepath = branch_path_ / ".mergerfs.branch_mounts_here";
rv = fs::exists(filepath);
if(rv)
return false;
rv = fs::lstat(branch_path_,&st);
if(rv == 0)
return (st.st_dev != src_st_.st_dev);
return false;
}
static
void
_check_mounted(const struct stat &src_st_,
@ -56,21 +94,13 @@ _check_mounted(const struct stat &src_st_,
for(auto const &tgt_path : tgt_paths_)
{
int rv;
struct stat tgt_st;
bool mounted;
rv = fs::stat(tgt_path,&tgt_st);
if(rv == 0)
{
if(tgt_st.st_dev != src_st_.st_dev)
successes.push_back(tgt_path);
else
failures.push_back(tgt_path);
}
mounted = ::_branch_is_mounted(src_st_,tgt_path);
if(mounted)
successes.push_back(tgt_path);
else
{
failures.push_back(tgt_path);
}
failures.push_back(tgt_path);
}
}
@ -80,6 +110,7 @@ _wait_for_mount(const struct stat &src_st_,
const fs::PathVector &tgt_paths_,
const std::chrono::milliseconds &timeout_)
{
bool first_loop;
fs::PathVector successes;
fs::PathVector failures;
std::unordered_set<fs::Path> tgt_paths;
@ -90,6 +121,7 @@ _wait_for_mount(const struct stat &src_st_,
now = std::chrono::steady_clock::now();
deadline = now + timeout_;
first_loop = true;
while(true)
{
if(tgt_paths.empty())
@ -100,12 +132,19 @@ _wait_for_mount(const struct stat &src_st_,
successes.clear();
failures.clear();
::_check_mounted(src_st_,tgt_paths,&successes,&failures);
for(auto const &path : successes)
for(const auto &path : successes)
{
tgt_paths.erase(path);
syslog_info("%s is mounted",path.string().c_str());
}
if(first_loop)
{
for(const auto &path : failures)
syslog_notice("%s is not mounted, waiting",path.string().c_str());
first_loop = false;
}
std::this_thread::sleep_for(SLEEP_DURATION);
now = std::chrono::steady_clock::now();
}
@ -124,7 +163,7 @@ fs::wait_for_mount(const fs::Path &src_path_,
const std::chrono::milliseconds &timeout_)
{
int rv;
struct stat src_st;
struct stat src_st = {0};
rv = fs::stat(src_path_,&src_st);
if(rv == -1)

View File

@ -173,8 +173,9 @@ namespace l
paths = cfg_->branches->to_paths();
syslog_info("Waiting %u seconds for branches to mount",
(uint64_t)cfg_->branches_mount_timeout);
syslog_info("Waiting %u seconds for %zu branches to mount",
(uint64_t)cfg_->branches_mount_timeout,
paths.size());
timeout = std::chrono::milliseconds(cfg_->branches_mount_timeout * 1000);
fs::wait_for_mount((std::string)cfg_->mountpoint,