Skip to content

feat(fs): await_no_writers closes the inherited-descriptor ETXTBSY race (0.1.20) - #352

Merged
zackees merged 1 commit into
mainfrom
feat/fs-await-no-writers
Sep 25, 2026
Merged

zackees merged 1 commit into
mainfrom
feat/fs-await-no-writers

Conversation

@zackees

@zackees zackees commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Fixes the root cause of zackees/soldr#3350 at the platform owner; first link of the kernal-api -> zccache -> soldr -> setup-soldr cascade.

Mechanism

A child forked while a publisher's write descriptor is open inherits it until its own exec (O_CLOEXEC closes on exec, not fork). rename keeps the inode, so Linux refuses to execute the published file (ETXTBSY) for that child's fork-to-exec window even after the publisher closed its copy. zccache and soldr guard this with two separate process-wide locks, so any spawn in the embedded daemon that takes the other lock (or none) still leaks.

Fix

platform::fs::await_no_writers(path, timeout) -> WriterWait: waits until no process holds the file open for writing, whoever forked. Linux observes writers with a read lease (F_SETLEASE F_RDLCK is refused with EAGAIN under the same condition as exec's ETXTBSY); macOS and Windows report Unobservable (Windows children inherit only inheritable handles). Publishers call it after closing and before handing the file to anything that executes it.

Tests (RED -> GREEN)

platform_linux::fs_materialize::tests::a_descriptor_inherited_across_fork_is_waited_out forks a child that lingers before exec while the writer is open, closes the writer, asserts exec fails with ETXTBSY, then awaits writers and execs successfully.

  • RED (await reporting Clear immediately): exec after waiting: Os { code: 26, kind: ExecutableFileBusy, message: "Text file busy" }
  • GREEN: pass. Plus a host-neutral facade test in tests/fs/materialization.rs.

Local: fmt, clippy --all-features --all-targets -D warnings, fs + lib tests, Python compat. (current_executable_exposes_a_gnu_build_id fails locally on untouched main too; linker note settings.)

Version 0.1.19 -> 0.1.20 for the release zccache and soldr will pin.

🤖 Generated with Claude Code

…ce (0.1.20)

A child forked while a publisher's write descriptor is open keeps it
until its own exec, so Linux refuses to execute the published file
(ETXTBSY) even after the publisher closed its copy (zackees/soldr#3350).
await_no_writers waits until no process holds the file open for writing,
observed on Linux through a read lease; other hosts report Unobservable.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@zackees zackees added the ci-full Run the complete release-equivalent CI matrix on this PR SHA label Sep 25, 2026
@zackees
zackees merged commit bc32672 into main Sep 25, 2026
14 of 19 checks passed
@zackees
zackees deleted the feat/fs-await-no-writers branch September 26, 2026 00:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-full Run the complete release-equivalent CI matrix on this PR SHA

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant