Repository navigation
pool: settle a capture interrupted by sandboxd's death - #447
Merged
Merged
Conversation
A crash during a capture left the guest paused with its record running, and exec returned 502 until someone ran vm start. Reconcile now keeps the intent, holds the claim, waits for the capture's CLI to exit, then acts on what is there. A listed hibernate snapshot is the guest as it last ran, so it is adopted and woken with vm restore. Otherwise vm start resumes the guest, with retries because it fails during a dump, and a silkd probe confirms it. vm start must not run while the CLI lives: it waits on cocoon's ops lock and can then cold-boot a guest whose VMM the hibernate has stopped. A snapshot save now journals an intent too, one claims.json commit per capture, never on the warm claim path. A failed hibernate or save settles the same way, which closes #442. Reconcile's orphan sweeps moved to helpers to stay under the complexity limit.
…resumes first A failed hibernate or save now returns its error immediately and resumes the guest in the background through the restart path, so the API no longer waits up to 30 minutes on a dump that is still being written. Only calls to that sandbox wait for the resume, as they would otherwise get 502. A wake or hibernate that found an intent still went through the old resolver, which cleared an unlisted hibernate intent without resuming the guest. After a settle that gave up, the next exec left the guest paused with nothing left to recover it. Every dangling intent now goes through settleCapture. State is read with vm list instead of vm inspect, which blocks on the VMM API while a dump runs.
This was referenced Nov 5, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
If sandboxd died during a capture, the guest could stay paused until someone ran
vm start, or lose its memory to a cold boot. The next start now waits for the capture's CLI to exit and settles the claim from what the capture left behind. A failed hibernate or save answers at once and settles the same way in the background.Closes #446. Closes #442.
Needs cocoon with cocoonstack/cocoon#306, now merged as
2f7252fabut not yet released, which removes the state where a VMM stays alive with no guest. The hardware below ran on that tree.What happens now
The settle keeps the intent and holds the claim's transition, so calls to that sandbox wait while other claims are unaffected. Once no process carries the snapshot name as an argument, it reads
vm listandsnapshot list(no VMM API call, so a running dump cannot stall it):runningvm stop --force, adopt as hibernated, wake withvm restorerunningvm start, then a silkd probe; the claim is marked failed after 30 minutesstoppedorerrorvm restore; nevervm startstoppedTwo rules hold this together:
vm startwaits on cocoon's ops lock, then cold-boots a guest whose VMM the hibernate stopped, and still returns 0.The intent stays until the guest is safe. If
vm stopfails, the settle gives up, or sandboxd stops during the retries, the next wake or start finishes the work: every dangling intent goes through the same settle, and a wake never clears one without resuming the guest.snapshot savenow journals an intent too; a save cut short could not be seen after a restart.Hardware
Bare metal, cocoon
2f7252fa, a 4 GiB guest with 3.5 GiB dirtied in/dev/shm. Every row checked the boot id, the PID of a running process and a marker hash, so a cold boot cannot pass.Paused, snapshot swept,vm startby handvm restore, intact; survives a second SIGKILL before the wakevm startby handvm startvm startby handvm startduring the holdvm restore, intactvm startby handvm startby handvm start, intactvm start, 200, intact; a later restart is quietvm startnever succeedsSuccessful captures leave no intent on disk, and later restarts run no settle.
sandboxd-e2e.shandarchive-e2e.shpass, and a clean stop still waits for the capture (about 2 s, and 26 s with a held capture).Cost
Measured on bare metal NVMe, both arms pinned to one NUMA node, ABBA over 4 rounds, with an A/A control.
claims.jsoncommits.sync_claimsoff / onAgainst a real 4 GiB
snapshot saveof about 3.4 s, that is 0.02% to 0.25%.Not covered
watch, holds the claim until it exits. The warning names the snapshot.Tests and gates
Unit tests cover every row. Mutations of the decision logic each fail a test, among them not waiting for the CLI, answering only after the resume, swallowing a failed stop, starting a stopped VM, stopping a stopped one, skipping the probe, adopting a save's snapshot, and a wake clearing an intent through the old resolver.
make go-lint: 100 issues.lines, 5 modules on linux and darwin, with a cold cache (a warm one panics staticcheck's SA4023).make go-test: 29 packages ok.aslon all five modules, linux and darwin: no findings.WaitCapturetest passes in a Linux container; it skips on macOS, which has no/proc.Production +248 −28, of which about 40 lines are
Reconcile's orphan sweeps moved to helpers to stay under the complexity limit. Tests +536 −22. Go comment lines +2 −2.