Skip to content

openvmm: don't resume beside a restorable staged snapshot - #1415

Merged
Pedro Henrique Penna (ppenna) merged 3 commits into
devfrom
agents/issue-1153-publication-cleanup
Nov 9, 2026
Merged

Pedro Henrique Penna (ppenna) merged 3 commits into
devfrom
agents/issue-1153-publication-cleanup

Conversation

@ppenna

@ppenna Pedro Henrique Penna (ppenna) commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1153

What and why

When a microVM capture fails before its commit point, the final rename of its
staging directory into place, OpenVMM rolls the capture back and resumes the
source VM, unless what the failure leaves makes resuming unsafe. A failed final
rename followed by a failed removal of the staging directory counted as safe
unless OpenVMM had tried to link the source's live RAM into that directory:
StagingDirectory::rollback (openvmm_helpers/src/snapshot/publish.rs) only
warned and returned SnapshotWriteError::BeforeCommit, on which the microVM
controller resumes the source. The staging directory of an independent memory
copy, which a capture with supplied RAM backing publishes, holds a complete
snapshot as soon as its manifest is written, though, so the source resumed
beside a snapshot that restore could open, and restoring it would start a
second copy of the VM (see Validation).

microsoft/openvmm#4993, openvmm_helpers: don't resume beside a restorable staged snapshot, resumes a failed publication's source only once nothing in
staging can be restored or aliases the source's RAM:

  • Restore cannot open a snapshot directory without manifest.bin, so the
    cleanup removes the staged manifest first, proves it absent, and on Linux
    flushes the staging directory, before it removes the rest.
  • The staging directory records that it may hold a manifest from just before
    the manifest is written, as it records a live RAM alias from just before it
    tries to link the source's RAM. A failed cleanup returns BeforeCommit, with
    a warning, only when neither may remain; otherwise it returns
    CleanupUncertain with the staging path, and the controller terminates the
    source.

#1153 left open whether a complete leftover must prevent the source's resume.
This takes its second option, invalidating the leftover so that it cannot be
restored, and falls back to the first, terminating the source, only when the
invalidation cannot be proved:

  • Both keep the single-running-instance guarantee: the source resumes only when
    nothing in staging can be restored or aliases its RAM.
  • Terminating on every failed cleanup would also stop a VM when nothing
    restorable remains: when the removal fails only after the manifest is gone,
    or when staging failed before it wrote the manifest, as when the filesystem
    turns read-only during the copy, which keeps resuming as before.
  • Removing the manifest first also means that a failed cleanup that terminates
    the source only for a live RAM alias leaves nothing that restore can open,
    closer to OpenVMM/microVM umbrella: snapshot publication, the manifest, block identity, and restore claims #1180's objective that a snapshot is restorable exactly when its
    publication committed.
  • It costs one file removal and one directory flush, on the failure path only.

The publication documentation and the rollback outcome now describe the same
guarantee: CleanupUncertain's message and the controller's log speak of
staging cleanup, not only of an automatic RAM alias, and OpenVMM's snapshot
guides and NVX's designs 5.3 (Snapshot Protocol) and 5.4 (Snapshot Artifact and
Attachment Model) say when a failed publication resumes the source. #1362, the
no-replace guarantee of the same final rename outside Linux glibc builds, is
unaffected: the new tests make the rename fail on a non-empty destination,
which every target refuses.

Commits:

  • openvmm: pin the removal of a failed publication's staged manifest moves
    the gitlink from d6addf8c1, the head of feature/microvm/dev, to
    ed8fc0713b4c6301d3b82ffe88817e70084d84b8, the head of
    [DO NOT REVIEW] openvmm_helpers: don't resume beside a restorable staged snapshot openvmm#4993, one commit on d6addf8c1. The protocol vectors and
    CPU profiles that nvx-rs copies are unchanged, and no NVX code reads the
    messages that the revision rewords.
  • doc: describe the staged manifest's removal on a failed capture says, in
    designs 5.3 and 5.4 and Figure 5.5, that the cleanup removes the manifest
    first, and when the source resumes or terminates.
  • doc: map the staged manifest's removal in the OpenVMM roadmap maps position
    229, unassigned, 98 commits past the mapped tip, with the mapped work that it
    changes: the staging cleanup and rollback of PR11's positions 032 and 033,
    and the controller and guide sentences of PR17's position 076. It conflicts
    with upstream main in all four of its files, so it follows PR11 and PR17
    upstream.

ed8fc0713 is patch-equivalent to 985336151, the same commit on
adb7c8bc8, which the reproduction below tested (identical range-diff).

OpenVMM's tests: three new tests in openvmm_helpers::snapshot::publish, and
no change to an existing test. This pull request changes no NVX test.

Landing order: land microsoft/openvmm#4993 first, by fast-forwarding
feature/microvm/dev to ed8fc0713b4c6301d3b82ffe88817e70084d84b8
(OpenVMM's merge button squashes, which would leave the pin off the branch);
then merge this pull request.

Validation

Reproduction, before and after:

Check Profile Backend Host type Before (adb7c8bc8) After (985336151) After the rebase (ed8fc0713)
uncertain_cleanup_of_complete_independent_staging_is_not_rollback_safe local workstation Windows - fails: BeforeCommit passes passes
uncertain_cleanup_of_complete_independent_staging_is_not_rollback_safe nvx-kvm-test Linux virtual machine fails: BeforeCommit passes passes
Cleanup that a read-only staging directory refuses for real (uncommitted test) nvx-kvm-test Linux virtual machine BeforeCommit, and read_snapshot opens the manifest, state, and memory left CleanupUncertain -
Removal refused only below a nested read-only directory (uncommitted test) nvx-kvm-test Linux virtual machine - BeforeCommit; restore cannot open the leftover, which has no manifest -

Snapshot scenarios, with OpenVMM built at the pin on each host
(python3 scripts/nvx.py test-microvm --backend BACKEND --scenario ... --processors 1 2):

Scenarios Profile Backend Host type At 985336151 At this head
scratch-snapshot, snapshot-core, snapshot-rollback, snapshot-tiers nvx-kvm-test kvm virtual machine pass pass
scratch-snapshot, snapshot-core, snapshot-rollback, snapshot-tiers nvx-mshv-test mshv virtual machine pass pass
scratch-snapshot, snapshot-core, snapshot-rollback, snapshot-tiers nvx-whp-test whp virtual machine pass pass
console-snapshot, sandbox-lifecycle, smp-snapshot nvx-kvm-test kvm virtual machine pass pass

The guest artifacts were those of release v0.1.0-dev.da327b5bf6d1 at
985336151 and of v0.1.0-dev.62b53254c1fa at this head. No VM run reaches the
double failure, a failed rename and a failed cleanup, without fault injection;
the scenarios check that captures, restores, and the rollback of a publication
that fails before staging are unchanged.

OpenVMM package checks for openvmm_helpers and openvmm_entry at
ed8fc0713: on Linux (Azure Linux 3.0, nvx-kvm-test), cargo clippy --all-targets -- -D warnings and cargo doc --no-deps with -D warnings
pass, and nextest passes 126 and 311 tests; on Windows, the same, 120 and 285;
openvmm_helpers for x86_64-unknown-linux-musl (nvx-mshv-test) passes 126;
cargo xtask fmt --fix passes.

Local gates (python scripts/local_gates.py --base origin/dev, Windows):
test-changes (no changes to existing tests), markdown-links, test-layout,
openvmm-vectors, and openvmm-cpu-profiles pass, and
python scripts/openvmm_pin.py check-branch --topic and check-roadmap --worktree pass; python scripts/rebase_check.py verify passed after the
rebase onto a386c22e4. nvx-cli: 2188 tests ran, with 3 errors, all subtests
of test_host_loopback_allow_script_checks_publication_and_traffic, whose
script times out in Git for Windows' sh on this workstation, alone too; this
branch changes no script, and the test passes in CI and on Linux.
test_adversarial passes 84 tests. openvmm-ci waits for OpenVMM's CI of the
pin, the run of microsoft/openvmm#4993.

Left to CI: the full microVM matrix, the other scenarios and processor counts,
benchmarks, and OpenVMM's CI of the pin.

Pins microsoft/openvmm#4993 at ed8fc0713b4c6301d3b82ffe88817e70084d84b8,
one commit on d6addf8c1, the head of feature/microvm/dev, which NVX
pinned before:

- ed8fc0713 openvmm_helpers: don't resume beside a restorable staged
  snapshot

When a capture's final rename failed and the removal of its staging
directory failed too, OpenVMM resumed the source unless it had tried to
link the source's live RAM into that directory. The staging directory
of an independent memory copy, which a capture with supplied RAM
backing publishes, holds a complete snapshot once its manifest is
written, though, so the source resumed beside a snapshot that restore
could open, and restoring it would start a second copy of the source.
The revision removes the staged manifest first and proves its removal,
which it flushes on Linux, resumes the source only once neither a
manifest nor a live RAM alias may remain in staging, and otherwise
terminates it with CleanupUncertain, which reports the staging
directory.

No coordinated change is needed: the vectors and CPU profiles that
nvx-rs copies match the pin's, and no NVX code reads the messages that
the revision rewords.

Evidence, with OpenVMM built from the pin and the guest artifacts of
release v0.1.0-dev.62b53254c1fa:

- At adb7c8bc8, the revision's regression test fails on Windows and on
  an Azure Linux 3 KVM test VM, where rollback reported BeforeCommit for
  a complete staging directory whose rename and removal failed. On that
  VM, a removal that a read-only staging directory refused for real also
  reported BeforeCommit, beside a leftover that read_snapshot opened.
- 985336151, the same commit on adb7c8bc8 (an identical range-diff),
  reports CleanupUncertain for that refusal instead.
- At this pin, openvmm_helpers' tests pass on Windows, on Linux with
  glibc, and for the musl target, and test-microvm's scratch-snapshot,
  snapshot-core, snapshot-rollback, and snapshot-tiers scenarios pass
  on KVM, MSHV, and WHP test VMs, as do console-snapshot,
  sandbox-lifecycle, and smp-snapshot on KVM.

Part of #1153

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The pinned OpenVMM removes a failed publication's staged manifest
first, without which restore cannot open what the rest of the cleanup
leaves, and resumes the source only once it has proved that removal,
which it flushes on Linux; otherwise, it terminates the source instead
of resuming it beside a staged snapshot that could start a second copy
of it.

Snapshot Artifact and Attachment Model said only that a failure before
the commit removes the staging directory, and Snapshot Protocol that
the source terminates when the VMM cannot remove the staging
directory's alias of guest RAM. Both now give the manifest's removal
and the guarantee that it provides, and Figure 5.5's cleanup removes
the manifest first.

Part of #1153

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Maps NVX's new pin, ed8fc0713, the head of microsoft/openvmm#4993, at
position 229, after position 228, d6addf8c1, the head of
feature/microvm/dev, which microsoft/openvmm#4992 merged. The pin is 98
commits past the mapped tip, and positions 132-229 stay unassigned.

Position 229 removes a failed publication's staged manifest before the
rest of its staging directory, and terminates the source rather than
resume it while that manifest, or a live RAM alias, may remain. It
changes mapped work: the cleanup and rollback of the staging directory
that PR11's positions 032 and 033 add, on whose outcome the controller
of PR17's position 076 resumes or terminates the source, and the
sentences on a failed publication that position 076 adds to the
snapshot and snapshot format guides. Replaying it on upstream main
conflicts in all four of its files, so it follows PR11 and PR17
upstream.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues were identified in the snapshot safety documentation and upstream roadmap updates.

No open issues 🎉

What changed in this PR

Aligns NVX’s snapshot documentation with the OpenVMM fix for #1153: a failed capture must not resume the source beside a restorable staged snapshot.

Changes:

  • Documents manifest-first cleanup and when cleanup uncertainty requires terminating the source instead of resuming it.
  • Updates the OpenVMM roadmap to pin ed8fc0713 at position 229 and records its upstream dependencies.
File Description
doc/​openvmm-upstream-roadmap.md Records the new pin, commit mapping, and dependencies on PR11 and PR17.
doc/​design/​5.4-snapshot-artifact-and-attachment-model.md Updates the publication diagram and explains manifest removal and rollback safety.
doc/​design/​5.3-snapshot-protocol.md Adds failed staged-manifest removal as a reason to terminate the source.

Review effort: Balanced

@ppenna
Pedro Henrique Penna (ppenna) added this pull request to the merge queue Nov 9, 2026
Merged via the queue into dev with commit 15fde8b Nov 9, 2026
48 checks passed
@ppenna
Pedro Henrique Penna (ppenna) deleted the agents/issue-1153-publication-cleanup branch November 9, 2026 13:19
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.

openvmm: failed publication cleanup can leave a restorable snapshot while the source resumes

2 participants