mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-26 19:01:56 -04:00
Auto-commit fuse.cpp
This commit is contained in:
parent
d5a2187713
commit
02da8efbff
37 changed files with 374 additions and 267 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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_);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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 :
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
51
vendored/libfuse/lib/xalloc.hpp
Normal file
51
vendored/libfuse/lib/xalloc.hpp
Normal 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue