Use atomic open file reference counts

- Use relaxed increment under the map bucket lock when duplicating file handles.
- Use acq_rel decrement when releasing and checking for final references.
- Load moved ref_count with relaxed ordering during map insertion.
This commit is contained in:
Antonio SJ Musumeci
2026-05-14 00:22:06 -04:00
committed by trapexit
parent b13727abde
commit 608cd00764
3 changed files with 27 additions and 4 deletions
+10 -1
View File
@@ -367,10 +367,19 @@ _open(const fuse_req_ctx_t *ctx_,
// The ref increment keeps fuse_release.cpp from erasing and
// freeing the canonical entry while we duplicate its fd.
//
// memory_order_relaxed is sufficient for the increment. The
// concurrent_flat_map bucket lock held inside visit() already
// provides the happens-before relationship with other mutators
// of the same key (the release() erase_if() callback and other
// open() visitors.) The lock's release/acquire semantics
// publish the ref_count update to subsequent observers of the
// same entry, so we only need atomicity from the fetch_add
// itself.
of.visit(ctx_->nodeid,
[&](auto &v_)
{
v_.second.ref_count++;
v_.second.ref_count.fetch_add(1,std::memory_order_relaxed);
fi = v_.second.fi;
backing_id = v_.second.backing_id;
});
+12 -2
View File
@@ -81,11 +81,21 @@ FUSE::release(cu64 nodeid_,
FileInfo *canonical_fi = nullptr;
FileInfo *fh_fi_to_free = nullptr;
// memory_order_acq_rel on the decrement gives us the canonical
// refcount-publication pattern:
// - release: prior writes to the OpenFile by this thread are
// visible to whichever thread observes the final 0.
// - acquire: the thread that drops the last ref acquires every
// prior ref holder's writes before tearing down the entry.
// The concurrent_flat_map bucket lock already serializes concurrent
// visitors of this key so the acq_rel is good for any observer that
// might examine ref_count outside a visit().
of.erase_if(nodeid_,
[&](auto &v_)
{
v_.second.ref_count--;
if(v_.second.ref_count > 0)
const int prev =
v_.second.ref_count.fetch_sub(1,std::memory_order_acq_rel);
if(prev > 1)
{
if(fi_ != v_.second.fi)
fh_fi_to_free = fi_;
+5 -1
View File
@@ -103,8 +103,12 @@ public:
{
}
// Move constructor runs during initial insertion into the
// concurrent_flat_map before the new entry is reachable by the
// other threads. There is no concurrent observer of the moved
// value at this point so relaxed load is sufficient.
OpenFile(OpenFile &&o_) noexcept
: ref_count(o_.ref_count.load()),
: ref_count(o_.ref_count.load(std::memory_order_relaxed)),
backing_id(o_.backing_id),
fi(o_.fi)
{