Repository navigation
openvmm: pin the rollback as the only way to run a quiesced microVM - #1430
Merged
Pedro Henrique Penna (ppenna) merged 2 commits intoNov 10, 2026
Merged
Conversation
An ordinary resume could run a microVM again after the VM worker had quiesced it for a snapshot and handed its state to the snapshot controller, without the snapshot's rollback (#1170). The worker released the snapshot boundary of a quiesced VM, after which nothing refused a resume, and it quiesced a running VM that held no snapshot boundary, so that none refused one. NVX's controller sends neither order, but the capture's guarantee that a source runs again only through the rollback of a failed capture rested on that alone. Pin 4c2697aef28d7fa69f788ce4e65b6554c1cfb935, the head of microsoft/openvmm#5010, two commits on 46bfe02ed, the head of feature/microvm/dev: - b5d20bf84 petri: let a microVM test be its snapshot controller - 4c2697aef openvmm_core: run a quiesced microVM again only through its rollback The revision has the worker refuse to release the boundary of a quiesced VM, before it resumes host input or changes the boundary, so that only the rollback, which starts the VM's state units first, releases it; and reject a quiesce outside a guest-requested boundary without stopping the VM. Its VMM tests take the snapshot controller's part, which petri can now do. Evidence: with the worker change reverted on the revision, both new VMM tests fail on nvx-kvm-test (KVM), nvx-mshv-test (MSHV), and nvx-whp-test (WHP), all virtual machines, and locally on WHP: the release of a quiesced VM's boundary and an ordinary resume succeed, the partition runs, and the guest continues; and a quiesce outside a boundary returns the saved state of all 14 state units and leaves the partition stopped. At the revision they pass on all four, as do the test of the controller's own orders and phase_1_lifecycle. NVX's snapshot-core, snapshot-rollback, and snapshot-tiers scenarios, with 1 and 4 vCPUs, pass on the three hosts with OpenVMM built from the revision's code. NVX needs no coordinated change: the control-session vectors, the source excerpts, the contract versions, and the CPU profiles that nvx-rs copies from OpenVMM match the revision's. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Maps NVX's new pin, 4c2697aef, the head of microsoft/openvmm#5010, at position 240, after position 239, b5d20bf84, its other commit, which follows position 238, 46bfe02ed, the head of feature/microvm/dev, which microsoft/openvmm#5005 merged after microsoft/openvmm#5004 and microsoft/openvmm#5003. The pin is 109 commits past the mapped tip, and positions 132-240 stay unassigned. Positions 239 and 240 change the snapshot boundary of PR17. Position 239 lets a VMM test be the snapshot controller: it gives the boundary's channels to petri's handle of the snapshot-request port, which PR17's position 076 adds without one, and to petri's launch of the VM worker, whose boundary parameters position 072 adds, keeps them in the petri microVM support of PR15's position 065, and adds a test beside position 065's cold-boot test. Position 240 has the worker of position 072 refuse to release the boundary of a quiesced VM and reject a quiesce outside a boundary, extends the snapshot guide's paragraph that position 076 adds, and adds tests beside position 239's. Replaying them on upstream main conflicts in every file but petri's start of the VM, since upstream main lacks the petri microVM support of position 065 and the boundary of positions 072 and 076, so they follow PR15 and PR17 upstream. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
The snapshot commit/rollback safety change requires exact-head KVM, MSHV, and WHP CI and upstream fast-forward verification, while OpenVMM #5010 remains open with required runtime checks incomplete.
No open issues 🎉
What changed in this PR
This PR pins the OpenVMM fix for #1170, preventing ordinary resume from restarting a microVM quiesced for a snapshot without rollback. The roadmap records the new revision and its upstream dependencies.
Changes:
- Updates the documented pin to
4c2697aefand extends the chain through position 240. - Maps the snapshot-controller test support and rollback-only resume checks to their prerequisite work in PR15 and PR17.
| File | Description |
|---|---|
doc/openvmm-upstream-roadmap.md |
Updates the pin, commit counts, and mappings for positions 239–240, including upstream dependencies and replay conflicts. |
Review effort: Balanced
Pedro Henrique Penna (ppenna)
deleted the
agents/issue-1170-snapshot-resume-bypass
branch
November 10, 2026 10:25
This was referenced Nov 10, 2026
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.
Fixes #1170
What and why
An ordinary resume could run a microVM again after the VM worker had quiesced
it for a guest-requested snapshot and handed its state to the snapshot
controller, without the snapshot's rollback (
ResumeAfterFailedSnapshot), intwo ways:
ReleaseSnapshotBoundaryafterQuiesceForSnapshotreleased the boundaryof the quiesced VM: it resumed host input, completed the guest's snapshot
transaction, and dropped the vCPU stop guard of the stopped VM, after which
an ordinary
Resumestarted the VM again.QuiesceForSnapshotstopped and saved a running VM that had requested nosnapshot, and so held no boundary, and an ordinary
Resumestarted it againat once.
Root cause: in OpenVMM's VM worker
(
openvmm/openvmm_core/src/worker/dispatch/microvm.rs), the snapshot boundaryis what refuses an ordinary resume, since the boundary's RPC filter refuses
Resumewhile the boundary's vCPU stop guard is held, and two requests couldleave a quiesced VM without one:
release_snapshot_boundarychecked only thata boundary was active, and
quiesce_for_snapshotonly that the VM ran. NVX'scontroller, the VM controller of
openvmm_entry, sends neither order: itquiesces only at a boundary that the worker reported, and after a quiesce it
ends the source or rolls the snapshot back. But the capture's guarantee, that
a source runs again only through the rollback of a failed capture
(Commit Point), rested
on that order alone.
microsoft/openvmm#5010 has the worker hold the order itself, in two commits
on
46bfe02ed, the head offeature/microvm/dev:b5d20bf84,petri: let a microVM test be its snapshot controller: petrican now give a microVM's VM worker the snapshot boundary's channels and let
a VMM test send the controller's requests, in any order. A test takes the
controller's own two ways out of a boundary.
4c2697aef,openvmm_core: run a quiesced microVM again only through its rollback:release_snapshot_boundaryrefuses the boundary of a quiescedVM, before it resumes input or changes the boundary, so only the rollback,
which starts the VM's state units first, releases it, and the boundary keeps
refusing an ordinary resume until then; and
quiesce_for_snapshotrejects,with
SnapshotQuiesceError::Rejectedand without stopping it, a VM thatholds no boundary. VMM tests reproduce both of the issue's paths, and the
OpenVMM snapshot guide states the rule.
Commits:
openvmm: pin the rollback as the only way to run a quiesced microVMmovesthe gitlink, and nothing else, from
46bfe02ed, which openvmm: pin input gating that keeps devices open to the vCPUs #1425 pins, to4c2697aef28d7fa69f788ce4e65b6554c1cfb935, the head of[DO NOT REVIEW] openvmm_core: run a quiesced microVM again only through its rollback openvmm#5010; its message carries the host evidence below. NVX
needs no coordinated change: the control-session vectors, source excerpts,
contract versions, and CPU profiles that nvx-rs copies from OpenVMM match
the revision's.
doc: map the rollback-only resume in the OpenVMM roadmapmaps positions239 and 240, unassigned, 109 commits past the mapped tip, with the mapped
work that they change: the snapshot boundary that PR17's positions 072 and
076 add, and the petri microVM support of PR15's position 065. They conflict
with upstream main in every file but petri's start of the VM, so they follow
PR15 and PR17 upstream.
Decisions:
which OpenVMM's CI runs on KVM, MSHV, and WHP, in the
run vmm-testsjobsthat NVX's
openvmm-cicheck requires. Alternatives: the in-process KVMtests of
openvmm_entrythat the issue's patch proposed, which are ignoredby default and KVM-only, so no CI would run them; or unit tests of a check
function extracted for them, a seam that could not show the failure at the
base revision.
every caller gets them, rather than in the boundary's RPC filter.
ResumeAfterFailedSnapshotsent outside any boundarystill starts a paused VM and then fails its release. It does not bypass the
rollback, so hardening it is a separate change. The sibling issues of OpenVMM/microVM umbrella: snapshot quiesce, rollback, and device restoration in the VM worker #1181
keep their scope: openvmm: an uncertain snapshot quiesce makes teardown or a later lifecycle request panic #1148 and openvmm: stop, save, reset or restore panics if a state unit's task has exited #1363 (requests on a terminal or dead unit),
openvmm: failed snapshot rollback leaves restarted devices running #1149, openvmm: refactor device restoration onto upstream async save/restore #1232, and openvmm: a guest's virtio device reset lets host input past a held input gate #1416.
OPENVMM_REQUIRED_MICROVM_TESTSinscripts/nvx_tools/ci.py, whichnvx.py test-openvmm --backend whpruns, stays as it is: OpenVMM's CI runsthe new tests on all four platforms that NVX requires, and
test-openvmmselects them by name on KVM and MSHV. Adding them would change the count
that an existing test checks.
from
sleep: the kernel masks its LAPIC timer, and no PIT interrupt wakesthe halted vCPU, with or without a snapshot boundary; on KVM and WHP it wakes
at once. So no test here waits on a guest timer. It is outside this change.
Landing order: land microsoft/openvmm#5010 first, by fast-forwarding
feature/microvm/devto4c2697aef28d7fa69f788ce4e65b6554c1cfb935, sinceOpenVMM's merge button squashes and would leave the pin off the branch; then
merge this pull request.
Validation
The head submitted is
d4878c222, two commits ondev'sb6ad70074, pinning4c2697aef28d7fa69f788ce4e65b6554c1cfb935, the head ofmicrosoft/openvmm#5010, two commits on
46bfe02ed.Reproduction before and after, with
cargo xflowey vmm-tests-runselectingthe three new VMM tests and
phase_1_lifecycle. "Before" is the pin with theworker change reverted, a local scratch commit; "after" is the pin.
Before, on every host,
snapshot_quiesce_resumes_only_on_rollback(path 1)fails with "the boundary's release returned Ok(()), the ordinary resume
returned Ok(()), the guest's continuation within 5s was Ok(Ok(())), and the
partition is running", and
snapshot_quiesce_requires_a_boundary(path 2)with "a snapshot quiesce outside a snapshot boundary returned Ok([...]), and
left the partition stopped", the saved state of all 14 state units.
NVX's snapshot scenarios, with OpenVMM built by
nvx.py build-openvmmfromthis change's code over the release artifacts that
nvx-rs downloadinstalled,
v0.1.0-dev.995230d0ebb4, the executable's hash changing eachtime:
nvx.py test-microvm --scenario snapshot-core --scenario snapshot-rollback --scenario snapshot-tiers --processors 1 4passed onnvx-kvm-test (kvm), nvx-mshv-test (mshv), and nvx-whp-test (whp). They cover a
capture, a release without a capture, a rollback after a failed publication,
and the gated restore's acknowledgement. The builds were of
fee6cf1bb(kvm)and
634cfdc1a(mshv, whp), earlier versions of the pin's second commit thatdiffer from it only in
vmm_tests.Local, on Windows, with Rust 1.97.1:
cargo clippy --all-targetsforopenvmm_core,petri, andvmm_tests, andcargo doc --no-depsfor the three withwarnings denied, without warnings;
cargo nextest run --profile agent -p openvmm_core -p petri, 152 passed;cargo xtask fmt, clean.python scripts/nvx.py verify, passed.python scripts/local_gates.py --base origin/dev --run: test-changes, markdown-links, test-layout,openvmm-vectors, and openvmm-cpu-profiles passed; nvx-cli failed with 7
errors, each a 10-second timeout of a shell script that
test_host_loopback_allow_script_checks_publication_and_trafficortest_private_network_ingress_script_checks_policy_and_trafficruns throughGit's
sh.exeon this loaded machine. The same two tests fail the same wayat
origin/devthere, and this change touches no file underscripts/.python scripts/openvmm_pin.py check-roadmap --worktreeandcheck-branch --topic --target origin/dev, passed;python scripts/check_test_changes.py --base origin/dev, no change to anexisting test;
openvmm_pin.py land(dry run), a fast-forward.VM still ran depended on timing; both regression tests now read the state of
the partition's state unit through inspect.
CI run 42785929040
of this head,
d4878c222, passed, with OpenVMM built at the pin: everymicroVM suite on KVM, MSHV, and WHP, the NVX CLI tests on Linux and Windows,
the performance regression gate,
Required status check, andOpenVMM CI of the pinned revision, once OpenVMM's CI of the pin,run 42785708766,
had passed the 6 jobs that
check-openvmm-cirequires. Itsrun vmm-testsjobs on
x64-linux-amd-kvm,x64-linux-intel-mshv,x64-windows-intel, andx64-windows-amdran the three new tests andphase_1_lifecycle, which allpassed. Its
x64-windows-amd-snpjob failed in 5 Hyper-V OpenHCL SEV-SNP TPMtests, which NVX does not use and this change does not touch. The merge group
tests this pull request again, merged into the latest
dev.