diff --git a/src/branches.cpp b/src/branches.cpp index f2aed5dd..c6c22b2f 100644 --- a/src/branches.cpp +++ b/src/branches.cpp @@ -34,7 +34,7 @@ #include -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(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(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; diff --git a/src/branches.hpp b/src/branches.hpp index cf4c1d11..5320983c 100644 --- a/src/branches.hpp +++ b/src/branches.hpp @@ -39,13 +39,13 @@ public: public std::vector { private: - const u64 &_default_minfreespace; + u64 _default_minfreespace; public: using Ptr = std::shared_ptr; public: - Impl(const u64 &default_minfreespace); + Impl(u64 default_minfreespace); public: int from_string(const std::string_view str) final; diff --git a/src/config_log_file.cpp b/src/config_log_file.cpp index 65271990..f37c1f6d 100644 --- a/src/config_log_file.cpp +++ b/src/config_log_file.cpp @@ -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 diff --git a/src/dirinfo.hpp b/src/dirinfo.hpp index 972e07c8..2355b4a5 100644 --- a/src/dirinfo.hpp +++ b/src/dirinfo.hpp @@ -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(di_); +} + inline u64 DirInfo::to_fh() const { - ASSERT_NOT_NULL(this); - return reinterpret_cast(this); + return to_fh(this); } inline DirInfo* DirInfo::from_fh(const u64 fh_) { - DirInfo *rv; - - rv = reinterpret_cast(fh_); - - ASSERT_NOT_NULL(rv); - - return rv; + return reinterpret_cast(fh_); } diff --git a/src/fileinfo.hpp b/src/fileinfo.hpp index e905007a..6a2866f7 100644 --- a/src/fileinfo.hpp +++ b/src/fileinfo.hpp @@ -104,7 +104,6 @@ inline u64 FileInfo::to_fh(const FileInfo *fi_) { - ASSERT_NOT_NULL(fi_); return reinterpret_cast(fi_); } @@ -112,19 +111,12 @@ inline u64 FileInfo::to_fh() const { - ASSERT_NOT_NULL(this); - return reinterpret_cast(this); + return to_fh(this); } inline FileInfo* FileInfo::from_fh(const u64 fh_) { - FileInfo *rv; - - rv = reinterpret_cast(fh_); - - ASSERT_NOT_NULL(rv); - - return rv; + return reinterpret_cast(fh_); } diff --git a/src/fuse_create.cpp b/src/fuse_create.cpp index a05e6210..40cd0ea8 100644 --- a/src/fuse_create.cpp +++ b/src/fuse_create.cpp @@ -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): diff --git a/src/fuse_fallocate.cpp b/src/fuse_fallocate.cpp index abd4e90e..be11d40f 100644 --- a/src/fuse_fallocate.cpp +++ b/src/fuse_fallocate.cpp @@ -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_, diff --git a/src/fuse_fchmod.cpp b/src/fuse_fchmod.cpp index cc5b0c5b..f70996d0 100644 --- a/src/fuse_fchmod.cpp +++ b/src/fuse_fchmod.cpp @@ -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_); } diff --git a/src/fuse_fchown.cpp b/src/fuse_fchown.cpp index 91b799c9..e30ec9e0 100644 --- a/src/fuse_fchown.cpp +++ b/src/fuse_fchown.cpp @@ -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_); } diff --git a/src/fuse_fgetattr.cpp b/src/fuse_fgetattr.cpp index 94f20b11..4629bc0f 100644 --- a/src/fuse_fgetattr.cpp +++ b/src/fuse_fgetattr.cpp @@ -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) ? diff --git a/src/fuse_flock.cpp b/src/fuse_flock.cpp index 47b22f78..c2fde1e3 100644 --- a/src/fuse_flock.cpp +++ b/src/fuse_flock.cpp @@ -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_); } diff --git a/src/fuse_ftruncate.cpp b/src/fuse_ftruncate.cpp index cf967ca4..99aca0f5 100644 --- a/src/fuse_ftruncate.cpp +++ b/src/fuse_ftruncate.cpp @@ -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_); } diff --git a/src/fuse_futimens.cpp b/src/fuse_futimens.cpp index 2b4a2a21..e6b9e012 100644 --- a/src/fuse_futimens.cpp +++ b/src/fuse_futimens.cpp @@ -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_); } diff --git a/src/fuse_ioctl.cpp b/src/fuse_ioctl.cpp index 51ce85a6..f30e6b2e 100644 --- a/src/fuse_ioctl.cpp +++ b/src/fuse_ioctl.cpp @@ -32,6 +32,7 @@ #include "fs_open.hpp" #include "fs_path.hpp" #include "mergerfs_ioctl.hpp" +#include "state.hpp" #include "str.hpp" #include @@ -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(), diff --git a/src/fuse_open.cpp b/src/fuse_open.cpp index 251decab..fe6940bb 100644 --- a/src/fuse_open.cpp +++ b/src/fuse_open.cpp @@ -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)) { diff --git a/src/fuse_read.cpp b/src/fuse_read.cpp index 9847cfa6..3cd9ad35 100644 --- a/src/fuse_read.cpp +++ b/src/fuse_read.cpp @@ -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_); diff --git a/src/fuse_readdir.cpp b/src/fuse_readdir.cpp index 614927d9..d506d3d8 100644 --- a/src/fuse_readdir.cpp +++ b/src/fuse_readdir.cpp @@ -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; } diff --git a/src/fuse_readdir.hpp b/src/fuse_readdir.hpp index 8abf8820..afcff6da 100644 --- a/src/fuse_readdir.hpp +++ b/src/fuse_readdir.hpp @@ -22,6 +22,7 @@ #include "tofrom_string.hpp" #include "fuse_readdir_base.hpp" +#include #include #include @@ -58,7 +59,7 @@ namespace FUSE void initialize(); private: - bool _initialized = false; + std::atomic _initialized = false; std::shared_ptr _str; std::shared_ptr _impl; }; diff --git a/src/fuse_readdir_cor.cpp b/src/fuse_readdir_cor.cpp index e4f60eca..b0f5ba4a 100644 --- a/src/fuse_readdir_cor.cpp +++ b/src/fuse_readdir_cor.cpp @@ -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, diff --git a/src/fuse_readdir_cor_getdents.icpp b/src/fuse_readdir_cor_getdents.icpp index 03fb7941..3df46a5b 100644 --- a/src/fuse_readdir_cor_getdents.icpp +++ b/src/fuse_readdir_cor_getdents.icpp @@ -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_); diff --git a/src/fuse_readdir_cosr.cpp b/src/fuse_readdir_cosr.cpp index 4943061e..a916ba2e 100644 --- a/src/fuse_readdir_cosr.cpp +++ b/src/fuse_readdir_cosr.cpp @@ -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, diff --git a/src/fuse_readdir_cosr_getdents.icpp b/src/fuse_readdir_cosr_getdents.icpp index 93b0cc18..52a48adb 100644 --- a/src/fuse_readdir_cosr_getdents.icpp +++ b/src/fuse_readdir_cosr_getdents.icpp @@ -87,6 +87,8 @@ _readdir(std::vector> &dh_futures_, fuse_msgbuf_t *buf; buf = msgbuf_alloc(); + if(not buf) + return -ENOMEM; DEFER { msgbuf_free(buf); }; for(auto &dh_future : dh_futures_) diff --git a/src/fuse_readdir_seq.cpp b/src/fuse_readdir_seq.cpp index 11663d2d..3b8335d0 100644 --- a/src/fuse_readdir_seq.cpp +++ b/src/fuse_readdir_seq.cpp @@ -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_); diff --git a/src/fuse_readdir_seq_getdents.icpp b/src/fuse_readdir_seq_getdents.icpp index e190eccf..da99bb56 100644 --- a/src/fuse_readdir_seq_getdents.icpp +++ b/src/fuse_readdir_seq_getdents.icpp @@ -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_) diff --git a/src/fuse_readlink.cpp b/src/fuse_readlink.cpp index 7dd12933..dffa4350 100644 --- a/src/fuse_readlink.cpp +++ b/src/fuse_readlink.cpp @@ -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; } diff --git a/src/fuse_release.cpp b/src/fuse_release.cpp index c05f754c..17bbb0cd 100644 --- a/src/fuse_release.cpp +++ b/src/fuse_release.cpp @@ -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); diff --git a/src/fuse_releasedir.cpp b/src/fuse_releasedir.cpp index 7c755660..71226519 100644 --- a/src/fuse_releasedir.cpp +++ b/src/fuse_releasedir.cpp @@ -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); } diff --git a/src/fuse_statfs.cpp b/src/fuse_statfs.cpp index 68f0194d..3985f798 100644 --- a/src/fuse_statfs.cpp +++ b/src/fuse_statfs.cpp @@ -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_; diff --git a/src/fuse_statx_supported.icpp b/src/fuse_statx_supported.icpp index a49c75df..e16f792f 100644 --- a/src/fuse_statx_supported.icpp +++ b/src/fuse_statx_supported.icpp @@ -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 : diff --git a/src/fuse_write.cpp b/src/fuse_write.cpp index 08403ebd..4db6c397 100644 --- a/src/fuse_write.cpp +++ b/src/fuse_write.cpp @@ -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 diff --git a/vendored/libfuse/include/thread_pool.hpp b/vendored/libfuse/include/thread_pool.hpp index 4a2bffe4..d32061d5 100644 --- a/vendored/libfuse/include/thread_pool.hpp +++ b/vendored/libfuse/include/thread_pool.hpp @@ -180,14 +180,21 @@ ThreadPool::ThreadPool(const unsigned thread_count_, inline ThreadPool::~ThreadPool() { + std::vector 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); } diff --git a/vendored/libfuse/lib/debug.cpp b/vendored/libfuse/lib/debug.cpp index 57a48c2c..7dfd9027 100644 --- a/vendored/libfuse/lib/debug.cpp +++ b/vendored/libfuse/lib/debug.cpp @@ -63,7 +63,7 @@ _debug_set_output_stderr() auto new_log_file = std::shared_ptr(stderr,[](FILE*){}); fuse_cfg.log_file(new_log_file); - fuse_cfg.log_filepath("/dev/stderr"); + fuse_cfg.log_filepath(""); return 0; } diff --git a/vendored/libfuse/lib/fuse.cpp b/vendored/libfuse/lib/fuse.cpp index 79993680..76506451 100644 --- a/vendored/libfuse/lib/fuse.cpp +++ b/vendored/libfuse/lib/fuse.cpp @@ -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; diff --git a/vendored/libfuse/lib/fuse_loop.cpp b/vendored/libfuse/lib/fuse_loop.cpp index b2394a93..7194871b 100644 --- a/vendored/libfuse/lib/fuse_loop.cpp +++ b/vendored/libfuse/lib/fuse_loop.cpp @@ -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_) diff --git a/vendored/libfuse/lib/fuse_lowlevel.cpp b/vendored/libfuse/lib/fuse_lowlevel.cpp index 2e093ab8..de869daa 100644 --- a/vendored/libfuse/lib/fuse_lowlevel.cpp +++ b/vendored/libfuse/lib/fuse_lowlevel.cpp @@ -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); diff --git a/vendored/libfuse/lib/fuse_opt.cpp b/vendored/libfuse/lib/fuse_opt.cpp index 89bd9e80..1cf34b20 100644 --- a/vendored/libfuse/lib/fuse_opt.cpp +++ b/vendored/libfuse/lib/fuse_opt.cpp @@ -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(var) = copy; - } else { - if (sscanf(param, format, static_cast(var)) != 1) { - fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg); - return -1; } - } + else + { + if(sscanf(param, format, static_cast(var)) != 1) + { + fprintf(stderr,"mergerfs: invalid parameter in option `%s'\n",arg); + return -1; + } + } + return 0; } diff --git a/vendored/libfuse/lib/xalloc.hpp b/vendored/libfuse/lib/xalloc.hpp new file mode 100644 index 00000000..6219135d --- /dev/null +++ b/vendored/libfuse/lib/xalloc.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +#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; +}