mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-26 19:01:56 -04:00
Misc cleanup
This commit is contained in:
parent
ff48ff6047
commit
fa06b4b8bd
74 changed files with 809 additions and 619 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,12 @@ Branches::Impl::operator=(Branches::Impl &rval_)
|
|||
|
||||
*this_base = *rval_base;
|
||||
|
||||
for(auto &branch : *this)
|
||||
{
|
||||
if(std::holds_alternative<const u64*>(branch._minfreespace))
|
||||
branch._minfreespace = _default_minfreespace;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -60,6 +66,12 @@ Branches::Impl::operator=(Branches::Impl &&rval_)
|
|||
|
||||
*this_base = std::move(*rval_base);
|
||||
|
||||
for(auto &branch : *this)
|
||||
{
|
||||
if(std::holds_alternative<const u64*>(branch._minfreespace))
|
||||
branch._minfreespace = _default_minfreespace;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +79,7 @@ const
|
|||
u64&
|
||||
Branches::Impl::minfreespace(void) const
|
||||
{
|
||||
return _default_minfreespace;
|
||||
return *_default_minfreespace;
|
||||
}
|
||||
|
||||
namespace l
|
||||
|
|
@ -148,7 +160,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 +241,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 +263,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 +287,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 +431,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 +452,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 +473,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))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@
|
|||
#include "fuse_cfg.hpp"
|
||||
#include "fuse_readdir.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "tofrom_ref.hpp"
|
||||
#include "tofrom_wrapper.hpp"
|
||||
#include "syslog.hpp"
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@
|
|||
|
||||
LogFile::LogFile(const std::string &s_)
|
||||
{
|
||||
fuse_debug_set_output(s_);
|
||||
if(!s_.empty())
|
||||
fuse_debug_set_output(s_);
|
||||
}
|
||||
|
||||
std::string
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
class DirInfo : public FH
|
||||
{
|
||||
public:
|
||||
static u64 to_fh(const DirInfo*);
|
||||
static DirInfo *from_fh(const u64 fh);
|
||||
|
||||
public:
|
||||
|
|
@ -39,23 +40,23 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
inline
|
||||
u64
|
||||
DirInfo::to_fh(const DirInfo *di_)
|
||||
{
|
||||
return reinterpret_cast<u64>(di_);
|
||||
}
|
||||
|
||||
inline
|
||||
u64
|
||||
DirInfo::to_fh() const
|
||||
{
|
||||
ASSERT_NOT_NULL(this);
|
||||
return reinterpret_cast<u64>(this);
|
||||
return to_fh(this);
|
||||
}
|
||||
|
||||
inline
|
||||
DirInfo*
|
||||
DirInfo::from_fh(const u64 fh_)
|
||||
{
|
||||
DirInfo *rv;
|
||||
|
||||
rv = reinterpret_cast<DirInfo*>(fh_);
|
||||
|
||||
ASSERT_NOT_NULL(rv);
|
||||
|
||||
return rv;
|
||||
return reinterpret_cast<DirInfo*>(fh_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,6 @@ inline
|
|||
u64
|
||||
FileInfo::to_fh(const FileInfo *fi_)
|
||||
{
|
||||
ASSERT_NOT_NULL(fi_);
|
||||
return reinterpret_cast<u64>(fi_);
|
||||
}
|
||||
|
||||
|
|
@ -112,19 +111,12 @@ inline
|
|||
u64
|
||||
FileInfo::to_fh() const
|
||||
{
|
||||
ASSERT_NOT_NULL(this);
|
||||
return reinterpret_cast<u64>(this);
|
||||
return to_fh(this);
|
||||
}
|
||||
|
||||
inline
|
||||
FileInfo*
|
||||
FileInfo::from_fh(const u64 fh_)
|
||||
{
|
||||
FileInfo *rv;
|
||||
|
||||
rv = reinterpret_cast<FileInfo*>(fh_);
|
||||
|
||||
ASSERT_NOT_NULL(rv);
|
||||
|
||||
return rv;
|
||||
return reinterpret_cast<FileInfo*>(fh_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,6 +82,8 @@ _movefile_and_open(const Policy::Create &createFunc_,
|
|||
rv = createFunc_(branches_,fusepath_,dst_branch);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(dst_branch.empty())
|
||||
return -ENOSPC;
|
||||
|
||||
origfd_flags = fs::getfl(origfd_);
|
||||
if(origfd_flags < 0)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
static
|
||||
int
|
||||
_access(const Policy::Search &searchFunc_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
const int mask_)
|
||||
{
|
||||
|
|
@ -42,6 +42,8 @@ _access(const Policy::Search &searchFunc_,
|
|||
rv = searchFunc_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
fullpath = branches[0]->path / fusepath_;
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ static
|
|||
int
|
||||
_chmod(const Policy::Action &actionFunc_,
|
||||
const Policy::Search &searchFunc_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
const mode_t mode_)
|
||||
{
|
||||
|
|
@ -75,6 +75,8 @@ _chmod(const Policy::Action &actionFunc_,
|
|||
rv = actionFunc_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
::_chmod_loop(branches,fusepath_,mode_,&prv);
|
||||
if(prv.errors.empty())
|
||||
|
|
@ -86,6 +88,8 @@ _chmod(const Policy::Action &actionFunc_,
|
|||
rv = searchFunc_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
return prv.get_error(branches[0]->path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ static
|
|||
int
|
||||
_chown(const Policy::Action &actionFunc_,
|
||||
const Policy::Search &searchFunc_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
const uid_t uid_,
|
||||
const gid_t gid_)
|
||||
|
|
@ -78,6 +78,8 @@ _chown(const Policy::Action &actionFunc_,
|
|||
rv = actionFunc_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
::_chown_loop(branches,fusepath_,uid_,gid_,&prv);
|
||||
|
||||
|
|
@ -90,6 +92,8 @@ _chown(const Policy::Action &actionFunc_,
|
|||
rv = searchFunc_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
return prv.get_error(branches[0]->path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ int
|
|||
_create(const ugid_t ugid_,
|
||||
const Policy::Search &searchFunc_,
|
||||
const Policy::Create &createFunc_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *ffi_,
|
||||
const mode_t mode_,
|
||||
|
|
@ -224,10 +224,14 @@ _create(const ugid_t ugid_,
|
|||
rv = searchFunc_(branches_,fusedirpath,existingpaths);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(existingpaths.empty())
|
||||
return -ENOENT;
|
||||
|
||||
rv = createFunc_(branches_,fusedirpath,createpaths);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(createpaths.empty())
|
||||
return -ENOENT;
|
||||
|
||||
rv = fs::clonepath(existingpaths[0]->path,
|
||||
createpaths[0]->path,
|
||||
|
|
@ -292,6 +296,9 @@ _create(const fuse_req_ctx_t *ctx_,
|
|||
FileInfo *fi = FileInfo::from_fh(ffi_->fh);
|
||||
int backing_id = INVALID_BACKING_ID;
|
||||
|
||||
if(not fi)
|
||||
return -EBADF;
|
||||
|
||||
switch(_(cfg.passthrough_io,ffi_->flags))
|
||||
{
|
||||
case _(PassthroughIO::ENUM::RO,O_RDONLY):
|
||||
|
|
|
|||
|
|
@ -48,22 +48,10 @@ FUSE::fallocate(const fuse_req_ctx_t *ctx_,
|
|||
off_t offset_,
|
||||
off_t len_)
|
||||
{
|
||||
u64 fh;
|
||||
FileInfo *fi = FileInfo::from_fh(fh_);
|
||||
|
||||
fh = fh_;
|
||||
if(fh == 0)
|
||||
{
|
||||
state.open_files.cvisit(ctx_->nodeid,
|
||||
[&](auto &val_)
|
||||
{
|
||||
fh = val_.second.fi->to_fh();
|
||||
});
|
||||
}
|
||||
|
||||
if(fh == 0)
|
||||
return -ENOENT;
|
||||
|
||||
FileInfo *fi = FileInfo::from_fh(fh);
|
||||
if(not fi)
|
||||
return -EBADF;
|
||||
|
||||
return ::_fallocate(fi->fd,
|
||||
mode_,
|
||||
|
|
|
|||
|
|
@ -43,22 +43,10 @@ FUSE::fchmod(const fuse_req_ctx_t *ctx_,
|
|||
cu64 fh_,
|
||||
const mode_t mode_)
|
||||
{
|
||||
u64 fh;
|
||||
FileInfo *fi = FileInfo::from_fh(fh_);
|
||||
|
||||
fh = fh_;
|
||||
if(fh == 0)
|
||||
{
|
||||
state.open_files.cvisit(ctx_->nodeid,
|
||||
[&](auto &val_)
|
||||
{
|
||||
fh = val_.second.fi->to_fh();
|
||||
});
|
||||
}
|
||||
|
||||
if(fh == 0)
|
||||
return -ENOENT;
|
||||
|
||||
FileInfo *fi = FileInfo::from_fh(fh);
|
||||
if(not fi)
|
||||
return -EBADF;
|
||||
|
||||
return ::_fchmod(fi->fd,mode_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,22 +47,10 @@ FUSE::fchown(const fuse_req_ctx_t *ctx_,
|
|||
const uid_t uid_,
|
||||
const gid_t gid_)
|
||||
{
|
||||
u64 fh;
|
||||
FileInfo *fi = FileInfo::from_fh(fh_);
|
||||
|
||||
fh = fh_;
|
||||
if(fh == 0)
|
||||
{
|
||||
state.open_files.cvisit(ctx_->nodeid,
|
||||
[&](auto &val_)
|
||||
{
|
||||
fh = val_.second.fi->to_fh();
|
||||
});
|
||||
}
|
||||
|
||||
if(fh == 0)
|
||||
return -ENOENT;
|
||||
|
||||
FileInfo *fi = FileInfo::from_fh(fh);
|
||||
if(not fi)
|
||||
return -EBADF;
|
||||
|
||||
return ::_fchown(fi->fd,uid_,gid_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,26 +54,14 @@ FUSE::fgetattr(const fuse_req_ctx_t *ctx_,
|
|||
fuse_timeouts_t *timeout_)
|
||||
{
|
||||
int rv;
|
||||
u64 fh;
|
||||
FileInfo *fi = FileInfo::from_fh(fh_);
|
||||
|
||||
fh = fh_;
|
||||
if(fh == 0)
|
||||
{
|
||||
state.open_files.cvisit(ctx_->nodeid,
|
||||
[&](const auto &val_)
|
||||
{
|
||||
fh = val_.second.fi->to_fh();
|
||||
});
|
||||
}
|
||||
|
||||
if(fh == 0)
|
||||
if(not fi)
|
||||
{
|
||||
timeout_->entry = cfg.cache_negative_entry;
|
||||
return -ENOENT;
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
FileInfo *fi = FileInfo::from_fh(fh);
|
||||
|
||||
rv = ::_fgetattr(fi,st_);
|
||||
|
||||
timeout_->entry = ((rv >= 0) ?
|
||||
|
|
|
|||
|
|
@ -43,22 +43,10 @@ FUSE::flock(const fuse_req_ctx_t *ctx_,
|
|||
const fuse_file_info_t *ffi_,
|
||||
int op_)
|
||||
{
|
||||
u64 fh;
|
||||
FileInfo* fi = FileInfo::from_fh(ffi_->fh);
|
||||
|
||||
fh = ffi_->fh;
|
||||
if(fh == 0)
|
||||
{
|
||||
state.open_files.cvisit(ctx_->nodeid,
|
||||
[&](const auto &val_)
|
||||
{
|
||||
fh = val_.second.fi->to_fh();
|
||||
});
|
||||
}
|
||||
|
||||
if(fh == 0)
|
||||
return -ENOENT;
|
||||
|
||||
FileInfo* fi = FileInfo::from_fh(fh);
|
||||
if(not fi)
|
||||
return -EBADF;
|
||||
|
||||
return ::_flock(fi->fd,op_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,22 +43,10 @@ FUSE::ftruncate(const fuse_req_ctx_t *ctx_,
|
|||
cu64 fh_,
|
||||
off_t size_)
|
||||
{
|
||||
u64 fh;
|
||||
FileInfo *fi = FileInfo::from_fh(fh_);
|
||||
|
||||
fh = fh_;
|
||||
if(fh == 0)
|
||||
{
|
||||
state.open_files.cvisit(ctx_->nodeid,
|
||||
[&](auto &val_)
|
||||
{
|
||||
fh = val_.second.fi->to_fh();
|
||||
});
|
||||
}
|
||||
|
||||
if(fh == 0)
|
||||
return -ENOENT;
|
||||
|
||||
FileInfo *fi = FileInfo::from_fh(fh);
|
||||
if(not fi)
|
||||
return -EBADF;
|
||||
|
||||
return ::_ftruncate(fi->fd,size_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,22 +45,10 @@ FUSE::futimens(const fuse_req_ctx_t *ctx_,
|
|||
cu64 fh_,
|
||||
const struct timespec ts_[2])
|
||||
{
|
||||
u64 fh;
|
||||
FileInfo *fi = FileInfo::from_fh(fh_);
|
||||
|
||||
fh = fh_;
|
||||
if(fh == 0)
|
||||
{
|
||||
state.open_files.cvisit(ctx_->nodeid,
|
||||
[&](const auto &val_)
|
||||
{
|
||||
fh = val_.second.fi->to_fh();
|
||||
});
|
||||
}
|
||||
|
||||
if(fh == 0)
|
||||
return -ENOENT;
|
||||
|
||||
FileInfo *fi = FileInfo::from_fh(fh);
|
||||
if(not fi)
|
||||
return -EBADF;
|
||||
|
||||
return ::_futimens(fi->fd,ts_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,8 @@ _set_stat_if_leads_to_reg(const fs::path &path_,
|
|||
|
||||
static
|
||||
int
|
||||
_getattr_fake_root(struct stat *st_)
|
||||
_getattr_fake_root(struct stat *st_,
|
||||
fuse_timeouts_t *timeout_)
|
||||
{
|
||||
st_->st_dev = 0;
|
||||
st_->st_ino = 0;
|
||||
|
|
@ -89,12 +90,16 @@ _getattr_fake_root(struct stat *st_)
|
|||
st_->st_mtime = 0;
|
||||
st_->st_ctime = 0;
|
||||
|
||||
timeout_->entry = 0;
|
||||
timeout_->attr = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_getattr_controlfile(struct stat *st_)
|
||||
_getattr_controlfile(struct stat *st_,
|
||||
fuse_timeouts_t *timeout_)
|
||||
{
|
||||
static const uid_t uid = ::getuid();
|
||||
static const gid_t gid = ::getgid();
|
||||
|
|
@ -114,13 +119,16 @@ _getattr_controlfile(struct stat *st_)
|
|||
st_->st_mtime = now;
|
||||
st_->st_ctime = now;
|
||||
|
||||
timeout_->entry = cfg.cache_entry;
|
||||
timeout_->attr = cfg.cache_attr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_getattr(const Policy::Search &searchFunc_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
struct stat *st_,
|
||||
const bool symlinkify_,
|
||||
|
|
@ -134,6 +142,8 @@ _getattr(const Policy::Search &searchFunc_,
|
|||
rv = searchFunc_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
fullpath = branches[0]->path / fusepath_;
|
||||
|
||||
|
|
@ -144,12 +154,12 @@ _getattr(const Policy::Search &searchFunc_,
|
|||
break;
|
||||
case FollowSymlinks::ENUM::DIRECTORY:
|
||||
rv = fs::lstat(fullpath,st_);
|
||||
if(S_ISLNK(st_->st_mode))
|
||||
if((rv >= 0) && S_ISLNK(st_->st_mode))
|
||||
::_set_stat_if_leads_to_dir(fullpath,st_);
|
||||
break;
|
||||
case FollowSymlinks::ENUM::REGULAR:
|
||||
rv = fs::lstat(fullpath,st_);
|
||||
if(S_ISLNK(st_->st_mode))
|
||||
if((rv >= 0) && S_ISLNK(st_->st_mode))
|
||||
::_set_stat_if_leads_to_reg(fullpath,st_);
|
||||
break;
|
||||
case FollowSymlinks::ENUM::ALL:
|
||||
|
|
@ -187,7 +197,7 @@ _getattr(const fs::path &fusepath_,
|
|||
cfg.symlinkify_timeout,
|
||||
cfg.follow_symlinks);
|
||||
if((rv < 0) && Config::is_rootdir(fusepath_))
|
||||
return ::_getattr_fake_root(st_);
|
||||
return ::_getattr_fake_root(st_,timeout_);
|
||||
|
||||
timeout_->entry = ((rv >= 0) ?
|
||||
cfg.cache_entry :
|
||||
|
|
@ -223,7 +233,7 @@ FUSE::getattr(const fs::path &fusepath_,
|
|||
fuse_timeouts_t *timeout_)
|
||||
{
|
||||
if(Config::is_ctrl_file(fusepath_))
|
||||
return ::_getattr_controlfile(st_);
|
||||
return ::_getattr_controlfile(st_,timeout_);
|
||||
|
||||
return ::_getattr(fusepath_,st_,timeout_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ _getxattr_from_string(char *destbuf_,
|
|||
|
||||
static
|
||||
int
|
||||
_getxattr_user_mergerfs_allpaths(const Branches::Ptr &branches_,
|
||||
_getxattr_user_mergerfs_allpaths(const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
char *buf_,
|
||||
const size_t count_)
|
||||
|
|
@ -120,7 +120,7 @@ int
|
|||
_getxattr_user_mergerfs(const fs::path &basepath_,
|
||||
const fs::path &fusepath_,
|
||||
const fs::path &fullpath_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const char *attrname_,
|
||||
char *buf_,
|
||||
const size_t count_)
|
||||
|
|
@ -144,7 +144,7 @@ _getxattr_user_mergerfs(const fs::path &basepath_,
|
|||
static
|
||||
int
|
||||
_getxattr(const Policy::Search &searchFunc_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
const char *attrname_,
|
||||
char *buf_,
|
||||
|
|
@ -157,6 +157,8 @@ _getxattr(const Policy::Search &searchFunc_,
|
|||
rv = searchFunc_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
fullpath = branches[0]->path / fusepath_;
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ _want(fuse_conn_info_t *conn_,
|
|||
static
|
||||
bool
|
||||
_capable(fuse_conn_info_t *conn_,
|
||||
const int flag_)
|
||||
const int flag_)
|
||||
{
|
||||
return !!(conn_->capable & flag_);
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@ _capable(fuse_conn_info_t *conn_,
|
|||
static
|
||||
void
|
||||
_want_if_capable(fuse_conn_info_t *conn_,
|
||||
const int flag_)
|
||||
const int flag_)
|
||||
{
|
||||
if(::_capable(conn_,flag_))
|
||||
::_want(conn_,flag_);
|
||||
|
|
@ -62,8 +62,8 @@ _want_if_capable(fuse_conn_info_t *conn_,
|
|||
static
|
||||
void
|
||||
_want_if_capable(fuse_conn_info_t *conn_,
|
||||
const int flag_,
|
||||
ConfigBOOL *want_)
|
||||
const int flag_,
|
||||
ConfigBOOL *want_)
|
||||
{
|
||||
if(*want_ && ::_capable(conn_,flag_))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "fs_open.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "mergerfs_ioctl.hpp"
|
||||
#include "state.hpp"
|
||||
#include "str.hpp"
|
||||
|
||||
#include <string>
|
||||
|
|
@ -115,6 +116,9 @@ _ioctl_file(const fuse_req_ctx_t *ctx_,
|
|||
{
|
||||
FileInfo *fi = FileInfo::from_fh(ffi_->fh);
|
||||
|
||||
if(not fi)
|
||||
return -EBADF;
|
||||
|
||||
return ::_ioctl(fi->fd,cmd_,data_,out_bufsz_);
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +129,7 @@ _ioctl_file(const fuse_req_ctx_t *ctx_,
|
|||
static
|
||||
int
|
||||
_ioctl_dir_base(const Policy::Search &searchFunc_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
const u32 cmd_,
|
||||
void *data_,
|
||||
|
|
@ -139,6 +143,8 @@ _ioctl_dir_base(const Policy::Search &searchFunc_,
|
|||
rv = searchFunc_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
fullpath = branches[0]->path / fusepath_;
|
||||
|
||||
|
|
@ -163,6 +169,9 @@ _ioctl_dir(const fuse_req_ctx_t *ctx_,
|
|||
{
|
||||
DirInfo *di = DirInfo::from_fh(ffi_->fh);
|
||||
|
||||
if(not di)
|
||||
return -EBADF;
|
||||
|
||||
return ::_ioctl_dir_base(cfg.func.open.policy,
|
||||
cfg.branches,
|
||||
di->fusepath.c_str(),
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ static
|
|||
int
|
||||
_link_create_path(const Policy::Search &searchFunc_,
|
||||
const Policy::Action &actionFunc_,
|
||||
const Branches &ibranches_,
|
||||
const Branches::Ptr ibranches_,
|
||||
const fs::path &oldfusepath_,
|
||||
const fs::path &newfusepath_)
|
||||
{
|
||||
|
|
@ -86,12 +86,16 @@ _link_create_path(const Policy::Search &searchFunc_,
|
|||
rv = actionFunc_(ibranches_,oldfusepath_,oldbranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(oldbranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
newfusedirpath = newfusepath_.parent_path();
|
||||
|
||||
rv = searchFunc_(ibranches_,newfusedirpath,newbranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(newbranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
return ::_link_create_path_loop(oldbranches,newbranches[0],
|
||||
oldfusepath_,newfusepath_,
|
||||
|
|
@ -148,7 +152,7 @@ _link_preserve_path_loop(const std::vector<Branch*> &oldbranches_,
|
|||
static
|
||||
int
|
||||
_link_preserve_path(const Policy::Action &actionFunc_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &oldfusepath_,
|
||||
const fs::path &newfusepath_,
|
||||
struct stat *st_)
|
||||
|
|
@ -159,6 +163,8 @@ _link_preserve_path(const Policy::Action &actionFunc_,
|
|||
rv = actionFunc_(branches_,oldfusepath_,oldbranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(oldbranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
return ::_link_preserve_path_loop(oldbranches,
|
||||
oldfusepath_,
|
||||
|
|
@ -231,8 +237,8 @@ _link_exdev_rel_symlink(const fuse_req_ctx_t *ctx_,
|
|||
static
|
||||
int
|
||||
_link_exdev_abs_base_symlink(const fuse_req_ctx_t *ctx_,
|
||||
const Policy::Search &openPolicy_,
|
||||
const Branches::Ptr &ibranches_,
|
||||
const Policy::Search &openPolicy_,
|
||||
const Branches::Ptr ibranches_,
|
||||
const fs::path &oldpath_,
|
||||
const fs::path &newpath_,
|
||||
struct stat *st_,
|
||||
|
|
@ -245,6 +251,8 @@ _link_exdev_abs_base_symlink(const fuse_req_ctx_t *ctx_,
|
|||
rv = openPolicy_(ibranches_,oldpath_,obranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(obranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
target = obranches[0]->path / oldpath_;
|
||||
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ _listxattr(const std::vector<Branch*> &branches_,
|
|||
static
|
||||
int
|
||||
_listxattr(const Policy::Search &searchFunc_,
|
||||
const Branches &ibranches_,
|
||||
const Branches::Ptr ibranches_,
|
||||
const fs::path &fusepath_,
|
||||
char *list_,
|
||||
const size_t size_)
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ int
|
|||
_mkdir(const ugid_t ugid_,
|
||||
const Policy::Search &getattrPolicy_,
|
||||
const Policy::Create &mkdirPolicy_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
const mode_t mode_,
|
||||
const mode_t umask_)
|
||||
|
|
@ -118,10 +118,14 @@ _mkdir(const ugid_t ugid_,
|
|||
rv = getattrPolicy_(branches_,fusedirpath,existingbranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(existingbranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
rv = mkdirPolicy_(branches_,fusedirpath,createbranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(createbranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
return ::_mkdir_loop(ugid_,
|
||||
existingbranches[0],
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ int
|
|||
_mknod(const ugid_t ugid_,
|
||||
const Policy::Search &searchFunc_,
|
||||
const Policy::Create &createFunc_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
const mode_t mode_,
|
||||
const mode_t umask_,
|
||||
|
|
@ -124,10 +124,14 @@ _mknod(const ugid_t ugid_,
|
|||
rv = searchFunc_(branches_,fusedirpath,existingbranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(existingbranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
rv = createFunc_(branches_,fusedirpath,createbranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(createbranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
return ::_mknod_loop(ugid_,
|
||||
existingbranches[0]->path,
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@
|
|||
simultaneously attempt to open the same file (same nodeid), and we
|
||||
need to:
|
||||
|
||||
1. Share a single canonical FileInfo entry in the open_files map for all
|
||||
opens of the same file while still giving each FUSE handle its own
|
||||
FileInfo object and file descriptor
|
||||
1. Share a single canonical FileInfo entry in the open_files map for
|
||||
all opens of the same file while still giving each FUSE handle
|
||||
its own FileInfo object and file descriptor
|
||||
2. Properly reference count to know when to release resources
|
||||
3. Handle race conditions without deadlocks or resource leaks
|
||||
4. Support FUSE passthrough mode for performance
|
||||
|
|
@ -45,8 +45,8 @@
|
|||
FileInfo by re-opening the canonical file descriptor
|
||||
3. If it doesn't exist, we create a new FileInfo and try to insert it
|
||||
4. If insertion fails (another thread inserted first), we clean up
|
||||
and retry (because to use passthrough it MUST be the same underlying
|
||||
file as the backing id was created)
|
||||
and retry (because to use passthrough it MUST be the same
|
||||
underlying file as the backing id was created)
|
||||
|
||||
THE RETRY LOOP
|
||||
--------------
|
||||
|
|
@ -308,7 +308,7 @@ _open_fd(const int fd_,
|
|||
static
|
||||
int
|
||||
_open(const Policy::Search &searchFunc_,
|
||||
const Branches &ibranches_,
|
||||
const Branches::Ptr ibranches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *ffi_,
|
||||
const bool link_cow_,
|
||||
|
|
@ -321,6 +321,8 @@ _open(const Policy::Search &searchFunc_,
|
|||
rv = searchFunc_(ibranches_,fusepath_,obranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(obranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
filepath = obranches[0]->path / fusepath_;
|
||||
|
||||
|
|
@ -423,6 +425,8 @@ _open(const fuse_req_ctx_t *ctx_,
|
|||
return rv;
|
||||
|
||||
fi = FileInfo::from_fh(ffi_->fh);
|
||||
if(not fi)
|
||||
return -EBADF;
|
||||
|
||||
switch(_(cfg.passthrough_io,ffi_->flags))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -67,6 +67,9 @@ FUSE::read(const fuse_req_ctx_t *ctx_,
|
|||
ioprio::SetFrom iop(ctx_->pid);
|
||||
FileInfo *fi = FileInfo::from_fh(ffi_->fh);
|
||||
|
||||
if(not fi)
|
||||
return -EBADF;
|
||||
|
||||
if(fi->direct_io)
|
||||
return ::_read_direct_io(fi->fd,buf_,size_,offset_);
|
||||
|
||||
|
|
|
|||
|
|
@ -84,18 +84,24 @@ _handle_ENOENT(const fuse_file_info_t *ffi_,
|
|||
dirent de;
|
||||
DirInfo *di = DirInfo::from_fh(ffi_->fh);
|
||||
|
||||
if(not di)
|
||||
return -EBADF;
|
||||
|
||||
if(!di->fusepath.empty())
|
||||
return -ENOENT;
|
||||
|
||||
constexpr const char msg[] =
|
||||
"error: no valid mergerfs branch found, check config";
|
||||
|
||||
de = {};
|
||||
|
||||
de.d_ino = 0;
|
||||
de.d_off = 0;
|
||||
de.d_type = DT_UNKNOWN;
|
||||
strcpy(de.d_name,"error: no valid mergerfs branch found, check config");
|
||||
strncpy(de.d_name,msg,(sizeof(msg) - 1));
|
||||
de.d_reclen = sizeof(de);
|
||||
|
||||
fuse_dirents_add(buf_,&de,::strlen(de.d_name));
|
||||
fuse_dirents_add(buf_,&de,(sizeof(msg) - 1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "tofrom_string.hpp"
|
||||
#include "fuse_readdir_base.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
|
|
@ -58,7 +59,7 @@ namespace FUSE
|
|||
void initialize();
|
||||
|
||||
private:
|
||||
bool _initialized = false;
|
||||
std::atomic<bool> _initialized = false;
|
||||
std::shared_ptr<std::string> _str;
|
||||
std::shared_ptr<FUSE::ReadDirBase> _impl;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ static
|
|||
inline
|
||||
int
|
||||
_concurrent_readdir(ThreadPool &tp_,
|
||||
const Branches::Ptr &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &rel_dirpath_,
|
||||
fuse_dirents_t *dirents_)
|
||||
{
|
||||
|
|
@ -89,6 +89,9 @@ FUSE::ReadDirCOR::operator()(const fuse_req_ctx_t *ctx_,
|
|||
{
|
||||
DirInfo *di = DirInfo::from_fh(ffi_->fh);
|
||||
|
||||
if(not di)
|
||||
return -EBADF;
|
||||
|
||||
return ::_concurrent_readdir(_tp,
|
||||
cfg.branches,
|
||||
di->fusepath,
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@ _readdir(const fs::path &branch_path_,
|
|||
DEFER{ fs::close(fd); };
|
||||
|
||||
buf = msgbuf_alloc();
|
||||
if(not buf)
|
||||
return -ENOMEM;
|
||||
|
||||
DEFER{ msgbuf_free(buf); };
|
||||
|
||||
fs::inode::ReaddirCalc inodecalc(branch_path_,rel_dirpath_);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ static
|
|||
inline
|
||||
int
|
||||
_readdir(ThreadPool &tp_,
|
||||
const Branches::Ptr &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &rel_dirpath_,
|
||||
fuse_dirents_t *dirents_)
|
||||
{
|
||||
|
|
@ -67,6 +67,9 @@ FUSE::ReadDirCOSR::operator()(const fuse_req_ctx_t *ctx_,
|
|||
{
|
||||
DirInfo *di = DirInfo::from_fh(ffi_->fh);
|
||||
|
||||
if(not di)
|
||||
return -EBADF;
|
||||
|
||||
return ::_readdir(_tp,
|
||||
cfg.branches,
|
||||
di->fusepath,
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ _readdir(std::vector<std::future<DirRV>> &dh_futures_,
|
|||
fuse_msgbuf_t *buf;
|
||||
|
||||
buf = msgbuf_alloc();
|
||||
if(not buf)
|
||||
return -ENOMEM;
|
||||
DEFER { msgbuf_free(buf); };
|
||||
|
||||
for(auto &dh_future : dh_futures_)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ FUSE::ReadDirSeq::operator()(const fuse_req_ctx_t *ctx_,
|
|||
{
|
||||
DirInfo *di = DirInfo::from_fh(ffi_->fh);
|
||||
|
||||
if(not di)
|
||||
return -EBADF;
|
||||
|
||||
return ::_readdir(cfg.branches,
|
||||
di->fusepath,
|
||||
dirents_);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ _readdir(const Branches::Ptr &branches_,
|
|||
fuse_dirents_reset(dirents_);
|
||||
|
||||
buf = msgbuf_alloc();
|
||||
if(not buf)
|
||||
return -ENOMEM;
|
||||
DEFER { msgbuf_free(buf); };
|
||||
|
||||
for(const auto &branch : *branches_)
|
||||
|
|
|
|||
|
|
@ -40,12 +40,11 @@ _readlink_core_standard(const fs::path &fullpath_,
|
|||
{
|
||||
int rv;
|
||||
|
||||
rv = fs::readlink(fullpath_,buf_,bufsize_);
|
||||
rv = fs::readlink(fullpath_,buf_,(bufsize_ - 1));
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
if((size_t)rv < bufsize_)
|
||||
buf_[rv] = '\0';
|
||||
buf_[rv] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -71,10 +70,9 @@ _readlink_core_symlinkify(const fs::path &fullpath_,
|
|||
if(!symlinkify::can_be_symlink(st,symlinkify_timeout_))
|
||||
return ::_readlink_core_standard(fullpath_,buf_,bufsize_);
|
||||
|
||||
n = std::min(fullpath_str.size(),bufsize_);
|
||||
n = std::min(fullpath_str.size(),(bufsize_ - 1));
|
||||
memcpy(buf_,fullpath_str.c_str(),n);
|
||||
if(n < bufsize_)
|
||||
buf_[n] = '\0';
|
||||
buf_[n] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -101,7 +99,7 @@ _readlink_core(const fs::path &basepath_,
|
|||
static
|
||||
int
|
||||
_readlink(const Policy::Search &searchFunc_,
|
||||
const Branches &ibranches_,
|
||||
const Branches::Ptr ibranches_,
|
||||
const fs::path &fusepath_,
|
||||
char *buf_,
|
||||
const size_t bufsize_,
|
||||
|
|
|
|||
|
|
@ -119,6 +119,9 @@ FUSE::release(const fuse_req_ctx_t *ctx_,
|
|||
{
|
||||
FileInfo *fi = FileInfo::from_fh(ffi_->fh);
|
||||
|
||||
if(not fi)
|
||||
return -EBADF;
|
||||
|
||||
return ::_release(ctx_->nodeid,
|
||||
fi,
|
||||
cfg.dropcacheonclose);
|
||||
|
|
|
|||
|
|
@ -39,5 +39,8 @@ FUSE::releasedir(const fuse_req_ctx_t *ctx_,
|
|||
{
|
||||
DirInfo *di = DirInfo::from_fh(ffi_->fh);
|
||||
|
||||
if(not di)
|
||||
return -EBADF;
|
||||
|
||||
return ::_releasedir(di);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ static
|
|||
int
|
||||
_removexattr(const Policy::Action &actionFunc_,
|
||||
const Policy::Search &searchFunc_,
|
||||
const Branches &ibranches_,
|
||||
const Branches::Ptr ibranches_,
|
||||
const fs::path &fusepath_,
|
||||
const char *attrname_)
|
||||
{
|
||||
|
|
@ -74,6 +74,8 @@ _removexattr(const Policy::Action &actionFunc_,
|
|||
rv = actionFunc_(ibranches_,fusepath_,obranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(obranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
::_removexattr_loop(obranches,fusepath_,attrname_,&prv);
|
||||
if(prv.errors.empty())
|
||||
|
|
@ -85,6 +87,8 @@ _removexattr(const Policy::Action &actionFunc_,
|
|||
rv = searchFunc_(ibranches_,fusepath_,obranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(obranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
return prv.get_error(obranches[0]->path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,8 +70,8 @@ _remove(const StrVec &toremove_)
|
|||
static
|
||||
int
|
||||
_rename_create_path(const Policy::Search &searchPolicy_,
|
||||
const Policy::Action &actionPolicy_,
|
||||
const Branches::Ptr &branches_,
|
||||
const Policy::Action &actionPolicy_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &oldfusepath_,
|
||||
const fs::path &newfusepath_)
|
||||
{
|
||||
|
|
@ -86,10 +86,14 @@ _rename_create_path(const Policy::Search &searchPolicy_,
|
|||
rv = actionPolicy_(branches_,oldfusepath_,oldbranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(oldbranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
rv = searchPolicy_(branches_,newfusepath_.parent_path(),newbranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(newbranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
for(auto &branch : *branches_)
|
||||
{
|
||||
|
|
@ -127,7 +131,7 @@ _rename_create_path(const Policy::Search &searchPolicy_,
|
|||
static
|
||||
int
|
||||
_rename_preserve_path(const Policy::Action &actionPolicy_,
|
||||
const Branches::Ptr &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &oldfusepath_,
|
||||
const fs::path &newfusepath_)
|
||||
{
|
||||
|
|
@ -198,7 +202,7 @@ _rename_exdev_rename_back(const std::vector<Branch*> &branches_,
|
|||
static
|
||||
int
|
||||
_rename_exdev_rename_target(const Policy::Action &actionPolicy_,
|
||||
const Branches::Ptr &ibranches_,
|
||||
const Branches::Ptr ibranches_,
|
||||
const fs::path &oldfusepath_,
|
||||
std::vector<Branch*> &obranches_)
|
||||
{
|
||||
|
|
@ -245,8 +249,8 @@ _rename_exdev_rename_target(const Policy::Action &actionPolicy_,
|
|||
static
|
||||
int
|
||||
_rename_exdev_rel_symlink(const fuse_req_ctx_t *ctx_,
|
||||
const Policy::Action &actionPolicy_,
|
||||
const Branches::Ptr &branches_,
|
||||
const Policy::Action &actionPolicy_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &oldfusepath_,
|
||||
const fs::path &newfusepath_)
|
||||
{
|
||||
|
|
@ -274,8 +278,8 @@ _rename_exdev_rel_symlink(const fuse_req_ctx_t *ctx_,
|
|||
static
|
||||
int
|
||||
_rename_exdev_abs_symlink(const fuse_req_ctx_t *ctx_,
|
||||
const Policy::Action &actionPolicy_,
|
||||
const Branches::Ptr &branches_,
|
||||
const Policy::Action &actionPolicy_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &mount_,
|
||||
const fs::path &oldfusepath_,
|
||||
const fs::path &newfusepath_)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ _rmdir_loop(const std::vector<Branch*> &branches_,
|
|||
static
|
||||
int
|
||||
_rmdir(const Policy::Action &actionFunc_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const FollowSymlinks followsymlinks_,
|
||||
const fs::path &fusepath_)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ static
|
|||
int
|
||||
_setxattr(const Policy::Action &setxattrPolicy_,
|
||||
const Policy::Search &getxattrPolicy_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
const char *attrname_,
|
||||
const char *attrval_,
|
||||
|
|
@ -159,6 +159,8 @@ _setxattr(const Policy::Action &setxattrPolicy_,
|
|||
rv = setxattrPolicy_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
::_setxattr_loop(branches,fusepath_,attrname_,attrval_,attrvalsize_,flags_,&prv);
|
||||
if(prv.errors.empty())
|
||||
|
|
@ -170,6 +172,8 @@ _setxattr(const Policy::Action &setxattrPolicy_,
|
|||
rv = getxattrPolicy_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
return prv.get_error(branches[0]->path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,9 +41,13 @@ _normalize_statvfs(struct statvfs *fsstat_,
|
|||
const unsigned long min_frsize_,
|
||||
const unsigned long min_namemax_)
|
||||
{
|
||||
fsstat_->f_blocks = (fsblkcnt_t)((fsstat_->f_blocks * fsstat_->f_frsize) / min_frsize_);
|
||||
fsstat_->f_bfree = (fsblkcnt_t)((fsstat_->f_bfree * fsstat_->f_frsize) / min_frsize_);
|
||||
fsstat_->f_bavail = (fsblkcnt_t)((fsstat_->f_bavail * fsstat_->f_frsize) / min_frsize_);
|
||||
long double scale;
|
||||
|
||||
scale = (((long double)fsstat_->f_frsize) / ((long double)min_frsize_));
|
||||
|
||||
fsstat_->f_blocks = (fsblkcnt_t)(fsstat_->f_blocks * scale);
|
||||
fsstat_->f_bfree = (fsblkcnt_t)(fsstat_->f_bfree * scale);
|
||||
fsstat_->f_bavail = (fsblkcnt_t)(fsstat_->f_bavail * scale);
|
||||
fsstat_->f_bsize = min_bsize_;
|
||||
fsstat_->f_frsize = min_frsize_;
|
||||
fsstat_->f_namemax = min_namemax_;
|
||||
|
|
@ -76,7 +80,7 @@ _should_ignore(const StatFSIgnore ignore_,
|
|||
|
||||
static
|
||||
int
|
||||
_statfs(const Branches::Ptr &branches_,
|
||||
_statfs(const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
const StatFS mode_,
|
||||
const StatFSIgnore ignore_,
|
||||
|
|
@ -147,7 +151,7 @@ FUSE::statfs(const fuse_req_ctx_t *ctx_,
|
|||
const char *fusepath_,
|
||||
struct statvfs *st_)
|
||||
{
|
||||
const fs::path fusepath{fusepath_};
|
||||
const fs::path fusepath{fusepath_};
|
||||
|
||||
return ::_statfs(cfg.branches,
|
||||
fusepath,
|
||||
|
|
|
|||
|
|
@ -75,7 +75,8 @@ _set_stat_if_leads_to_reg(const fs::path &path_,
|
|||
|
||||
static
|
||||
int
|
||||
_statx_fake_root(struct fuse_statx *st_)
|
||||
_statx_fake_root(struct fuse_statx *st_,
|
||||
fuse_timeouts_t *timeout_)
|
||||
{
|
||||
st_->ino = 0;
|
||||
st_->mode = (S_IFDIR|S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
|
||||
|
|
@ -88,12 +89,16 @@ _statx_fake_root(struct fuse_statx *st_)
|
|||
st_->mtime.tv_sec = 0;
|
||||
st_->ctime.tv_sec = 0;
|
||||
|
||||
timeout_->entry = cfg.cache_entry;
|
||||
timeout_->attr = cfg.cache_attr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_statx_controlfile(struct fuse_statx *st_)
|
||||
_statx_controlfile(struct fuse_statx *st_,
|
||||
fuse_timeouts_t *timeout_)
|
||||
{
|
||||
static const uid_t uid = ::getuid();
|
||||
static const gid_t gid = ::getgid();
|
||||
|
|
@ -110,13 +115,16 @@ _statx_controlfile(struct fuse_statx *st_)
|
|||
st_->mtime.tv_sec = now;
|
||||
st_->ctime.tv_sec = now;
|
||||
|
||||
timeout_->entry = cfg.cache_entry;
|
||||
timeout_->attr = cfg.cache_attr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_statx(const Policy::Search &searchFunc_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
const uint32_t flags_,
|
||||
const uint32_t mask_,
|
||||
|
|
@ -132,6 +140,8 @@ _statx(const Policy::Search &searchFunc_,
|
|||
rv = searchFunc_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
fullpath = branches[0]->path / fusepath_;
|
||||
|
||||
|
|
@ -190,7 +200,7 @@ _statx(const fs::path &fusepath_,
|
|||
cfg.symlinkify_timeout,
|
||||
cfg.follow_symlinks);
|
||||
if((rv < 0) && Config::is_rootdir(fusepath_))
|
||||
return ::_statx_fake_root(st_);
|
||||
return ::_statx_fake_root(st_,timeout_);
|
||||
|
||||
timeout_->entry = ((rv >= 0) ?
|
||||
cfg.cache_entry :
|
||||
|
|
@ -235,7 +245,7 @@ FUSE::statx(const fuse_req_ctx_t *ctx_,
|
|||
const fs::path fusepath{fusepath_};
|
||||
|
||||
if(Config::is_ctrl_file(fusepath))
|
||||
return ::_statx_controlfile(st_);
|
||||
return ::_statx_controlfile(st_,timeout_);
|
||||
|
||||
return ::_statx(fusepath,
|
||||
flags_|AT_STATX_DONT_SYNC,
|
||||
|
|
@ -253,27 +263,15 @@ FUSE::statx_fh(const fuse_req_ctx_t *ctx_,
|
|||
fuse_timeouts_t *timeout_)
|
||||
{
|
||||
int rv;
|
||||
uint64_t fh;
|
||||
FileInfo *fi = FileInfo::from_fh(fh_);
|
||||
|
||||
fh = fh_;
|
||||
if(fh == 0)
|
||||
{
|
||||
state.open_files.cvisit(ctx_->nodeid,
|
||||
[&](auto &val_)
|
||||
{
|
||||
fh = val_.second.fi->to_fh();
|
||||
});
|
||||
}
|
||||
if(not fi)
|
||||
return -EBADF;
|
||||
|
||||
if(fh == 0)
|
||||
return -ENOENT;
|
||||
|
||||
FileInfo *fi = FileInfo::from_fh(fh);
|
||||
|
||||
rv = ::_statx(fi,
|
||||
flags_|AT_STATX_DONT_SYNC,
|
||||
mask_,
|
||||
st_);
|
||||
rv = ::_statx(fi,
|
||||
flags_|AT_STATX_DONT_SYNC,
|
||||
mask_,
|
||||
st_);
|
||||
|
||||
timeout_->entry = ((rv >= 0) ?
|
||||
cfg.cache_entry :
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ int
|
|||
_symlink(const ugid_t ugid_,
|
||||
const Policy::Search &searchFunc_,
|
||||
const Policy::Create &createFunc_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const char *target_,
|
||||
const fs::path &linkpath_,
|
||||
struct stat *st_)
|
||||
|
|
@ -112,10 +112,14 @@ _symlink(const ugid_t ugid_,
|
|||
rv = searchFunc_(branches_,newdirpath,existingbranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(existingbranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
rv = createFunc_(branches_,newdirpath,newbranches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(newbranches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
return ::_symlink_loop(ugid_,
|
||||
existingbranches[0]->path,
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ static
|
|||
int
|
||||
_truncate(const Policy::Action &actionFunc_,
|
||||
const Policy::Search &searchFunc_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
const off_t size_)
|
||||
{
|
||||
|
|
@ -75,6 +75,8 @@ _truncate(const Policy::Action &actionFunc_,
|
|||
rv = actionFunc_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
::_truncate_loop(branches,fusepath_,size_,&prv);
|
||||
if(prv.errors.empty())
|
||||
|
|
@ -86,6 +88,8 @@ _truncate(const Policy::Action &actionFunc_,
|
|||
rv = searchFunc_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
return prv.get_error(branches[0]->path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ _unlink_loop(const std::vector<Branch*> &branches_,
|
|||
static
|
||||
int
|
||||
_unlink(const Policy::Action &unlinkPolicy_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_)
|
||||
{
|
||||
int rv;
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ static
|
|||
int
|
||||
_utimens(const Policy::Action &utimensPolicy_,
|
||||
const Policy::Search &getattrPolicy_,
|
||||
const Branches &branches_,
|
||||
const Branches::Ptr branches_,
|
||||
const fs::path &fusepath_,
|
||||
const timespec ts_[2])
|
||||
{
|
||||
|
|
@ -74,6 +74,8 @@ _utimens(const Policy::Action &utimensPolicy_,
|
|||
rv = utimensPolicy_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
::_utimens_loop(branches,fusepath_,ts_,&prv);
|
||||
if(prv.errors.empty())
|
||||
|
|
@ -85,6 +87,8 @@ _utimens(const Policy::Action &utimensPolicy_,
|
|||
rv = getattrPolicy_(branches_,fusepath_,branches);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(branches.empty())
|
||||
return -ENOENT;
|
||||
|
||||
return prv.get_error(branches[0]->path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,6 +168,8 @@ _write(const fuse_file_info_t *ffi_,
|
|||
FileInfo *fi;
|
||||
|
||||
fi = FileInfo::from_fh(ffi_->fh);
|
||||
if(not fi)
|
||||
return -EBADF;
|
||||
|
||||
// Concurrent writes can only happen if:
|
||||
// 1) writeback-cache is enabled and using page caching
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include "fs_statvfs_cache.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
#include "fs_statvfs_cache.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rnd.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "strvec.hpp"
|
||||
|
||||
#include <string>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include "fs_statvfs_cache.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include "base_types.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
#include "fs_statvfs_cache.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <limits>
|
||||
|
|
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2026, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace rwlock
|
||||
{
|
||||
class ReadGuard
|
||||
{
|
||||
public:
|
||||
ReadGuard(pthread_rwlock_t &lock_)
|
||||
: _lock(lock_)
|
||||
{
|
||||
pthread_rwlock_rdlock(&_lock);
|
||||
}
|
||||
|
||||
~ReadGuard()
|
||||
{
|
||||
pthread_rwlock_unlock(&_lock);
|
||||
}
|
||||
|
||||
private:
|
||||
ReadGuard();
|
||||
|
||||
private:
|
||||
pthread_rwlock_t &_lock;
|
||||
};
|
||||
|
||||
class WriteGuard
|
||||
{
|
||||
public:
|
||||
WriteGuard(pthread_rwlock_t &lock_)
|
||||
: _lock(lock_)
|
||||
{
|
||||
pthread_rwlock_wrlock(&_lock);
|
||||
}
|
||||
|
||||
~WriteGuard()
|
||||
{
|
||||
pthread_rwlock_unlock(&_lock);
|
||||
}
|
||||
|
||||
private:
|
||||
WriteGuard();
|
||||
|
||||
private:
|
||||
pthread_rwlock_t &_lock;
|
||||
};
|
||||
}
|
||||
|
|
@ -79,6 +79,7 @@
|
|||
|
||||
#include "fuse.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
|
@ -102,7 +103,14 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
int ref_count;
|
||||
OpenFile(OpenFile &&o_) noexcept
|
||||
: ref_count(o_.ref_count.load()),
|
||||
backing_id(o_.backing_id),
|
||||
fi(o_.fi)
|
||||
{
|
||||
}
|
||||
|
||||
std::atomic<int> ref_count;
|
||||
int backing_id;
|
||||
FileInfo *fi;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -300,6 +300,9 @@ bool
|
|||
str::eq(const char *s0_,
|
||||
const char *s1_) noexcept
|
||||
{
|
||||
if((s0_ == nullptr) || (s1_ == nullptr))
|
||||
return (s0_ == s1_);
|
||||
|
||||
return (std::strcmp(s0_, s1_) == 0);
|
||||
}
|
||||
|
||||
|
|
@ -307,6 +310,9 @@ bool
|
|||
str::startswith(const char *s_,
|
||||
const char *p_) noexcept
|
||||
{
|
||||
if((s_ == nullptr) || (p_ == nullptr))
|
||||
return false;
|
||||
|
||||
while(*p_)
|
||||
{
|
||||
if(*p_ != *s_)
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ struct fuse_lowlevel_ops
|
|||
void (*bmap)(fuse_req_t *req, const struct fuse_in_header *hdr);
|
||||
void (*copy_file_range)(fuse_req_t *req, const struct fuse_in_header *hdr);
|
||||
void (*create)(fuse_req_t *req, struct fuse_in_header *hdr);
|
||||
void (*destroy)(void *userdata);
|
||||
void (*destroy)();
|
||||
void (*fallocate)(fuse_req_t *req, const struct fuse_in_header *hdr);
|
||||
void (*flock)(fuse_req_t *req, uint64_t ino, fuse_file_info_t *fi, int op);
|
||||
void (*flush)(fuse_req_t *req, struct fuse_in_header *hdr);
|
||||
|
|
@ -113,7 +113,7 @@ struct fuse_lowlevel_ops
|
|||
void (*getattr)(fuse_req_t *req, struct fuse_in_header *hdr);
|
||||
void (*getlk)(fuse_req_t *req, const struct fuse_in_header *hdr);
|
||||
void (*getxattr)(fuse_req_t *req, struct fuse_in_header *hdr);
|
||||
void (*init)(void *userdata, fuse_conn_info_t *conn);
|
||||
void (*init)(fuse_conn_info_t *conn);
|
||||
void (*ioctl)(fuse_req_t *req, const struct fuse_in_header *hdr);
|
||||
void (*link)(fuse_req_t *req, struct fuse_in_header *hdr);
|
||||
void (*listxattr)(fuse_req_t *req, struct fuse_in_header *hdr);
|
||||
|
|
@ -383,20 +383,6 @@ int fuse_reply_ioctl_retry(fuse_req_t *req,
|
|||
*/
|
||||
int fuse_reply_ioctl(fuse_req_t *req, int result, const void *buf, uint32_t size);
|
||||
|
||||
/**
|
||||
* Reply to finish ioctl with iov buffer
|
||||
*
|
||||
* Possible requests:
|
||||
* ioctl
|
||||
*
|
||||
* @param req request handle
|
||||
* @param result result to be passed to the caller
|
||||
* @param iov the vector containing the data
|
||||
* @param count the size of vector
|
||||
*/
|
||||
int fuse_reply_ioctl_iov(fuse_req_t *req, int result, const struct iovec *iov,
|
||||
int count);
|
||||
|
||||
/**
|
||||
* Reply with poll result event mask
|
||||
*
|
||||
|
|
@ -535,12 +521,11 @@ int fuse_lowlevel_is_lib_option(const char *opt);
|
|||
* @param args argument vector
|
||||
* @param op the low level filesystem operations
|
||||
* @param op_size sizeof(struct fuse_lowlevel_ops)
|
||||
* @param userdata user data
|
||||
* @return the created session object, or NULL on failure
|
||||
*/
|
||||
struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
|
||||
const struct fuse_lowlevel_ops *op,
|
||||
size_t op_size, void *userdata);
|
||||
size_t op_size);
|
||||
|
||||
/* ----------------------------------------------------------- *
|
||||
* Session interface *
|
||||
|
|
|
|||
|
|
@ -214,6 +214,9 @@ private:
|
|||
static_cast<void*>(node) :
|
||||
_allocator.allocate(size_, alignof(T)));
|
||||
|
||||
if(not mem)
|
||||
return nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
return new(mem) T(std::forward<Args>(args_)...);
|
||||
|
|
@ -242,12 +245,13 @@ public:
|
|||
if(not obj_)
|
||||
return;
|
||||
|
||||
bool should_pool = _should_pool(obj_);
|
||||
bool should_pool = _should_pool(obj_);
|
||||
Node *node = to_node(obj_);
|
||||
|
||||
obj_->~T();
|
||||
|
||||
if(should_pool)
|
||||
_push_node(to_node(obj_),size_);
|
||||
_push_node(node,size_);
|
||||
else
|
||||
_allocator.deallocate(obj_,size_,alignof(T));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,14 +180,21 @@ ThreadPool::ThreadPool(const unsigned thread_count_,
|
|||
inline
|
||||
ThreadPool::~ThreadPool()
|
||||
{
|
||||
std::vector<pthread_t> threads;
|
||||
|
||||
{
|
||||
mutex_lockguard(_threads_mutex);
|
||||
threads = _threads;
|
||||
}
|
||||
|
||||
syslog(LOG_DEBUG,
|
||||
"threadpool (%s): destroying %zu threads",
|
||||
_name.c_str(),
|
||||
_threads.size());
|
||||
threads.size());
|
||||
|
||||
for(auto t : _threads)
|
||||
for(auto t : threads)
|
||||
pthread_cancel(t);
|
||||
for(auto t : _threads)
|
||||
for(auto t : threads)
|
||||
pthread_join(t,NULL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,6 +136,12 @@ CPU::cpu2core()
|
|||
|
||||
ifs >> core_id;
|
||||
|
||||
if(!ifs)
|
||||
{
|
||||
ifs.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
c2c[i] = core_id;
|
||||
|
||||
ifs.close();
|
||||
|
|
@ -169,6 +175,12 @@ CPU::core2cpus()
|
|||
|
||||
ifs >> core_id;
|
||||
|
||||
if(!ifs)
|
||||
{
|
||||
ifs.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
c2c[core_id].insert(i);
|
||||
|
||||
ifs.close();
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ _debug_set_output_stderr()
|
|||
auto new_log_file = std::shared_ptr<FILE>(stderr,[](FILE*){});
|
||||
|
||||
fuse_cfg.log_file(new_log_file);
|
||||
fuse_cfg.log_filepath("/dev/stderr");
|
||||
fuse_cfg.log_filepath("");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
/* For pthread_rwlock_t */
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
|
@ -15,9 +14,11 @@
|
|||
|
||||
#include "crc32b.h"
|
||||
#include "debug.hpp"
|
||||
#include "fatal.hpp"
|
||||
#include "kvec.h"
|
||||
#include "mutex.hpp"
|
||||
#include "node.hpp"
|
||||
#include "xalloc.hpp"
|
||||
|
||||
#include "fuse_cfg.hpp"
|
||||
#include "fuse_req.hpp"
|
||||
|
|
@ -188,7 +189,7 @@ id_hash(uint64_t ino)
|
|||
|
||||
static
|
||||
node_t*
|
||||
get_node_nocheck(uint64_t nodeid)
|
||||
get_node(const uint64_t nodeid)
|
||||
{
|
||||
size_t hash = id_hash(nodeid);
|
||||
node_t *node;
|
||||
|
|
@ -200,22 +201,6 @@ get_node_nocheck(uint64_t nodeid)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
node_t*
|
||||
get_node(const uint64_t nodeid)
|
||||
{
|
||||
node_t *node = get_node_nocheck(nodeid);
|
||||
|
||||
if(!node)
|
||||
{
|
||||
fprintf(stderr,"fuse internal error: node %llu not found\n",
|
||||
(unsigned long long)nodeid);
|
||||
abort();
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
remove_remembered_node(node_t *node_)
|
||||
|
|
@ -290,10 +275,11 @@ node_table_reduce(struct node_table *t)
|
|||
return;
|
||||
|
||||
newarray = realloc(t->array,sizeof(node_t*) * newsize);
|
||||
if(newarray != NULL)
|
||||
t->array = (node_t**)newarray;
|
||||
if(newarray == NULL)
|
||||
return;
|
||||
|
||||
t->size = newsize;
|
||||
t->array = (node_t**)newarray;
|
||||
t->size = newsize;
|
||||
t->split = t->size / 2;
|
||||
}
|
||||
|
||||
|
|
@ -471,33 +457,32 @@ static
|
|||
void
|
||||
unhash_name(node_t *node)
|
||||
{
|
||||
if(node->name)
|
||||
if(not (node && node->name && node->parent))
|
||||
return;
|
||||
|
||||
size_t hash = name_hash(node->parent->nodeid,node->name);
|
||||
node_t **nodep = &f.name_table.array[hash];
|
||||
|
||||
for(; *nodep != NULL; nodep = &(*nodep)->name_next)
|
||||
{
|
||||
size_t hash = name_hash(node->parent->nodeid,node->name);
|
||||
node_t **nodep = &f.name_table.array[hash];
|
||||
if(*nodep != node)
|
||||
continue;
|
||||
|
||||
for(; *nodep != NULL; nodep = &(*nodep)->name_next)
|
||||
if(*nodep == node)
|
||||
{
|
||||
*nodep = node->name_next;
|
||||
node->name_next = NULL;
|
||||
unref_node(node->parent);
|
||||
free(node->name);
|
||||
node->name = NULL;
|
||||
node->parent = NULL;
|
||||
f.name_table.use--;
|
||||
*nodep = node->name_next;
|
||||
node->name_next = NULL;
|
||||
unref_node(node->parent);
|
||||
free(node->name);
|
||||
node->name = NULL;
|
||||
node->parent = NULL;
|
||||
f.name_table.use--;
|
||||
|
||||
if(f.name_table.use < f.name_table.size / 4)
|
||||
remerge_name();
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"fuse internal error: unable to unhash node: %llu\n",
|
||||
(unsigned long long)node->nodeid);
|
||||
|
||||
abort();
|
||||
if(f.name_table.use < f.name_table.size / 4)
|
||||
remerge_name();
|
||||
return;
|
||||
}
|
||||
|
||||
fatal::abort("mergerfs: unable to unhash node: {}",
|
||||
node->nodeid);
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -517,6 +502,12 @@ rehash_name()
|
|||
for(nodep = &t->array[hash]; *nodep != NULL; nodep = next)
|
||||
{
|
||||
node_t *node = *nodep;
|
||||
if(node->parent == NULL)
|
||||
{
|
||||
next = &node->name_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t newhash = name_hash(node->parent->nodeid,node->name);
|
||||
|
||||
if(newhash != hash)
|
||||
|
|
@ -542,8 +533,15 @@ hash_name(node_t *node,
|
|||
uint64_t parentid,
|
||||
const char *name)
|
||||
{
|
||||
size_t hash = name_hash(parentid,name);
|
||||
node_t *parent = get_node(parentid);
|
||||
size_t hash;
|
||||
node_t *parent;
|
||||
|
||||
hash = name_hash(parentid,name);
|
||||
parent = get_node(parentid);
|
||||
|
||||
if(parent == NULL)
|
||||
return -1;
|
||||
|
||||
node->name = strdup(name);
|
||||
if(node->name == NULL)
|
||||
return -1;
|
||||
|
|
@ -634,12 +632,18 @@ find_node(uint64_t parent,
|
|||
const char *name)
|
||||
{
|
||||
node_t *node;
|
||||
mutex_lockguard(f.lock);
|
||||
|
||||
mutex_lock(f.lock);
|
||||
if(!name)
|
||||
node = get_node(parent);
|
||||
{
|
||||
node = get_node(parent);
|
||||
if(node == NULL)
|
||||
goto out_err;
|
||||
}
|
||||
else
|
||||
node = lookup_node(parent,name);
|
||||
{
|
||||
node = lookup_node(parent,name);
|
||||
}
|
||||
|
||||
if(node == NULL)
|
||||
{
|
||||
|
|
@ -664,8 +668,8 @@ find_node(uint64_t parent,
|
|||
remove_remembered_node(node);
|
||||
}
|
||||
inc_nlookup(node);
|
||||
|
||||
out_err:
|
||||
mutex_unlock(f.lock);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
|
@ -723,8 +727,11 @@ unlock_path(uint64_t nodeid,
|
|||
wnode->treelock = 0;
|
||||
}
|
||||
|
||||
for(node = get_node(nodeid);
|
||||
node != end && node->nodeid != FUSE_ROOT_ID;
|
||||
node = get_node(nodeid);
|
||||
if(node == NULL)
|
||||
return;
|
||||
|
||||
for(;node != end && node->nodeid != FUSE_ROOT_ID;
|
||||
node = node->parent)
|
||||
{
|
||||
assert(node->treelock != 0);
|
||||
|
|
@ -794,7 +801,14 @@ try_get_path(uint64_t nodeid,
|
|||
}
|
||||
}
|
||||
|
||||
for(node = get_node(nodeid); node->nodeid != FUSE_ROOT_ID; node = node->parent)
|
||||
node = get_node(nodeid);
|
||||
if(node == NULL)
|
||||
{
|
||||
err = -ESTALE;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
for(; node->nodeid != FUSE_ROOT_ID; node = node->parent)
|
||||
{
|
||||
err = -ESTALE;
|
||||
if(node->name == NULL || node->parent == NULL)
|
||||
|
|
@ -874,7 +888,8 @@ queue_element_wakeup(struct lock_queue_element *qe)
|
|||
if(!qe->path1)
|
||||
{
|
||||
/* Just waiting for it to be unlocked */
|
||||
if(get_node(qe->nodeid1)->treelock == 0)
|
||||
node_t *qnode = get_node(qe->nodeid1);
|
||||
if(qnode && (qnode->treelock == 0))
|
||||
pthread_cond_signal(&qe->cond);
|
||||
|
||||
return;
|
||||
|
|
@ -1102,8 +1117,11 @@ forget_node(const uint64_t nodeid,
|
|||
if(nodeid == FUSE_ROOT_ID)
|
||||
return;
|
||||
|
||||
mutex_lock(f.lock);
|
||||
mutex_lockguard(f.lock);
|
||||
|
||||
node = get_node(nodeid);
|
||||
if(node == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Node may still be locked due to interrupt idiocy in open,
|
||||
|
|
@ -1142,8 +1160,6 @@ forget_node(const uint64_t nodeid,
|
|||
|
||||
kv_push(remembered_node_t,f.remembered_nodes,fn);
|
||||
}
|
||||
|
||||
mutex_unlock(f.lock);
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -1320,15 +1336,14 @@ reply_entry(fuse_req_t *req_,
|
|||
|
||||
static
|
||||
void
|
||||
fuse_lib_init(void *data,
|
||||
fuse_conn_info_t *conn)
|
||||
fuse_lib_init(fuse_conn_info_t *conn)
|
||||
{
|
||||
f.ops.init(conn);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
fuse_lib_destroy(void *data)
|
||||
fuse_lib_destroy()
|
||||
{
|
||||
f.ops.destroy();
|
||||
}
|
||||
|
|
@ -1353,29 +1368,34 @@ fuse_lib_lookup(fuse_req_t *req_,
|
|||
if(name[1] == '\0')
|
||||
{
|
||||
name = NULL;
|
||||
mutex_lock(f.lock);
|
||||
dot = get_node_nocheck(nodeid);
|
||||
mutex_lockguard(f.lock);
|
||||
dot = get_node(nodeid);
|
||||
if(dot == NULL)
|
||||
{
|
||||
mutex_unlock(f.lock);
|
||||
reply_entry(req_,&e,-ESTALE);
|
||||
return;
|
||||
}
|
||||
dot->refctr++;
|
||||
mutex_unlock(f.lock);
|
||||
}
|
||||
else if((name[1] == '.') && (name[2] == '\0'))
|
||||
{
|
||||
if(nodeid == 1)
|
||||
if(nodeid == FUSE_ROOT_ID)
|
||||
{
|
||||
reply_entry(req_,&e,-ENOENT);
|
||||
return;
|
||||
}
|
||||
|
||||
name = NULL;
|
||||
mutex_lock(f.lock);
|
||||
nodeid = get_node(nodeid)->parent->nodeid;
|
||||
mutex_unlock(f.lock);
|
||||
mutex_lockguard(f.lock);
|
||||
{
|
||||
node_t *pnode = get_node(nodeid);
|
||||
if((pnode == NULL) || (pnode->parent == NULL))
|
||||
{
|
||||
reply_entry(req_,&e,-ESTALE);
|
||||
return;
|
||||
}
|
||||
nodeid = pnode->parent->nodeid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1476,19 +1496,28 @@ fuse_lib_getattr(fuse_req_t *req_,
|
|||
|
||||
if(!err)
|
||||
{
|
||||
err = ((fusepath != NULL) ?
|
||||
f.ops.getattr(&req_->ctx,&fusepath[1],&buf,&timeouts) :
|
||||
f.ops.fgetattr(&req_->ctx,fh,&buf,&timeouts));
|
||||
if(fusepath != NULL)
|
||||
err = f.ops.getattr(&req_->ctx,&fusepath[1],&buf,&timeouts);
|
||||
else if(fh != 0)
|
||||
err = f.ops.fgetattr(&req_->ctx,fh,&buf,&timeouts);
|
||||
else
|
||||
err = -ENOENT;
|
||||
|
||||
free_path(hdr_->nodeid,fusepath);
|
||||
}
|
||||
|
||||
if(!err)
|
||||
{
|
||||
mutex_lock(f.lock);
|
||||
node = get_node(hdr_->nodeid);
|
||||
update_stat(node,&buf);
|
||||
mutex_unlock(f.lock);
|
||||
{
|
||||
mutex_lockguard(f.lock);
|
||||
node = get_node(hdr_->nodeid);
|
||||
if(node == NULL)
|
||||
{
|
||||
fuse_reply_err(req_,ENOMEM);
|
||||
return;
|
||||
}
|
||||
update_stat(node,&buf);
|
||||
}
|
||||
set_stat(hdr_->nodeid,&buf);
|
||||
fuse_reply_attr(req_,&buf,timeouts.attr);
|
||||
}
|
||||
|
|
@ -1654,9 +1683,15 @@ fuse_lib_setattr(fuse_req_t *req_,
|
|||
|
||||
if(!err)
|
||||
{
|
||||
mutex_lock(f.lock);
|
||||
update_stat(get_node(hdr_->nodeid),&stbuf);
|
||||
mutex_unlock(f.lock);
|
||||
{
|
||||
node_t *node;
|
||||
mutex_lockguard(f.lock);
|
||||
|
||||
node = get_node(hdr_->nodeid);
|
||||
if(node)
|
||||
update_stat(node,&stbuf);
|
||||
}
|
||||
|
||||
set_stat(hdr_->nodeid,&stbuf);
|
||||
fuse_reply_attr(req_,&stbuf,timeouts.attr);
|
||||
}
|
||||
|
|
@ -1997,15 +2032,17 @@ fuse_do_release(fuse_req_ctx_t *req_ctx_,
|
|||
f.ops.release(req_ctx_,
|
||||
ffi_);
|
||||
|
||||
mutex_lock(f.lock);
|
||||
mutex_lockguard(f.lock);
|
||||
{
|
||||
node_t *node;
|
||||
|
||||
node = get_node(ino_);
|
||||
assert(node->open_count > 0);
|
||||
node->open_count--;
|
||||
if(node)
|
||||
{
|
||||
assert(node->open_count > 0);
|
||||
node->open_count--;
|
||||
}
|
||||
}
|
||||
mutex_unlock(f.lock);
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -2021,8 +2058,8 @@ fuse_lib_create(fuse_req_t *req_,
|
|||
struct fuse_entry_param e;
|
||||
struct fuse_create_in *arg;
|
||||
|
||||
arg = (fuse_create_in*)fuse_hdr_arg(hdr_);
|
||||
name = (const char*)PARAM(arg);
|
||||
arg = (fuse_create_in*)fuse_hdr_arg(hdr_);
|
||||
name = (const char*)PARAM(arg);
|
||||
|
||||
ffi.flags = arg->flags;
|
||||
|
||||
|
|
@ -2034,7 +2071,15 @@ fuse_lib_create(fuse_req_t *req_,
|
|||
// opportunistically allocate a node so we have a new nodeid for
|
||||
// later in the actual create. Added for use with passthrough.
|
||||
{
|
||||
node_t *node = find_node(hdr_->nodeid,name);
|
||||
node_t *node;
|
||||
|
||||
node = find_node(hdr_->nodeid,name);
|
||||
if(node == NULL)
|
||||
{
|
||||
fuse_reply_err(req_,ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
new_nodeid = node->nodeid;
|
||||
req_->ctx.nodeid = new_nodeid;
|
||||
}
|
||||
|
|
@ -2065,7 +2110,9 @@ fuse_lib_create(fuse_req_t *req_,
|
|||
if(!err)
|
||||
{
|
||||
mutex_lock(f.lock);
|
||||
get_node(e.ino)->open_count++;
|
||||
node_t *node = get_node(e.ino);
|
||||
if(node)
|
||||
node->open_count++;
|
||||
mutex_unlock(f.lock);
|
||||
|
||||
if(fuse_reply_create(req_,&e,&ffi) == -ENOENT)
|
||||
|
|
@ -2098,6 +2145,12 @@ open_auto_cache(fuse_req_ctx_t *req_ctx_,
|
|||
mutex_lock(f.lock);
|
||||
|
||||
node = get_node(ino);
|
||||
if(not node)
|
||||
{
|
||||
mutex_unlock(f.lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if(node->is_stat_cache_valid)
|
||||
{
|
||||
int err;
|
||||
|
|
@ -2134,7 +2187,7 @@ fuse_lib_open(fuse_req_t *req_,
|
|||
fuse_file_info_t ffi = {};
|
||||
struct fuse_open_in *arg;
|
||||
|
||||
arg = (fuse_open_in*)fuse_hdr_arg(hdr_);
|
||||
arg = (fuse_open_in*)fuse_hdr_arg(hdr_);
|
||||
|
||||
ffi.flags = arg->flags;
|
||||
|
||||
|
|
@ -2154,7 +2207,9 @@ fuse_lib_open(fuse_req_t *req_,
|
|||
if(!err)
|
||||
{
|
||||
mutex_lock(f.lock);
|
||||
get_node(hdr_->nodeid)->open_count++;
|
||||
node_t *node = get_node(hdr_->nodeid);
|
||||
if(node)
|
||||
node->open_count++;
|
||||
mutex_unlock(f.lock);
|
||||
/* The open syscall was interrupted,so it must be cancelled */
|
||||
if(fuse_reply_open(req_,&ffi) == -ENOENT)
|
||||
|
|
@ -2187,6 +2242,11 @@ fuse_lib_read(fuse_req_t *req_,
|
|||
}
|
||||
|
||||
msgbuf = msgbuf_alloc_page_aligned();
|
||||
if(msgbuf == NULL)
|
||||
{
|
||||
fuse_reply_err(req_,ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
res = f.ops.read(&req_->ctx,
|
||||
&ffi,
|
||||
|
|
@ -2260,11 +2320,17 @@ fuse_lib_fsync(fuse_req_t *req_,
|
|||
static
|
||||
struct fuse_dh*
|
||||
get_dirhandle(const fuse_file_info_t *llfi,
|
||||
fuse_file_info_t *fi)
|
||||
fuse_file_info_t *ffi)
|
||||
{
|
||||
struct fuse_dh *dh = (struct fuse_dh *)(uintptr_t)llfi->fh;
|
||||
memset(fi,0,sizeof(fuse_file_info_t));
|
||||
fi->fh = dh->fh;
|
||||
|
||||
if(dh == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(ffi,0,sizeof(fuse_file_info_t));
|
||||
|
||||
ffi->fh = dh->fh;
|
||||
|
||||
return dh;
|
||||
}
|
||||
|
||||
|
|
@ -2283,14 +2349,21 @@ fuse_lib_opendir(fuse_req_t *req_,
|
|||
arg = (fuse_open_in*)fuse_hdr_arg(hdr_);
|
||||
llffi.flags = arg->flags;
|
||||
|
||||
dh = (struct fuse_dh *)calloc(1,sizeof(struct fuse_dh));
|
||||
dh = (fuse_dh*)calloc(1,sizeof(fuse_dh));
|
||||
if(dh == NULL)
|
||||
{
|
||||
fuse_reply_err(req_,ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
fuse_dirents_init(&dh->d);
|
||||
err = fuse_dirents_init(&dh->d);
|
||||
if(err)
|
||||
{
|
||||
free(dh);
|
||||
fuse_reply_err(req_,ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_init(dh->lock);
|
||||
|
||||
llffi.fh = (uintptr_t)dh;
|
||||
|
|
@ -2313,8 +2386,9 @@ fuse_lib_opendir(fuse_req_t *req_,
|
|||
{
|
||||
/* The opendir syscall was interrupted,so it
|
||||
must be cancelled */
|
||||
f.ops.releasedir(&req_->ctx,
|
||||
&ffi);
|
||||
f.ops.releasedir(&req_->ctx,&ffi);
|
||||
|
||||
fuse_dirents_free(&dh->d);
|
||||
mutex_destroy(dh->lock);
|
||||
free(dh);
|
||||
}
|
||||
|
|
@ -2322,6 +2396,7 @@ fuse_lib_opendir(fuse_req_t *req_,
|
|||
else
|
||||
{
|
||||
fuse_reply_err(req_,err);
|
||||
fuse_dirents_free(&dh->d);
|
||||
mutex_destroy(dh->lock);
|
||||
free(dh);
|
||||
}
|
||||
|
|
@ -2363,7 +2438,7 @@ fuse_lib_readdir(fuse_req_t *req_,
|
|||
size_t size;
|
||||
fuse_dirents_t *d;
|
||||
struct fuse_dh *dh;
|
||||
fuse_file_info_t ffi = {};
|
||||
fuse_file_info_t ffi;
|
||||
fuse_file_info_t llffi = {};
|
||||
struct fuse_read_in *arg;
|
||||
|
||||
|
|
@ -2372,9 +2447,15 @@ fuse_lib_readdir(fuse_req_t *req_,
|
|||
llffi.fh = arg->fh;
|
||||
|
||||
dh = get_dirhandle(&llffi,&ffi);
|
||||
d = &dh->d;
|
||||
if(not dh)
|
||||
{
|
||||
fuse_reply_err(req_,EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(dh->lock);
|
||||
d = &dh->d;
|
||||
|
||||
mutex_lockguard(dh->lock);
|
||||
|
||||
rv = 0;
|
||||
if((arg->offset == 0) || (kv_size(d->data) == 0))
|
||||
|
|
@ -2385,17 +2466,17 @@ fuse_lib_readdir(fuse_req_t *req_,
|
|||
if(rv)
|
||||
{
|
||||
fuse_reply_err(req_,rv);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
size = readdir_buf_size(d,size,arg->offset);
|
||||
|
||||
fuse_reply_buf(req_,
|
||||
readdir_buf(d,arg->offset),
|
||||
size);
|
||||
|
||||
out:
|
||||
mutex_unlock(dh->lock);
|
||||
if(size == 0)
|
||||
fuse_reply_buf(req_,NULL,0);
|
||||
else
|
||||
fuse_reply_buf(req_,
|
||||
readdir_buf(d,arg->offset),
|
||||
size);
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -2407,7 +2488,7 @@ fuse_lib_readdir_plus(fuse_req_t *req_,
|
|||
size_t size;
|
||||
fuse_dirents_t *d;
|
||||
struct fuse_dh *dh;
|
||||
fuse_file_info_t ffi = {};
|
||||
fuse_file_info_t ffi;
|
||||
fuse_file_info_t llffi = {};
|
||||
struct fuse_read_in *arg;
|
||||
|
||||
|
|
@ -2416,9 +2497,15 @@ fuse_lib_readdir_plus(fuse_req_t *req_,
|
|||
llffi.fh = arg->fh;
|
||||
|
||||
dh = get_dirhandle(&llffi,&ffi);
|
||||
d = &dh->d;
|
||||
if(not dh)
|
||||
{
|
||||
fuse_reply_err(req_,EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(dh->lock);
|
||||
d = &dh->d;
|
||||
|
||||
mutex_lockguard(dh->lock);
|
||||
|
||||
rv = 0;
|
||||
if((arg->offset == 0) || (kv_size(d->data) == 0))
|
||||
|
|
@ -2429,17 +2516,17 @@ fuse_lib_readdir_plus(fuse_req_t *req_,
|
|||
if(rv)
|
||||
{
|
||||
fuse_reply_err(req_,rv);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
size = readdir_buf_size(d,size,arg->offset);
|
||||
|
||||
fuse_reply_buf(req_,
|
||||
readdir_buf(d,arg->offset),
|
||||
size);
|
||||
|
||||
out:
|
||||
mutex_unlock(dh->lock);
|
||||
if(size == 0)
|
||||
fuse_reply_buf(req_,NULL,0);
|
||||
else
|
||||
fuse_reply_buf(req_,
|
||||
readdir_buf(d,arg->offset),
|
||||
size);
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -2457,6 +2544,11 @@ fuse_lib_releasedir(fuse_req_t *req_,
|
|||
llffi.flags = arg->flags;
|
||||
|
||||
dh = get_dirhandle(&llffi,&ffi);
|
||||
if(not dh)
|
||||
{
|
||||
fuse_reply_err(req_,EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
f.ops.releasedir(&req_->ctx,
|
||||
&ffi);
|
||||
|
|
@ -2477,6 +2569,7 @@ fuse_lib_fsyncdir(fuse_req_t *req_,
|
|||
{
|
||||
int err;
|
||||
int is_datasync;
|
||||
fuse_dh *dh;
|
||||
fuse_file_info_t ffi;
|
||||
fuse_file_info_t llffi = {};
|
||||
struct fuse_fsync_in *arg;
|
||||
|
|
@ -2485,7 +2578,12 @@ fuse_lib_fsyncdir(fuse_req_t *req_,
|
|||
is_datasync = !!(arg->fsync_flags & FUSE_FSYNC_FDATASYNC);
|
||||
llffi.fh = arg->fh;
|
||||
|
||||
get_dirhandle(&llffi,&ffi);
|
||||
dh = get_dirhandle(&llffi,&ffi);
|
||||
if(not dh)
|
||||
{
|
||||
fuse_reply_err(req_,EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
err = f.ops.fsyncdir(&req_->ctx,
|
||||
&ffi,
|
||||
|
|
@ -2822,7 +2920,9 @@ fuse_lib_tmpfile(fuse_req_t *req_,
|
|||
if(!err)
|
||||
{
|
||||
mutex_lock(f.lock);
|
||||
get_node(e.ino)->open_count++;
|
||||
node_t *node = get_node(e.ino);
|
||||
if(node)
|
||||
node->open_count++;
|
||||
mutex_unlock(f.lock);
|
||||
|
||||
if(fuse_reply_create(req_,&e,&ffi) == -ENOENT)
|
||||
|
|
@ -3008,9 +3108,13 @@ fuse_flush_common(fuse_req_t *req_,
|
|||
{
|
||||
flock_to_lock(&lock,&l);
|
||||
l.owner = ffi_->lock_owner;
|
||||
mutex_lock(f.lock);
|
||||
locks_insert(get_node(ino_),&l);
|
||||
mutex_unlock(f.lock);
|
||||
|
||||
{
|
||||
mutex_lockguard(f.lock);
|
||||
node_t *n = get_node(ino_);
|
||||
if(n)
|
||||
locks_insert(n,&l);
|
||||
}
|
||||
|
||||
/* if op.lock() is defined FLUSH is needed regardless
|
||||
of op.flush() */
|
||||
|
|
@ -3133,11 +3237,15 @@ fuse_lib_getlk(fuse_req_t *req_,
|
|||
|
||||
flock_to_lock(&flk,&lk);
|
||||
lk.owner = ffi.lock_owner;
|
||||
mutex_lock(f.lock);
|
||||
conflict = locks_conflict(get_node(hdr_->nodeid),&lk);
|
||||
if(conflict)
|
||||
lock_to_flock(conflict,&flk);
|
||||
mutex_unlock(f.lock);
|
||||
|
||||
{
|
||||
mutex_lockguard(f.lock);
|
||||
node_t *n = get_node(hdr_->nodeid);
|
||||
conflict = (n ? locks_conflict(n,&lk) : NULL);
|
||||
if(conflict)
|
||||
lock_to_flock(conflict,&flk);
|
||||
}
|
||||
|
||||
if(!conflict)
|
||||
err = fuse_lock_common(req_,hdr_->nodeid,&ffi,&flk,F_GETLK);
|
||||
else
|
||||
|
|
@ -3157,16 +3265,26 @@ fuse_lib_setlk(fuse_req_t *req_,
|
|||
struct flock *lock,
|
||||
int sleep)
|
||||
{
|
||||
int err = fuse_lock_common(req_,ino,fi,lock,
|
||||
sleep ? F_SETLKW : F_SETLK);
|
||||
int err;
|
||||
|
||||
err = fuse_lock_common(req_,
|
||||
ino,
|
||||
fi,
|
||||
lock,
|
||||
sleep ? F_SETLKW : F_SETLK);
|
||||
if(!err)
|
||||
{
|
||||
lock_t l;
|
||||
|
||||
flock_to_lock(lock,&l);
|
||||
l.owner = fi->lock_owner;
|
||||
mutex_lock(f.lock);
|
||||
locks_insert(get_node(ino),&l);
|
||||
mutex_unlock(f.lock);
|
||||
|
||||
{
|
||||
mutex_lockguard(f.lock);
|
||||
node_t *n = get_node(ino);
|
||||
if(n)
|
||||
locks_insert(n,&l);
|
||||
}
|
||||
}
|
||||
|
||||
fuse_reply_err(req_,err);
|
||||
|
|
@ -3224,20 +3342,20 @@ fuse_lib_ioctl(fuse_req_t *req_,
|
|||
{
|
||||
int err;
|
||||
char *out_buf = NULL;
|
||||
fuse_file_info_t ffi;
|
||||
fuse_dh *dh;
|
||||
fuse_file_info_t ffi = {};
|
||||
fuse_file_info_t llffi = {};
|
||||
const void *in_buf;
|
||||
uint32_t out_size;
|
||||
const struct fuse_ioctl_in *arg;
|
||||
|
||||
arg = (fuse_ioctl_in*)fuse_hdr_arg(hdr_);
|
||||
if((arg->flags & FUSE_IOCTL_DIR) && !(req_->conn.want & FUSE_CAP_IOCTL_DIR))
|
||||
{
|
||||
fuse_reply_err(req_,ENOTTY);
|
||||
return;
|
||||
}
|
||||
|
||||
if((sizeof(void*) == 4) &&
|
||||
err = -EPERM;
|
||||
if(arg->flags & FUSE_IOCTL_UNRESTRICTED)
|
||||
goto err;
|
||||
|
||||
if((sizeof(void*) == 4) &&
|
||||
(req_->conn.proto_minor >= 16) &&
|
||||
!(arg->flags & FUSE_IOCTL_32BIT))
|
||||
{
|
||||
|
|
@ -3248,14 +3366,27 @@ fuse_lib_ioctl(fuse_req_t *req_,
|
|||
out_size = arg->out_size;
|
||||
in_buf = (arg->in_size ? PARAM(arg) : NULL);
|
||||
|
||||
err = -EPERM;
|
||||
if(arg->flags & FUSE_IOCTL_UNRESTRICTED)
|
||||
goto err;
|
||||
|
||||
if(arg->flags & FUSE_IOCTL_DIR)
|
||||
get_dirhandle(&llffi,&ffi);
|
||||
{
|
||||
dh = get_dirhandle(&llffi,&ffi);
|
||||
if(not dh)
|
||||
{
|
||||
err = -EBADF;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
else
|
||||
ffi = llffi;
|
||||
{
|
||||
ffi = llffi;
|
||||
}
|
||||
|
||||
if((arg->in_size > 0) &&
|
||||
(out_size > 0) &&
|
||||
(arg->in_size != out_size))
|
||||
{
|
||||
err = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(out_size)
|
||||
{
|
||||
|
|
@ -3263,28 +3394,27 @@ fuse_lib_ioctl(fuse_req_t *req_,
|
|||
out_buf = (char*)malloc(out_size);
|
||||
if(!out_buf)
|
||||
goto err;
|
||||
DEFER { free(out_buf); };
|
||||
}
|
||||
|
||||
assert(!arg->in_size || !out_size || arg->in_size == out_size);
|
||||
if(out_buf && in_buf)
|
||||
memcpy(out_buf,in_buf,arg->in_size);
|
||||
if(in_buf && out_buf)
|
||||
memcpy(out_buf,in_buf,out_size);
|
||||
|
||||
err = f.ops.ioctl(&req_->ctx,
|
||||
&ffi,
|
||||
arg->cmd,
|
||||
(void*)(uintptr_t)arg->arg,
|
||||
arg->flags,
|
||||
out_buf ?: (void *)in_buf,
|
||||
out_buf ? out_buf : (void*)in_buf,
|
||||
&out_size);
|
||||
if(err < 0)
|
||||
goto err;
|
||||
|
||||
fuse_reply_ioctl(req_,err,out_buf,out_size);
|
||||
goto out;
|
||||
return;
|
||||
|
||||
err:
|
||||
fuse_reply_err(req_,err);
|
||||
out:
|
||||
free(out_buf);
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -3352,7 +3482,11 @@ remembered_node_cmp(const void *a_,
|
|||
const remembered_node_t *a = (const remembered_node_t*)a_;
|
||||
const remembered_node_t *b = (const remembered_node_t*)b_;
|
||||
|
||||
return (a->time - b->time);
|
||||
if(a->time < b->time)
|
||||
return -1;
|
||||
if(a->time > b->time)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -3606,7 +3740,10 @@ metrics_log_nodes_info_to_tmp_dir(struct fuse *f_)
|
|||
struct stat st;
|
||||
char const *mode = "a";
|
||||
|
||||
sprintf(filepath,"/tmp/mergerfs.%d.info",getpid());
|
||||
snprintf(filepath,
|
||||
sizeof(filepath),
|
||||
"/tmp/mergerfs.%d.info",
|
||||
getpid());
|
||||
|
||||
rv = lstat(filepath,&st);
|
||||
if((rv == 0) && (st.st_size > INFO_FILE_MAX_SIZE))
|
||||
|
|
@ -3725,7 +3862,7 @@ fuse_new(int fd_,
|
|||
llop.setlk = NULL;
|
||||
}
|
||||
|
||||
f.se = fuse_lowlevel_new_common(args,&llop,sizeof(llop),&f);
|
||||
f.se = fuse_lowlevel_new_common(args,&llop,sizeof(llop));
|
||||
if(f.se == NULL)
|
||||
goto out_free_fs;
|
||||
|
||||
|
|
@ -3750,11 +3887,11 @@ fuse_new(int fd_,
|
|||
root = node_alloc();
|
||||
if(root == NULL)
|
||||
{
|
||||
fprintf(stderr,"fuse: memory allocation failed\n");
|
||||
fprintf(stderr,"mergerfs: root node alloc failed\n");
|
||||
goto out_free_id_table;
|
||||
}
|
||||
|
||||
root->name = strdup("/");
|
||||
root->name = xstrdup("/");
|
||||
|
||||
root->parent = NULL;
|
||||
root->nodeid = FUSE_ROOT_ID;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,6 @@ EXTERN_C_BEGIN
|
|||
|
||||
struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
|
||||
const struct fuse_lowlevel_ops *op,
|
||||
size_t op_size, void *userdata);
|
||||
size_t op_size);
|
||||
|
||||
EXTERN_C_END
|
||||
|
|
|
|||
|
|
@ -57,6 +57,13 @@ _print_error(int rv_)
|
|||
-rv_);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_nproc()
|
||||
{
|
||||
return std::max(1,(int)std::thread::hardware_concurrency());
|
||||
}
|
||||
|
||||
struct AsyncWorker
|
||||
{
|
||||
fuse_session *_se;
|
||||
|
|
@ -86,6 +93,11 @@ struct AsyncWorker
|
|||
fuse_msgbuf_t *msgbuf;
|
||||
|
||||
msgbuf = msgbuf_alloc();
|
||||
if(not msgbuf)
|
||||
{
|
||||
fmt::println(stderr,"mergerfs: failure to allocate msgbuf, exiting");
|
||||
return;
|
||||
}
|
||||
|
||||
while(true)
|
||||
{
|
||||
|
|
@ -141,6 +153,11 @@ struct SyncWorker
|
|||
fuse_msgbuf_t *msgbuf;
|
||||
|
||||
msgbuf = msgbuf_alloc();
|
||||
if(not msgbuf)
|
||||
{
|
||||
fmt::println(stderr,"mergerfs: failure to allocate msgbuf, exiting");
|
||||
return;
|
||||
}
|
||||
|
||||
while(true)
|
||||
{
|
||||
|
|
@ -166,31 +183,6 @@ struct SyncWorker
|
|||
}
|
||||
};
|
||||
|
||||
int
|
||||
fuse_start_thread(pthread_t *thread_id,
|
||||
void *(*func)(void *),
|
||||
void *arg)
|
||||
{
|
||||
int res;
|
||||
sigset_t oldset;
|
||||
sigset_t newset;
|
||||
|
||||
sigfillset(&newset);
|
||||
pthread_sigmask(SIG_BLOCK,&newset,&oldset);
|
||||
res = pthread_create(thread_id,NULL,func,arg);
|
||||
pthread_sigmask(SIG_SETMASK,&oldset,NULL);
|
||||
|
||||
if(res != 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"fuse: error creating thread: %s\n",
|
||||
strerror(res));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_calculate_thread_count(const int raw_thread_count_)
|
||||
|
|
@ -199,12 +191,12 @@ _calculate_thread_count(const int raw_thread_count_)
|
|||
|
||||
if(raw_thread_count_ == 0)
|
||||
{
|
||||
thread_count = std::thread::hardware_concurrency();
|
||||
thread_count = ::_nproc();
|
||||
thread_count = std::min(8,thread_count);
|
||||
}
|
||||
else if(raw_thread_count_ < 0)
|
||||
{
|
||||
thread_count = (std::thread::hardware_concurrency() / -raw_thread_count_);
|
||||
thread_count = (::_nproc() / -raw_thread_count_);
|
||||
thread_count = std::max(1,thread_count);
|
||||
}
|
||||
else if(raw_thread_count_ > 0)
|
||||
|
|
@ -225,14 +217,14 @@ _calculate_thread_counts(int *read_thread_count_,
|
|||
{
|
||||
int nproc;
|
||||
|
||||
nproc = std::thread::hardware_concurrency();
|
||||
nproc = ::_nproc();
|
||||
*read_thread_count_ = std::min(8,nproc);
|
||||
}
|
||||
else if((*read_thread_count_ == 0) && (*process_thread_count_ == 0))
|
||||
{
|
||||
int nproc;
|
||||
|
||||
nproc = std::thread::hardware_concurrency();
|
||||
nproc = ::_nproc();
|
||||
*read_thread_count_ = 2;
|
||||
*process_thread_count_ = std::max(2,(nproc - 2));
|
||||
*process_thread_count_ = std::min(8,*process_thread_count_);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ static size_t pagesize;
|
|||
struct fuse_ll
|
||||
{
|
||||
struct fuse_lowlevel_ops op;
|
||||
void *userdata;
|
||||
uid_t owner;
|
||||
fuse_conn_info_t conn;
|
||||
mutex_t lock;
|
||||
|
|
@ -361,6 +360,9 @@ int
|
|||
fuse_reply_readlink(fuse_req_t *req,
|
||||
const char *linkname)
|
||||
{
|
||||
if(not linkname)
|
||||
return fuse_reply_err(req,EIO);
|
||||
|
||||
if(fuse_cfg.debug)
|
||||
fuse_debug_readlink(req->ctx.unique,linkname);
|
||||
|
||||
|
|
@ -538,12 +540,12 @@ fuse_reply_ioctl_retry(fuse_req_t *req,
|
|||
const struct iovec *out_iov,
|
||||
size_t out_count)
|
||||
{
|
||||
int res;
|
||||
struct fuse_ioctl_out arg = {};
|
||||
struct fuse_ioctl_iovec *in_fiov = NULL;
|
||||
struct fuse_ioctl_iovec *out_fiov = NULL;
|
||||
struct iovec iov[4];
|
||||
size_t count = 1;
|
||||
int res;
|
||||
|
||||
arg.flags |= FUSE_IOCTL_RETRY;
|
||||
arg.in_iovs = in_count;
|
||||
|
|
@ -603,6 +605,7 @@ fuse_reply_ioctl_retry(fuse_req_t *req,
|
|||
}
|
||||
|
||||
res = send_reply_iov(req, 0, iov, count);
|
||||
|
||||
out:
|
||||
free(in_fiov);
|
||||
free(out_fiov);
|
||||
|
|
@ -647,36 +650,6 @@ fuse_reply_ioctl(fuse_req_t *req,
|
|||
return send_reply_iov(req, 0, iov, count);
|
||||
}
|
||||
|
||||
int
|
||||
fuse_reply_ioctl_iov(fuse_req_t *req,
|
||||
int result,
|
||||
const struct iovec *iov,
|
||||
int count)
|
||||
{
|
||||
struct iovec *padded_iov;
|
||||
struct fuse_ioctl_out arg = {};
|
||||
int res;
|
||||
|
||||
padded_iov = (iovec*)malloc((count + 2) * sizeof(struct iovec));
|
||||
if(padded_iov == NULL)
|
||||
return fuse_reply_err(req, ENOMEM);
|
||||
|
||||
arg.result = result;
|
||||
|
||||
if(fuse_cfg.debug)
|
||||
fuse_debug_ioctl_out(req->ctx.unique,&arg);
|
||||
|
||||
padded_iov[1].iov_base = &arg;
|
||||
padded_iov[1].iov_len = sizeof(arg);
|
||||
|
||||
memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
|
||||
|
||||
res = send_reply_iov(req, 0, padded_iov, count + 2);
|
||||
free(padded_iov);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
fuse_reply_poll(fuse_req_t *req,
|
||||
unsigned revents)
|
||||
|
|
@ -1195,8 +1168,7 @@ do_init(fuse_req_t *req,
|
|||
max_write = bufsize;
|
||||
|
||||
f.got_init = 1;
|
||||
if(f.op.init)
|
||||
f.op.init(f.userdata, &f.conn);
|
||||
f.op.init(&f.conn);
|
||||
|
||||
outargflags = outarg.flags;
|
||||
if((inargflags & FUSE_MAX_PAGES) && (f.conn.want & FUSE_CAP_MAX_PAGES))
|
||||
|
|
@ -1309,7 +1281,8 @@ do_destroy(fuse_req_t *req,
|
|||
struct fuse_in_header *hdr_)
|
||||
{
|
||||
f.got_destroy = 1;
|
||||
f.op.destroy(f.userdata);
|
||||
|
||||
f.op.destroy();
|
||||
|
||||
send_reply_ok(req,NULL,0);
|
||||
}
|
||||
|
|
@ -1697,10 +1670,7 @@ void
|
|||
fuse_ll_destroy(void *data)
|
||||
{
|
||||
if(f.got_init && !f.got_destroy)
|
||||
{
|
||||
if(f.op.destroy)
|
||||
f.op.destroy(f.userdata);
|
||||
}
|
||||
f.op.destroy();
|
||||
|
||||
mutex_destroy(f.lock);
|
||||
msgbuf_gc();
|
||||
|
|
@ -1854,8 +1824,7 @@ fuse_ll_buf_process_read_init(struct fuse_session *se_,
|
|||
struct fuse_session *
|
||||
fuse_lowlevel_new_common(struct fuse_args *args,
|
||||
const struct fuse_lowlevel_ops *op,
|
||||
size_t op_size,
|
||||
void *userdata)
|
||||
size_t op_size)
|
||||
{
|
||||
struct fuse_session *se;
|
||||
|
||||
|
|
@ -1871,7 +1840,6 @@ fuse_lowlevel_new_common(struct fuse_args *args,
|
|||
|
||||
memcpy(&f.op,op,op_size);
|
||||
f.owner = getuid();
|
||||
f.userdata = userdata;
|
||||
|
||||
se = fuse_session_new(&f,
|
||||
(void*)fuse_ll_buf_receive_read,
|
||||
|
|
@ -1892,8 +1860,7 @@ fuse_lowlevel_new_common(struct fuse_args *args,
|
|||
struct fuse_session*
|
||||
fuse_lowlevel_new(struct fuse_args *args,
|
||||
const struct fuse_lowlevel_ops *op,
|
||||
size_t op_size,
|
||||
void *userdata)
|
||||
size_t op_size)
|
||||
{
|
||||
return fuse_lowlevel_new_common(args, op, op_size, userdata);
|
||||
return fuse_lowlevel_new_common(args, op, op_size);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,23 +214,35 @@ int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
|
|||
return find_opt(opts, opt, &dummy) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int process_opt_param(void *var, const char *format, const char *param,
|
||||
const char *arg)
|
||||
static
|
||||
int
|
||||
process_opt_param(void *var,
|
||||
const char *format,
|
||||
const char *param,
|
||||
const char *arg)
|
||||
{
|
||||
assert(format[0] == '%');
|
||||
if (format[1] == 's')
|
||||
|
||||
if(format[1] == 's')
|
||||
{
|
||||
char *copy = strdup(param);
|
||||
if (!copy)
|
||||
if(!copy)
|
||||
return alloc_failed();
|
||||
|
||||
*static_cast<char**>(var) = copy;
|
||||
} else {
|
||||
if (sscanf(param, format, static_cast<int*>(var)) != 1) {
|
||||
fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = sscanf(param, format, static_cast<int*>(var));
|
||||
if(rv != 1)
|
||||
{
|
||||
fprintf(stderr,"mergerfs: invalid parameter in option `%s'\n",arg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ fuse_session_new(void *data,
|
|||
void
|
||||
fuse_session_destroy(struct fuse_session *se)
|
||||
{
|
||||
if(se == nullptr)
|
||||
return;
|
||||
|
||||
if(se->destroy)
|
||||
se->destroy(se->f);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,19 +8,24 @@
|
|||
|
||||
#include "fuse_lowlevel.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
static struct fuse_session *fuse_instance;
|
||||
static std::atomic<fuse_session*> g_fuse_instance{nullptr};
|
||||
|
||||
static
|
||||
void
|
||||
exit_handler(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
if (fuse_instance)
|
||||
fuse_session_exit(fuse_instance);
|
||||
struct fuse_session *instance;
|
||||
|
||||
instance = g_fuse_instance.load(std::memory_order_acquire);
|
||||
if(instance)
|
||||
fuse_session_exit(instance);
|
||||
}
|
||||
|
||||
static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
|
||||
|
|
@ -54,20 +59,20 @@ int fuse_set_signal_handlers(struct fuse_session *se)
|
|||
(set_one_signal_handler(SIGPIPE, SIG_IGN, 0) == -1))
|
||||
return -1;
|
||||
|
||||
fuse_instance = se;
|
||||
g_fuse_instance.store(se,std::memory_order_release);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fuse_remove_signal_handlers(struct fuse_session *se)
|
||||
{
|
||||
if (fuse_instance != se)
|
||||
fprintf(stderr,
|
||||
"fuse: fuse_remove_signal_handlers: unknown session\n");
|
||||
else
|
||||
fuse_instance = NULL;
|
||||
|
||||
set_one_signal_handler(SIGINT, exit_handler, 1);
|
||||
set_one_signal_handler(SIGTERM, exit_handler, 1);
|
||||
set_one_signal_handler(SIGQUIT, exit_handler, 1);
|
||||
set_one_signal_handler(SIGPIPE, SIG_IGN, 1);
|
||||
|
||||
if(g_fuse_instance.load(std::memory_order_acquire) != se)
|
||||
fprintf(stderr,"mergerfs: fuse_remove_signal_handlers: unknown session\n");
|
||||
else
|
||||
g_fuse_instance.store(nullptr,std::memory_order_release);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ fuse_helper_opt_proc(void *data,
|
|||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int add_default_subtype(const char *progname, struct fuse_args *args)
|
||||
|
|
@ -153,58 +153,66 @@ fuse_parse_cmdline(struct fuse_args *args_,
|
|||
|
||||
err:
|
||||
free(hopts.mountpoint);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fuse_daemonize(int foreground)
|
||||
int
|
||||
fuse_daemonize(int foreground)
|
||||
{
|
||||
if (!foreground) {
|
||||
int nullfd;
|
||||
int waiter[2];
|
||||
char completed;
|
||||
if(!foreground)
|
||||
{
|
||||
int nullfd;
|
||||
int waiter[2];
|
||||
char completed;
|
||||
|
||||
if (pipe(waiter)) {
|
||||
perror("fuse_daemonize: pipe");
|
||||
return -1;
|
||||
if(pipe(waiter))
|
||||
{
|
||||
perror("fuse_daemonize: pipe");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* demonize current process by forking it and killing the
|
||||
* parent. This makes current process as a child of 'init'.
|
||||
*/
|
||||
switch(fork())
|
||||
{
|
||||
case -1:
|
||||
perror("fuse_daemonize: fork");
|
||||
return -1;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
read(waiter[0], &completed, sizeof(completed));
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if(setsid() == -1)
|
||||
{
|
||||
perror("fuse_daemonize: setsid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
(void) chdir("/");
|
||||
|
||||
nullfd = open("/dev/null", O_RDWR, 0);
|
||||
if(nullfd != -1)
|
||||
{
|
||||
(void) dup2(nullfd, 0);
|
||||
(void) dup2(nullfd, 1);
|
||||
(void) dup2(nullfd, 2);
|
||||
if (nullfd > 2)
|
||||
close(nullfd);
|
||||
}
|
||||
|
||||
/* Propagate completion of daemon initializatation */
|
||||
completed = 1;
|
||||
write(waiter[1], &completed, sizeof(completed));
|
||||
close(waiter[0]);
|
||||
close(waiter[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
* demonize current process by forking it and killing the
|
||||
* parent. This makes current process as a child of 'init'.
|
||||
*/
|
||||
switch(fork()) {
|
||||
case -1:
|
||||
perror("fuse_daemonize: fork");
|
||||
return -1;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
read(waiter[0], &completed, sizeof(completed));
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if (setsid() == -1) {
|
||||
perror("fuse_daemonize: setsid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
(void) chdir("/");
|
||||
|
||||
nullfd = open("/dev/null", O_RDWR, 0);
|
||||
if (nullfd != -1) {
|
||||
(void) dup2(nullfd, 0);
|
||||
(void) dup2(nullfd, 1);
|
||||
(void) dup2(nullfd, 2);
|
||||
if (nullfd > 2)
|
||||
close(nullfd);
|
||||
}
|
||||
|
||||
/* Propagate completion of daemon initializatation */
|
||||
completed = 1;
|
||||
write(waiter[1], &completed, sizeof(completed));
|
||||
close(waiter[0]);
|
||||
close(waiter[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ static
|
|||
void*
|
||||
_thread_loop(void *)
|
||||
{
|
||||
int count;
|
||||
u64 count;
|
||||
|
||||
pthread_setname_np(pthread_self(),"fuse.maint");
|
||||
|
||||
|
|
|
|||
60
vendored/libfuse/lib/xalloc.hpp
Normal file
60
vendored/libfuse/lib/xalloc.hpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define xstrdup(S) xstrdup_impl((S),__FILE__,__LINE__)
|
||||
#define xmalloc(S) xmalloc_impl((S),__FILE__,__LINE__)
|
||||
|
||||
static
|
||||
inline
|
||||
char*
|
||||
xstrdup_impl(const char *s_,
|
||||
const char *file_,
|
||||
const unsigned line_)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if(s_ == NULL)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"mergerfs: xstrdup called with NULL - file: %s; line: %u\n",
|
||||
file_,
|
||||
line_);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
p = strdup(s_);
|
||||
if(p == NULL)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"mergerfs: strdup failed - file: %s; line: %u\n",
|
||||
file_,
|
||||
line_);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static
|
||||
inline
|
||||
void*
|
||||
xmalloc_impl(const size_t size_,
|
||||
const char *file_,
|
||||
const unsigned line_)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = malloc(size_);
|
||||
if(p == NULL)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"mergerfs: malloc failed - file: %s; line: %u\n",
|
||||
file_,
|
||||
line_);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
|
@ -445,6 +445,7 @@ static int unmount_fuse_locked(const char *mnt, int quiet, int lazy)
|
|||
}
|
||||
|
||||
out:
|
||||
free(copy);
|
||||
if (res == -1)
|
||||
return -1;
|
||||
|
||||
|
|
@ -688,7 +689,7 @@ static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
|
|||
|
||||
if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
|
||||
return -1;
|
||||
strcat(*mnt_optsp, user);
|
||||
strncat(*mnt_optsp,user,strlen(user));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -992,7 +993,7 @@ static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd)
|
|||
return -1;
|
||||
}
|
||||
|
||||
sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
|
||||
snprintf(procfile,sizeof(procfile),"/proc/self/fd/%i",*mountpoint_fd);
|
||||
*mntp = procfile;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue