Skip to content

fix(sandbox): retry a Retained unmount through the workspace record's token (#538) - #653

Open
mengmengmengqiang wants to merge 1 commit into
Ephemeral-AI-Lab:fix/538-custody-retryfrom
tokenaissance:fix/538-unmount-retry
Open

mengmengmengqiang wants to merge 1 commit into
Ephemeral-AI-Lab:fix/538-custody-retryfrom
tokenaissance:fix/538-unmount-retry

Conversation

@mengmengmengqiang

@mengmengmengqiang mengmengmengqiang commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

workspace.unmount re-sent a retryable Retained detach by calling
state.token(path), which re-runs unmount_guard::check and re-reports the
Retained custody before the retry reaches the daemon. A user who retried the
unmount after the holder exited kept getting the same Retained answer.

This branch reads the WorkspaceToken from the workspace record
(files::token_of, exactly as sandbox.close already does) instead, so a later
unmount actually re-attempts the recorded EBUSY detach once the holder is gone.

What it fixes

Files: control/crates/layerfs-sandbox/src/{files,unmount_guard,workspace/serve}.rs.

Stack

  1. fix(daemon): retry detach from Retained custody and add sandbox.destroy (#538) #640 fix/538-custody-retry @ 4020e9097 (base layerfs_v2_0_0 @ 03883a63c) — Retained custody and sandbox.destroy.
  2. this PR fix/538-unmount-retry @ 46109ee56 → base fix/538-custody-retry — the unmount path.
  3. fix/538-close-refuse @ 995627e09 → base fix/538-unmount-retry — the sandbox.close path.

Rebased onto the current base on 2026-11-12: layerfs_v2_0_0 moved from the
stack's fork point 833d04cf4 to 03883a63c (#639/#641/#621/#543/#547/#655).
No commits were squashed and authorship is unchanged.

Test evidence — Dell (aluminium), Linux x86_64, cargo 1.85.1

Rebased stack, verified at the stack head 995627e09 (Linux x86_64, 88 cores,
/dev/fuse present as crw-rw-rw-). Non-mount test binaries ran as the ordinary
user; the four Linux-only FUSE mount targets (the repo's own tools/ci_tests.py
mount lane) ran as root with /dev/fuse, under flock /tmp/dell-fuse.lock.
/dev/fuse was left at 666. Logs: /home/dell/538-538v2-*.log.

Gates (all exit 0):

Command Result
cargo +1.85.1 fmt --all -- --check exit 0
cargo +1.85.1 clippy --locked --workspace --exclude layerfs-node --all-targets -- -D warnings exit 0 — no exceptions
cargo +1.85.1 build --locked -p layerfs-daemon (mount-lane prerequisite) exit 0
cargo +1.85.1 test --locked -p layerfs-sandbox -p layerfs-control -p layerfs-api --no-run exit 0

Tests (cargo test -p layerfs-sandbox -p layerfs-control -p layerfs-api, each
built test binary run individually):

Package Binaries Passed Failed Ignored
layerfs-sandbox 9 27 0 0
layerfs-control 36 133 0 2
layerfs-api 58 137 0 2
total 103 297 0 4

FUSE mount targets run as root (12 tests, all pass): kernel_application 1,
kernel_mount_routes 2, observed_application 8, r5_1_actual_daemon_commit 1.

The 4 ignored tests are the repository's own #[ignore] fixtures, unchanged by
this branch: remote_store::minio_round_trip (needs MinIO),
store_family::a_killed_opener_leaves_its_log_frames,
doctor_sandbox::worker_fixture_server, store_doctor::worker_child.

Why the earlier CI on this PR was red

CI on the rebased head

ci run 43154286536,
attempt 3 (head 46109ee56): fmt and guards pass, clippy pass, test pass,
windows build (reports only) fail (pre-existing, non-gating). The first two
attempts failed on two different pre-existing concurrency tests —
layerfs-control::doctor_host::concurrent_management_record_rewrites_leave_consistency_incomplete
and layerfs-persistence::concurrent_first_installs::two_writers_saving_the_same_new_content_both_complete
(Err(Integrity("dependency cycle"))). Neither crate is touched by this stack;
both tests pass on Dell (full suite three times, plus 25 repeats pinned to four
CPUs with taskset -c 0-3).

NOT RUN

  • Whole-workspace suite (--workspace) — only the three packages named in
    the task were run.
  • layerfs-daemon package tests, including the Linux-only
    stalled_unmount mount target — outside the three requested packages; the
    daemon binary was built only as the mount-lane prerequisite.
  • Nightly/slow lane (tools/ci_tests.py nightly) — not requested.
  • macOS results are not evidence here: a local cargo check/fmt/clippy
    and one sandbox-package smoke run passed, reported as compile-only.

No merges; #538, #547 and #640 stay open.
Refs #538, #547, #640.

… token (Ephemeral-AI-Lab#538)

workspace.unmount re-sent a retryable Retained detach by calling
state.token(path), which re-runs unmount_guard::check and re-reports the
Retained custody before the retry reaches the daemon. Read the
WorkspaceToken from the workspace record (files::token_of, as
sandbox.close does) instead, so a later unmount actually re-attempts the
recorded EBUSY detach once the holder is gone.
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