FUSE: pass Branches::Ptr by value with empty-branches guards

Previously most FUSE ops took a reference to the live cfg.branches
object. With atomic_load now producing a shared_ptr snapshot, pass
it by value: the op works against a single stable view of the
configuration for its whole lifetime, immune to concurrent
reconfiguration.

Also bail out with -ENOENT when the policy returns an empty branch
set rather than dereferencing branches[0]. This was reachable if a
policy rejected every branch (e.g. everything readonly while
looking for a writable target).

Covers access, chmod, chown, create, getattr, getxattr, ioctl,
link, listxattr, mkdir, mknod, open, readdir (cor/cosr),
readlink, removexattr, rename, rmdir, setxattr, statfs, statx,
symlink, truncate, unlink, utimens.

While here, in _getattr only dereference st_->st_mode when lstat
succeeded (it is otherwise uninitialized).
This commit is contained in:
Antonio S. Musumeci 2026-04-18 00:56:15 -04:00 • committed by trapexit
parent 98648ae44b
commit 0c17492c78
25 changed files with 110 additions and 45 deletions

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
--------------
@ -308,7 +308,7 @@ _open_fd(const int fd_,
static
int
_open(const Policy::Search &searchFunc_,
const Branches &ibranches_,
const Branches::Ptr ibranches_,
const fs::path &fusepath_,
fuse_file_info_t *ffi_,
const bool link_cow_,
@ -321,6 +321,8 @@ _open(const Policy::Search &searchFunc_,
rv = searchFunc_(ibranches_,fusepath_,obranches);
if(rv < 0)
return rv;
if(obranches.empty())
return -ENOENT;
filepath = obranches[0]->path / fusepath_;