mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-19 16:16:48 +00:00
FUSE: require valid file/dir handle; drop open_files fallback
Several FUSE ops fell back to looking up a FileInfo via state.open_files when the kernel-provided fh was zero, returning -ENOENT if the lookup failed. This path papered over handle-tracking bugs and added cost on every call. Use the handle directly and return -EBADF when it is invalid - the kernel should always hand us a valid fh for an open resource. Also simplify FileInfo::from_fh / DirInfo::from_fh and their to_fh helpers: callers now handle the null-pointer case explicitly so the ASSERT_NOT_NULL checks are redundant. Covers fallocate, fchmod, fchown, fgetattr, flock, ftruncate, futimens, read, release, releasedir, write, statx, ioctl (file + dir), readdir (sequential, concurrent-on-read, concurrent-on-search), and the passthrough fast paths in create/open.
This commit is contained in:
committed by
trapexit
parent
0dcca0f1a3
commit
98648ae44b
+10
-9
@@ -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_);
|
||||
}
|
||||
|
||||
+2
-10
@@ -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):
|
||||
|
||||
+3
-15
@@ -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_,
|
||||
|
||||
+3
-15
@@ -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_);
|
||||
}
|
||||
|
||||
+3
-15
@@ -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_);
|
||||
}
|
||||
|
||||
+3
-15
@@ -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) ?
|
||||
|
||||
+3
-15
@@ -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_);
|
||||
}
|
||||
|
||||
+3
-15
@@ -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_);
|
||||
}
|
||||
|
||||
+3
-15
@@ -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_);
|
||||
}
|
||||
|
||||
@@ -115,6 +115,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 +166,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(),
|
||||
|
||||
@@ -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,6 +84,9 @@ _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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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_);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user