Skip to content

fix: gate read/write fd-cache fast paths on is_stale() (issue #30)#35

Merged
congwang-mk merged 1 commit into
mainfrom
fix/issue-30-fd-cache-staleness
May 23, 2026
Merged

fix: gate read/write fd-cache fast paths on is_stale() (issue #30)#35
congwang-mk merged 1 commit into
mainfrom
fix/issue-30-fd-cache-staleness

Conversation

@congwang-mk
Copy link
Copy Markdown
Contributor

@congwang-mk congwang-mk commented May 23, 2026

Summary

  • The read and write fd-cache fast paths served a cached descriptor without consulting is_stale() — the only 2 of 20 callbacks that didn't. A commit or abort from another mount could leave a held-open fd reading or writing a replaced/deleted backing file (issue High: stale/epoch protection is bypassed by file descriptor caches #30).
  • Call is_stale() at the top of both fast paths so they return ESTALE consistently with the rest of the filesystem, while still skipping the resolve()/File::open() the cache exists to avoid.
  • is_stale() covers both failure modes: a foreign commit (epoch arm) and a foreign abort (branch-removal arm — abort signals through is_branch_valid(), not the epoch, so no epoch bump was needed).

Tests

  • Added fs::tests unit tests proving is_stale() is true after a foreign commit and after a foreign abort, and false when in sync.
  • No functional regression test: under TTL=0, getattr/lookup already ESTALE before read() is reached, so the read fast-path window is masked in normal operation. Verified the held-open-fd scenario returns ESTALE on both pre- and post-fix binaries, confirming the mask. This change is therefore defense-in-depth — it removes the lone inconsistency and stays correct if a read ever reaches the daemon without a preceding getattr (read-ahead, future caching/TTL changes).

Test Plan

  • cargo test --lib — 14 pass

🤖 Generated with Claude Code

The fd-cache fast paths served a cached descriptor without consulting
staleness, while every other callback returns ESTALE on is_stale(). A
foreign commit (epoch arm) or abort (is_branch_valid arm) could thus leave
a held-open fd reading/writing a replaced or deleted backing file.

Call is_stale() at the top of both fast paths so they ESTALE consistently
with the rest of the filesystem. This still skips the resolve()/File::open()
the cache exists to avoid.

Signed-off-by: Cong Wang <cwang@multikernel.io>
@congwang-mk congwang-mk merged commit a4b6592 into main May 23, 2026
4 checks passed
@congwang-mk congwang-mk deleted the fix/issue-30-fd-cache-staleness branch May 23, 2026 04:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant