Skip to content

[DO NOT REVIEW] openvmm_helpers: don't resume beside a restorable staged snapshot - #4993

Merged
Pedro Henrique Penna (ppenna) merged 1 commit into
feature/microvm/devfrom
copilot/nvx-issue-1153-publication-cleanup
Nov 9, 2026
Merged

Pedro Henrique Penna (ppenna) merged 1 commit into
feature/microvm/devfrom
copilot/nvx-issue-1153-publication-cleanup

Conversation

@ppenna

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

Copy link
Copy Markdown
Contributor

Keeps a failed snapshot publication from leaving a restorable snapshot beside a source that resumes, for microsoft/nvx#1153. When the final rename of a microVM capture failed and so did the removal of its staging directory, 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 VM.

One commit on d6addf8c1, the head of feature/microvm/dev. microsoft/nvx#1415 pins this head.

Don't resume beside a restorable staged snapshot (ed8fc0713)

  • Cause. StagingDirectory::rollback in openvmm_helpers::snapshot::publish returned SnapshotWriteError::CleanupUncertain, which makes the microVM controller terminate the source, only when the staging directory may hold an alias to live RAM, which it assumes from the moment that it tries to link the source's RAM. Otherwise it only warned that removing the staging directory failed and returned BeforeCommit, which the controller treats as rollback-safe, so it resumed the quiesced source whatever the staging directory still held.
  • Change.
    • Restore cannot open a snapshot directory without manifest.bin, so cleanup removes the staged manifest first, proves it absent, and on Unix flushes the staging directory, before it removes the rest of the directory.
    • 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, and otherwise CleanupUncertain with the staging path, so that the controller terminates the source.
    • CleanupUncertain's message and the controller's log speak of staging cleanup, not only of an automatic RAM alias.
  • Alternatives. Returning CleanupUncertain for every failed cleanup of an independent copy would keep the guarantee too, but would stop the VM when nothing that restore can open 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.
  • Compatibility. The snapshot format is unchanged. Successful publications, and failed ones whose cleanup succeeds, behave as before.
  • Tests. uncertain_cleanup_of_complete_independent_staging_is_not_rollback_safe stages a complete independent copy that restore can open, fails the final rename on a non-empty destination, injects a failed cleanup, and requires CleanupUncertain with the staging path; it fails at adb7c8bc8 on Windows and Linux. independent_staging_without_its_manifest_is_rollback_safe stops the removal after the manifest and requires that restore cannot open what remains and that rollback is safe, and uncertain_cleanup_of_staging_that_never_held_a_manifest_is_rollback_safe requires that a staging directory that never held a manifest still resumes the source.
  • Guide. The snapshot guide's warning and the snapshot format's memory section say when a failed publication resumes the source.

Validation

With Rust 1.97.1, at this head:

  • Linux (Azure Linux 3.0): cargo clippy --all-targets -- -D warnings, cargo doc --no-deps with -D warnings, and cargo nextest run --profile agent for openvmm_helpers and openvmm_entry: 437 passed. openvmm_helpers for x86_64-unknown-linux-musl: 126 passed, so the new tests' failed rename does not depend on renameat2.
  • Windows: the same, 405 passed, and cargo xtask fmt --fix, clean.
  • NVX's scratch-snapshot, snapshot-core, snapshot-rollback, and snapshot-tiers scenarios pass on KVM, MSHV, and WHP with OpenVMM built at this head, as do console-snapshot, sandbox-lifecycle, and smp-snapshot on KVM; openvmm: don't resume beside a restorable staged snapshot nvx#1415 reports them.

At 985336151, the same commit on adb7c8bc8 (an identical range-diff), on Linux: a cleanup that a read-only staging directory refuses for real, rather than by injection, returns CleanupUncertain, where adb7c8bc8 returned BeforeCommit while read_snapshot still opened the manifest, state, and memory that it left; and a removal refused only below a nested read-only directory, after the manifest's removal, returns BeforeCommit beside artifacts that restore cannot open.

Notes

  • Land it by fast-forwarding feature/microvm/dev to this head, ed8fc0713b4c6301d3b82ffe88817e70084d84b8, since this repository's merge button squashes and would leave NVX's pin off the branch.

Publication stages a snapshot in a private sibling directory and
renames it into place. When a failure before that rename was followed
by a failed removal of the staging directory, rollback reported
BeforeCommit, which lets the quiesced source resume, unless the
directory held a hard link to the source's live RAM. An independent
copy's staging directory holds a complete snapshot once its manifest
is written, though, so a failed final rename followed by a failed
cleanup left a snapshot that restore could open while the source
resumed, and restoring it would start a second copy of the source.

Restore cannot open a snapshot directory without its manifest, so
cleanup now removes the staged manifest first, proves it absent, and
flushes the staging directory on Unix, before it removes the rest of
the directory. 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, and
a failed cleanup is rollback-safe only once neither may remain:

- When no manifest was staged, or its removal was proved, a failed
  removal of the rest leaves nothing that restore can open, so
  rollback still reports BeforeCommit, with a warning.
- When the manifest's removal fails, or a live RAM alias may remain,
  rollback reports CleanupUncertain, which reports the staging
  directory, and the microVM controller terminates the source instead
  of resuming it.

Terminating the source on every failed cleanup would keep the
guarantee too, but would also stop a VM when nothing that restore can
open remains. CleanupUncertain and the controller's log no longer
speak of an automatic RAM alias only, and the snapshot and snapshot
format guides describe the guarantee.

Tests: a complete independent staging directory whose final rename and
removal fail is not rollback-safe; at the base revision, this test
fails on Windows and Linux, since rollback reported BeforeCommit.
Staging whose removal stops after its manifest leaves artifacts that
restore cannot open and is rollback-safe, as is staging that never
held a manifest. At the base revision on Linux, a removal that a
read-only staging directory refuses for real, rather than by
injection, also reported BeforeCommit while read_snapshot still
opened the manifest, state, and memory that it left.

See microsoft/nvx#1153.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot added Guide release-nvx Targets a branch under feature/microvm/. labels Nov 9, 2026
Pedro Henrique Penna (ppenna) added a commit to microsoft/nvx that referenced this pull request Nov 9, 2026
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>
Pedro Henrique Penna (ppenna) added a commit to microsoft/nvx that referenced this pull request Nov 9, 2026
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>
@ppenna
Pedro Henrique Penna (ppenna) merged commit ed8fc07 into feature/microvm/dev Nov 9, 2026
73 of 74 checks passed
@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Guide release-nvx Targets a branch under feature/microvm/.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant