diff --git a/src/fuse_copy_file_range.cpp b/src/fuse_copy_file_range.cpp index c186e046..e9cedf11 100644 --- a/src/fuse_copy_file_range.cpp +++ b/src/fuse_copy_file_range.cpp @@ -21,6 +21,7 @@ #include "errno.hpp" #include "fileinfo.hpp" #include "fs_copy_file_range.hpp" +#include "state.hpp" #include "fuse.h" @@ -57,11 +58,14 @@ FUSE::copy_file_range(const fuse_req_ctx_t *ctx_, const size_t size_, const unsigned int flags_) { - FileInfo *src_fi = FileInfo::from_fh(src_ffi_->fh); - FileInfo *dst_fi = FileInfo::from_fh(dst_ffi_->fh); + FileInfo *src_fi; + FileInfo *dst_fi; + src_fi = state.get_fi(ctx_,src_ffi_->fh); if(not src_fi) return -EBADF; + + dst_fi = state.get_fi(ctx_,dst_ffi_->fh); if(not dst_fi) return -EBADF; diff --git a/src/fuse_fallocate.cpp b/src/fuse_fallocate.cpp index be11d40f..4eb964ab 100644 --- a/src/fuse_fallocate.cpp +++ b/src/fuse_fallocate.cpp @@ -41,6 +41,13 @@ _fallocate(const int fd_, return rv; } +// In cases where the node was opened but unlinked there will be no +// path and no guarentee of a `fh`. It could always do the lookup but +// why bother if the kernel has provided it to us? The reason the +// function doesn't need to run within the visit lambda is because +// since the request is outstanding the kernel won't be releasing the +// node and therefore the entry will be valid over the lifetime of +// this function. int FUSE::fallocate(const fuse_req_ctx_t *ctx_, cu64 fh_, @@ -48,8 +55,9 @@ FUSE::fallocate(const fuse_req_ctx_t *ctx_, off_t offset_, off_t len_) { - FileInfo *fi = FileInfo::from_fh(fh_); + FileInfo *fi; + fi = state.get_fi(ctx_,fh_); if(not fi) return -EBADF; diff --git a/src/fuse_fchmod.cpp b/src/fuse_fchmod.cpp index f70996d0..389d2c1e 100644 --- a/src/fuse_fchmod.cpp +++ b/src/fuse_fchmod.cpp @@ -38,13 +38,21 @@ _fchmod(const int fd_, return rv; } +// In cases where the node was opened but unlinked there will be no +// path and no guarentee of a `fh`. It could always do the lookup but +// why bother if the kernel has provided it to us? The reason the +// function doesn't need to run within the visit lambda is because +// since the request is outstanding the kernel won't be releasing the +// node and therefore the entry will be valid over the lifetime of +// this function. int FUSE::fchmod(const fuse_req_ctx_t *ctx_, cu64 fh_, const mode_t mode_) { - FileInfo *fi = FileInfo::from_fh(fh_); + FileInfo *fi; + fi = state.get_fi(ctx_,fh_); if(not fi) return -EBADF; diff --git a/src/fuse_fchown.cpp b/src/fuse_fchown.cpp index e30ec9e0..4a9e320e 100644 --- a/src/fuse_fchown.cpp +++ b/src/fuse_fchown.cpp @@ -41,14 +41,22 @@ _fchown(const int fd_, return rv; } +// In cases where the node was opened but unlinked there will be no +// path and no guarentee of a `fh`. It could always do the lookup but +// why bother if the kernel has provided it to us? The reason the +// function doesn't need to run within the visit lambda is because +// since the request is outstanding the kernel won't be releasing the +// node and therefore the entry will be valid over the lifetime of +// this function. int FUSE::fchown(const fuse_req_ctx_t *ctx_, cu64 fh_, const uid_t uid_, const gid_t gid_) { - FileInfo *fi = FileInfo::from_fh(fh_); + FileInfo *fi; + fi = state.get_fi(ctx_,fh_); if(not fi) return -EBADF; diff --git a/src/fuse_fgetattr.cpp b/src/fuse_fgetattr.cpp index 4629bc0f..457b0c4c 100644 --- a/src/fuse_fgetattr.cpp +++ b/src/fuse_fgetattr.cpp @@ -46,7 +46,13 @@ _fgetattr(const FileInfo *fi_, return rv; } - +// In cases where the node was opened but unlinked there will be no +// path and no guarentee of a `fh`. It could always do the lookup but +// why bother if the kernel has provided it to us? The reason the +// function doesn't need to run within the visit lambda is because +// since the request is outstanding the kernel won't be releasing the +// node and therefore the entry will be valid over the lifetime of +// this function. int FUSE::fgetattr(const fuse_req_ctx_t *ctx_, cu64 fh_, @@ -54,13 +60,11 @@ FUSE::fgetattr(const fuse_req_ctx_t *ctx_, fuse_timeouts_t *timeout_) { int rv; - FileInfo *fi = FileInfo::from_fh(fh_); + FileInfo *fi; + fi = state.get_fi(ctx_,fh_); if(not fi) - { - timeout_->entry = cfg.cache_negative_entry; - return -EBADF; - } + return -EBADF; rv = ::_fgetattr(fi,st_); diff --git a/src/fuse_flock.cpp b/src/fuse_flock.cpp index c2fde1e3..c6f32e39 100644 --- a/src/fuse_flock.cpp +++ b/src/fuse_flock.cpp @@ -38,13 +38,21 @@ _flock(const int fd_, return rv; } +// In cases where the node was opened but unlinked there will be no +// path and no guarentee of a `fh`. It could always do the lookup but +// why bother if the kernel has provided it to us? The reason the +// function doesn't need to run within the visit lambda is because +// since the request is outstanding the kernel won't be releasing the +// node and therefore the entry will be valid over the lifetime of +// this function. int FUSE::flock(const fuse_req_ctx_t *ctx_, const fuse_file_info_t *ffi_, int op_) { - FileInfo* fi = FileInfo::from_fh(ffi_->fh); + FileInfo *fi; + fi = state.get_fi(ctx_,ffi_->fh); if(not fi) return -EBADF; diff --git a/src/fuse_flush.cpp b/src/fuse_flush.cpp index 666c8fb3..b2658995 100644 --- a/src/fuse_flush.cpp +++ b/src/fuse_flush.cpp @@ -22,6 +22,7 @@ #include "fileinfo.hpp" #include "fs_close.hpp" #include "fs_dup.hpp" +#include "state.hpp" #include "fuse.h" @@ -39,12 +40,20 @@ _flush(const int fd_) return fs::close(rv); } +// In cases where the node was opened but unlinked there will be no +// path and no guarentee of a `fh`. It could always do the lookup but +// why bother if the kernel has provided it to us? The reason the +// function doesn't need to run within the visit lambda is because +// since the request is outstanding the kernel won't be releasing the +// node and therefore the entry will be valid over the lifetime of +// this function. int FUSE::flush(const fuse_req_ctx_t *ctx_, const fuse_file_info_t *ffi_) { - FileInfo *fi = FileInfo::from_fh(ffi_->fh); + FileInfo *fi; + fi = state.get_fi(ctx_,ffi_->fh); if(not fi) return -EBADF; diff --git a/src/fuse_fsync.cpp b/src/fuse_fsync.cpp index 8ae48331..d0b700fe 100644 --- a/src/fuse_fsync.cpp +++ b/src/fuse_fsync.cpp @@ -22,6 +22,7 @@ #include "fileinfo.hpp" #include "fs_fdatasync.hpp" #include "fs_fsync.hpp" +#include "state.hpp" #include "to_neg_errno.hpp" #include "fuse.h" @@ -44,13 +45,21 @@ _fsync(const int fd_, return ::to_neg_errno(rv); } +// In cases where the node was opened but unlinked there will be no +// path and no guarentee of a `fh`. It could always do the lookup but +// why bother if the kernel has provided it to us? The reason the +// function doesn't need to run within the visit lambda is because +// since the request is outstanding the kernel won't be releasing the +// node and therefore the entry will be valid over the lifetime of +// this function. int FUSE::fsync(const fuse_req_ctx_t *ctx_, - cu64 fh_, - int isdatasync_) + cu64 fh_, + int isdatasync_) { - FileInfo *fi = FileInfo::from_fh(fh_); + FileInfo *fi; + fi = state.get_fi(ctx_,fh_); if(not fi) return -EBADF; diff --git a/src/fuse_ftruncate.cpp b/src/fuse_ftruncate.cpp index 99aca0f5..3f1cfdfd 100644 --- a/src/fuse_ftruncate.cpp +++ b/src/fuse_ftruncate.cpp @@ -38,13 +38,21 @@ _ftruncate(const int fd_, return rv; } +// In cases where the node was opened but unlinked there will be no +// path and no guarentee of a `fh`. It could always do the lookup but +// why bother if the kernel has provided it to us? The reason the +// function doesn't need to run within the visit lambda is because +// since the request is outstanding the kernel won't be releasing the +// node and therefore the entry will be valid over the lifetime of +// this function. int FUSE::ftruncate(const fuse_req_ctx_t *ctx_, cu64 fh_, off_t size_) { - FileInfo *fi = FileInfo::from_fh(fh_); + FileInfo *fi; + fi = state.get_fi(ctx_,fh_); if(not fi) return -EBADF; diff --git a/src/fuse_futimens.cpp b/src/fuse_futimens.cpp index e6b9e012..4dcec896 100644 --- a/src/fuse_futimens.cpp +++ b/src/fuse_futimens.cpp @@ -40,13 +40,21 @@ _futimens(const int fd_, return rv; } +// In cases where the node was opened but unlinked there will be no +// path and no guarentee of a `fh`. It could always do the lookup but +// why bother if the kernel has provided it to us? The reason the +// function doesn't need to run within the visit lambda is because +// since the request is outstanding the kernel won't be releasing the +// node and therefore the entry will be valid over the lifetime of +// this function. int FUSE::futimens(const fuse_req_ctx_t *ctx_, cu64 fh_, const struct timespec ts_[2]) { - FileInfo *fi = FileInfo::from_fh(fh_); + FileInfo *fi; + fi = state.get_fi(ctx_,fh_); if(not fi) return -EBADF; diff --git a/src/fuse_ioctl.cpp b/src/fuse_ioctl.cpp index eecf5ac2..bd0a0259 100644 --- a/src/fuse_ioctl.cpp +++ b/src/fuse_ioctl.cpp @@ -114,8 +114,9 @@ _ioctl_file(const fuse_req_ctx_t *ctx_, void *data_, u32 *out_bufsz_) { - FileInfo *fi = FileInfo::from_fh(ffi_->fh); + FileInfo *fi; + fi = state.get_fi(ctx_,ffi_->fh); if(not fi) return -EBADF; diff --git a/src/fuse_read.cpp b/src/fuse_read.cpp index 3cd9ad35..57c9daae 100644 --- a/src/fuse_read.cpp +++ b/src/fuse_read.cpp @@ -22,6 +22,7 @@ #include "fileinfo.hpp" #include "fs_pread.hpp" #include "ioprio.hpp" +#include "state.hpp" #include "fuse.h" @@ -65,8 +66,9 @@ FUSE::read(const fuse_req_ctx_t *ctx_, off_t offset_) { ioprio::SetFrom iop(ctx_->pid); - FileInfo *fi = FileInfo::from_fh(ffi_->fh); + FileInfo *fi; + fi = state.get_fi(ctx_,ffi_->fh); if(not fi) return -EBADF; diff --git a/src/fuse_statx_supported.icpp b/src/fuse_statx_supported.icpp index 84a81018..5ec930a8 100644 --- a/src/fuse_statx_supported.icpp +++ b/src/fuse_statx_supported.icpp @@ -263,8 +263,9 @@ FUSE::statx_fh(const fuse_req_ctx_t *ctx_, fuse_timeouts_t *timeout_) { int rv; - FileInfo *fi = FileInfo::from_fh(fh_); + FileInfo *fi; + fi = state.get_fi(ctx_,fh_); if(not fi) return -EBADF; diff --git a/src/fuse_write.cpp b/src/fuse_write.cpp index 4db6c397..3bdcb0e0 100644 --- a/src/fuse_write.cpp +++ b/src/fuse_write.cpp @@ -27,6 +27,7 @@ #include "fs_pwrite.hpp" #include "fs_pwriten.hpp" #include "ioprio.hpp" +#include "state.hpp" #include "scope_guard/scope_guard.hpp" @@ -160,14 +161,15 @@ _write_cached(const char *buf_, static int -_write(const fuse_file_info_t *ffi_, +_write(const fuse_req_ctx_t *ctx_, + const fuse_file_info_t *ffi_, const char *buf_, const size_t count_, const off_t offset_) { FileInfo *fi; - fi = FileInfo::from_fh(ffi_->fh); + fi = state.get_fi(ctx_,ffi_->fh); if(not fi) return -EBADF; @@ -180,8 +182,7 @@ _write(const fuse_file_info_t *ffi_, // could change the move file behavior to use a known target file // and have threads use O_EXCL and back off and wait for the // transfer to complete before retrying. - mutex_lock(fi->mutex); - DEFER { mutex_unlock(fi->mutex); }; + mutex_lockguard(fi->mutex); if(fi->direct_io) return ::_write_direct_io(buf_,count_,offset_,fi); @@ -198,7 +199,7 @@ FUSE::write(const fuse_req_ctx_t *ctx_, { ioprio::SetFrom iop(ctx_->pid); - return ::_write(ffi_,buf_,count_,offset_); + return ::_write(ctx_,ffi_,buf_,count_,offset_); } int diff --git a/src/state.hpp b/src/state.hpp index b7905a51..f5e5867c 100644 --- a/src/state.hpp +++ b/src/state.hpp @@ -115,6 +115,24 @@ public: FileInfo *fi; }; +public: + FileInfo* + get_fi(const fuse_req_ctx_t *ctx_, + cu64 fh_) const + { + FileInfo *fi; + + fi = FileInfo::from_fh(fh_); + if(not fi) + open_files.cvisit(ctx_->nodeid, + [&](auto &v_) + { + fi = v_.second.fi; + }); + + return fi; + } + public: struct GetSet { diff --git a/vendored/libfuse/lib/fuse.cpp b/vendored/libfuse/lib/fuse.cpp index 2596391c..2b9bd19d 100644 --- a/vendored/libfuse/lib/fuse.cpp +++ b/vendored/libfuse/lib/fuse.cpp @@ -1498,10 +1498,8 @@ fuse_lib_getattr(fuse_req_t *req_, { if(fusepath != NULL) err = f.ops.getattr(&req_->ctx,&fusepath[1],&buf,&timeouts); - else if(fh != 0) - err = f.ops.fgetattr(&req_->ctx,fh,&buf,&timeouts); else - err = -ENOENT; + err = f.ops.fgetattr(&req_->ctx,fh,&buf,&timeouts); free_path(hdr_->nodeid,fusepath); } @@ -1538,20 +1536,29 @@ fuse_lib_statx_path(fuse_req_t *req_, struct fuse_statx st{}; fuse_timeouts_t timeouts{}; - // TODO: if node unlinked... but FUSE may not send it err = get_path(hdr_->nodeid,&fusepath); + if(err == -ESTALE) + err = 0; if(err) { fuse_reply_err(req_,err); return; } - err = f.ops.statx(&req_->ctx, - &fusepath[1], - inarg_->sx_flags, - inarg_->sx_mask, - &st, - &timeouts); + if(fusepath != NULL) + err = f.ops.statx(&req_->ctx, + &fusepath[1], + inarg_->sx_flags, + inarg_->sx_mask, + &st, + &timeouts); + else + err = f.ops.statx_fh(&req_->ctx, + 0, + inarg_->sx_flags, + inarg_->sx_mask, + &st, + &timeouts); free_path(hdr_->nodeid,fusepath);