Auto-commit fuse.cpp

This commit is contained in:
Antonio SJ Musumeci 2026-04-13 18:55:56 -05:00
parent d5a2187713
commit 02da8efbff
37 changed files with 374 additions and 267 deletions

View file

@ -34,7 +34,7 @@
#include <fnmatch.h>
Branches::Impl::Impl(const u64 &default_minfreespace_)
Branches::Impl::Impl(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;
}
@ -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:
@ -440,7 +452,9 @@ Branches::to_string(void) const
void
Branches::find_and_set_mode_ro()
{
for(auto &branch : *_impl)
auto impl = std::atomic_load(&_impl);
for(auto &branch : *impl)
{
if(branch.mode != Branch::Mode::RW)
continue;

View file

@ -39,13 +39,13 @@ public:
public std::vector<Branch>
{
private:
const u64 &_default_minfreespace;
u64 _default_minfreespace;
public:
using Ptr = std::shared_ptr<Impl>;
public:
Impl(const u64 &default_minfreespace);
Impl(u64 default_minfreespace);
public:
int from_string(const std::string_view str) final;

View file

@ -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

View file

@ -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_);
}

View file

@ -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_);
}

View file

@ -292,6 +292,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):

View file

@ -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_,

View file

@ -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_);
}

View file

@ -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_);
}

View file

@ -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) ?

View file

@ -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_);
}

View file

@ -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_);
}

View file

@ -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_);
}

View file

@ -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_);
}
@ -163,6 +167,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(),

View file

@ -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
--------------
@ -423,6 +423,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))
{

View file

@ -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_);

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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,

View file

@ -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_);

View file

@ -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,

View file

@ -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_)

View file

@ -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_);

View file

@ -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_)

View file

@ -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;
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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_;

View file

@ -253,27 +253,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 :

View file

@ -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

View file

@ -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);
}

View file

@ -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;
}

View file

@ -18,6 +18,7 @@
#include "kvec.h"
#include "mutex.hpp"
#include "node.hpp"
#include "xalloc.hpp"
#include "fuse_cfg.hpp"
#include "fuse_req.hpp"
@ -290,10 +291,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;
}
@ -542,8 +544,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 +643,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 +679,8 @@ find_node(uint64_t parent,
remove_remembered_node(node);
}
inc_nlookup(node);
out_err:
mutex_unlock(f.lock);
return node;
}
@ -723,8 +738,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 +812,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 +899,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 +1128,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 +1171,6 @@ forget_node(const uint64_t nodeid,
kv_push(remembered_node_t,f.remembered_nodes,fn);
}
mutex_unlock(f.lock);
}
static
@ -1353,29 +1380,34 @@ fuse_lib_lookup(fuse_req_t *req_,
if(name[1] == '\0')
{
name = NULL;
mutex_lock(f.lock);
mutex_lockguard(f.lock);
dot = get_node_nocheck(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;
}
}
}
@ -2187,6 +2219,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,
@ -2264,7 +2301,12 @@ get_dirhandle(const fuse_file_info_t *llfi,
{
struct fuse_dh *dh = (struct fuse_dh *)(uintptr_t)llfi->fh;
memset(fi,0,sizeof(fuse_file_info_t));
if(dh == NULL)
return NULL;
fi->fh = dh->fh;
return dh;
}
@ -2283,7 +2325,7 @@ 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);
@ -2372,7 +2414,13 @@ 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;
}
d = &dh->d;
mutex_lock(dh->lock);
@ -2416,7 +2464,13 @@ 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;
}
d = &dh->d;
mutex_lock(dh->lock);
@ -2457,6 +2511,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);
@ -2485,7 +2544,11 @@ fuse_lib_fsyncdir(fuse_req_t *req_,
is_datasync = !!(arg->fsync_flags & FUSE_FSYNC_FDATASYNC);
llffi.fh = arg->fh;
get_dirhandle(&llffi,&ffi);
if(not get_dirhandle(&llffi,&ffi))
{
fuse_reply_err(req_,EBADF);
return;
}
err = f.ops.fsyncdir(&req_->ctx,
&ffi,
@ -3008,9 +3071,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 +3200,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 *no = 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 +3228,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);
@ -3231,13 +3312,12 @@ fuse_lib_ioctl(fuse_req_t *req_,
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 +3328,26 @@ 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);
{
if(not get_dirhandle(&llffi,&ffi))
{
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 +3355,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
@ -3606,7 +3697,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))
@ -3750,11 +3844,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;

View file

@ -86,6 +86,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 +146,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 +176,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_)

View file

@ -538,12 +538,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 +603,7 @@ fuse_reply_ioctl_retry(fuse_req_t *req,
}
res = send_reply_iov(req, 0, iov, count);
out:
free(in_fiov);
free(out_fiov);

View file

@ -214,23 +214,32 @@ 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
{
if(sscanf(param, format, static_cast<int*>(var)) != 1)
{
fprintf(stderr,"mergerfs: invalid parameter in option `%s'\n",arg);
return -1;
}
}
return 0;
}

View file

@ -0,0 +1,51 @@
#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;
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;
}