Repository navigation
openvmm: pin input gating that keeps devices open to the vCPUs - #1425
Merged
Pedro Henrique Penna (ppenna) merged 3 commits intoNov 10, 2026
Merged
Conversation
A guest's snapshot request could crash a multi-vCPU microVM, or lose the device accesses of its other vCPUs (#1138). The snapshot boundary gates host input before it stops the vCPUs, so they run while each device's state unit changes the device's gate, and the unit held the device's mutex closed for the change, until the end of its wait. A port or MMIO access that another vCPU made then was dropped, a read returning all ones; an interrupt from another device was lost; and an EOI or a PCI configuration access panicked the VM worker with "lock should not be closed". Pin 46bfe02ed65697e858f66ce55eb60831b3ac3461, the head of microsoft/openvmm#5005, one commit on cba21d109, the head of microsoft/openvmm#5004, on which it stacks, which follows ac3dc27a7, the head of microsoft/openvmm#5003, and b4028c1aa, the head of feature/microvm/dev: - 46bfe02ed vmotherboard: gate a device's input without closing it to the vCPUs The revision splits a device's gate change into a synchronous part, which the unit makes under the lock that the vCPUs' accesses take, and a wait that does not borrow the device, which the unit awaits without it. The virtio transports and the remote device proxy send their gate's request in the synchronous part, in the order of the guest's accesses. Evidence: a microVM guest with 2 and 4 vCPUs requested 2000 snapshots, each of which gated host input and then failed its preflight, since its destination existed, while its other vCPUs read the magic value of the virtio-fs device's MMIO window, and with 4 vCPUs the console's too, in a loop. With OpenVMM at d6addf8c1, 145 to 2358 of a run's reads returned all ones, and OpenVMM logged that the device did not respond, in each of 3 runs per count on nvx-kvm-test (KVM), nvx-mshv-test (MSHV), and nvx-whp-test (WHP), all virtual machines; with a91d4c7a4, the same patch on d6addf8c1, no read did. With a91d4c7a4, the default microVM suite passed on all three, with 1, 2, and 4 vCPUs. At the pinned revision, the OpenVMM tests of the changed packages and the virtio devices pass, 545 on Windows and 550 on Linux, as they did at a91d4c7a4. 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, 46bfe02ed, the head of microsoft/openvmm#5005, at position 238, after position 237, cba21d109, the head of microsoft/openvmm#5004, on which it stacks, which follows positions 236, ac3dc27a7, the head of microsoft/openvmm#5003, and 235, b4028c1aa, the head of feature/microvm/dev. The pin is 107 commits past the mapped tip, and positions 132-238 stay unassigned. Position 238 changes the input gate that PR09's position 018 adds: the chipset device unit, which changed a device's gate with the device's mutex closed, now makes the gate's synchronous part under the device's ordinary lock and awaits the rest without the device, since the vCPUs run through a gate change. It changes the gate's methods of ChangeDeviceState, the erased chipset devices, and the remote device proxy, which position 018 adds, and the virtio transports' forwarding of the gate, which PR13's position 040 adds, and adds tests of the unit, both virtio transports, and the proxy. Replaying it on upstream main conflicts in all eight of the files that it changes, since upstream main lacks the input gate of position 018 and its forwarding by position 040, so it follows PR09 and PR13 upstream. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Nov 9, 2026
Pedro Henrique Penna (ppenna)
marked this pull request as ready for review
November 10, 2026 03:02
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The roadmap conflates eight conflicting files with nine total changed files in commit 46bfe02ed, leaving the upstream replay notes inaccurate.
1 open issue
What changed in this PR
This PR pins OpenVMM’s fix for #1138, keeping devices accessible to running vCPUs during snapshot input gating. The roadmap records the new revision and its upstream dependencies.
Changes:
- Updates the documented pin to
46bfe02ed, position 238, extending the chain to 107 commits beyond the mapped tip. - Describes the split between the synchronous gate change and its asynchronous wait, with dependencies on PR09 and PR13.
| File | Description |
|---|---|
doc/openvmm-upstream-roadmap.md |
Updates the pin, chain counts, commit mapping, and upstream replay notes for the input-gating fix. |
Review effort: Balanced
Position 238 changes nine files, eight that it modifies and the new file that holds the transports' tests, but the roadmap said that its replay on upstream main conflicts in all eight of the files that it changes. The replay conflicts in the eight that it modifies, and the new file applies cleanly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
deleted the
agents/issue-1138-input-gate-lock
branch
November 10, 2026 03:57
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 #1138
What and why
A guest's snapshot request could crash a multi-vCPU microVM, or lose the device
accesses of its other vCPUs. A port or MMIO access that another vCPU made
during the request went unanswered, a read returning all ones and a write
lost; an interrupt from another device was dropped; and an EOI or a PCI
configuration access panicked the VM worker with "lock should not be closed".
Root cause: a snapshot boundary gates host input before it stops the vCPUs,
and resumes a gate that failed before any of them stops, so the vCPUs run
through both. OpenVMM's chipset device unit
(
vmotherboard/src/chipset/backing/arc_mutex/state_unit.rs) neverthelesschanged each gate with the device's mutex closed, from the call to the end of
the change's wait, as it changes the device's other states, which run only
while the vCPUs are stopped, and a vCPU's access that met the closed mutex was
dropped. The window lasted the whole wait of a virtio transport's gate for its
device task, and of a remote device's gate for its worker, and even a gate
that completes at once, as most devices' gates do, closed the device for an
instant, which a vCPU that signals EOIs in a loop met within one to five
gates.
microsoft/openvmm#5005,
vmotherboard: gate a device's input without closing it to the vCPUs, splits a gate change into two parts.ChangeDeviceState::quiesce_inputandresume_inputmake the synchronouspart and return what remains as an
InputGateWait, an owned, boxed futurethat does not borrow the device. The chipset device unit makes the call under
the device's ordinary lock, as a vCPU's access does, releases the lock, and
then awaits the wait, so a vCPU's access comes before the synchronous part or
after it and is served either way. The virtio transports and the remote device
proxy send their gate's request in the synchronous part, on the channel that
carries the commands of the guest's accesses, so that their device takes the
gate in the order of those accesses, and wait for its answer without the
device; the erased chipset devices forward both parts. Only the input gate
changed: the other state changes still close the device, since they run with
the vCPUs stopped, and the remote device worker is unchanged.
Commits:
openvmm: pin input gating that keeps devices open to the vCPUsmoves thegitlink, and nothing else, from
cba21d109, the head of[DO NOT REVIEW] openvmm_helpers: refuse a FIFO artifact without waiting for a writer openvmm#5004, which openvmm: pin refusing a FIFO snapshot artifact without waiting #1424 pins, to
46bfe02ed65697e858f66ce55eb60831b3ac3461, the head of[DO NOT REVIEW] vmotherboard: gate a device's input without closing it to the vCPUs openvmm#5005, one commit on
cba21d109; its message carries thehost 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 input gating that keeps devices open in the OpenVMM roadmapmaps position 238, unassigned, 107 commits past the mapped tip, with the
mapped work that it changes: the input gate that PR09's position 018 adds
and that PR13's position 040 forwards through the virtio transports. It
conflicts with upstream main in eight of its nine files, all but the new
file of the transports' tests, so it follows PR09 and PR13 upstream.
doc: say which files of the input gating conflict upstreamcorrects thatcount in the roadmap, which said that position 238 conflicts in all eight of
the files that it changes, after review.
Decisions:
vCPUs that access the device for the whole wait and risk a deadlock with a
device task that needs a vCPU's access to finish; and the vCPUs' access
paths do not tolerate a closed device, which would hide the dropped accesses
rather than serve them.
closes the chipset bus while the vCPUs can still access it, can use the same
pattern later.
clearing a device's input gate while a boundary holds host input, is openvmm: a guest's virtio device reset lets host input past a held input gate #1416,
outside this change.
46bfe02edis the commit that the validation before this restack tested,a91d4c7a4ond6addf8c1, rebased ontocba21d109:git range-diffshowsthe patch identical, and the commits between change none of its files.
Stack
This is layer 3 of a stack of four pull requests, one for each of four issues,
each based on the branch of the one below it; their OpenVMM pull requests
stacked the same way. Layers 1 and 2 have landed, so this pull request now
targets
dev, and microsoft/openvmm#5005 targetsfeature/microvm/dev.dev)feature/microvm/dev), landedac3dc27a7, position 236dev)feature/microvm/dev), landedcba21d109, position 237dev)feature/microvm/dev)46bfe02ed, position 238agents/issue-1138-input-gate-lock)46bfe02ed, this layer'sLanding order, bottom first, one layer at a time; each OpenVMM pull request
lands before its NVX pull request merges:
feature/microvm/devtoac3dc27a738808d38e1148d3caefc5e89111ee32, since OpenVMM's merge buttonsquashes and would leave the pin off the branch. Then merge openvmm: pin overflow-free memory-expansion ranges #1423
through the merge queue; GitHub deletes its branch and retargets openvmm: pin refusing a FIFO snapshot artifact without waiting #1424
to
dev.feature/microvm/dev(
gh pr edit 5004 --repo microsoft/openvmm --base feature/microvm/dev),fast-forward
feature/microvm/devtocba21d109eeb99fbc573c79b2ed9f4754f734b25, and merge openvmm: pin refusing a FIFO snapshot artifact without waiting #1424; GitHubretargets this pull request to
dev.feature/microvm/devto46bfe02ed65697e858f66ce55eb60831b3ac3461, andmerge this pull request.
Validation
Before this restack, with OpenVMM
d6addf8c1for "before" anda91d4c7a4(the same patch on
d6addf8c1) for "after". End to end, a microVM guestrequested 2000 snapshots, each of which gated host input and then failed its
preflight, since its destination existed, while its other vCPUs read the
magic value of the virtio-fs device's MMIO window, and with 4 vCPUs the
console's too, in a loop; 3 runs per cell. Reads that returned all ones:
Before, OpenVMM logged that the device did not respond; after, it logged no
such warning. With
a91d4c7a4, the snapshot and SMP scenarios and the fulldefault microVM suite, with 1, 2, and 4 vCPUs, passed on all three hosts.
OpenVMM's tests then: without the fix, the deterministic test failed, with the
port write dropped ("device didn't respond"), the EOI panicking ("lock should
not be closed"), and the interrupt lost, and the 1000-round stress test failed
in 10 of 10 runs; with it, 20 of 20 runs passed. Mutation checks of the virtio
and proxy gates ran too. The package checks passed:
cargo clippyandcargo docon Windows for the five changed packages and the three virtiodevices, and
cargo nextest, 545 tests on Windows and 550 on Linux.Rerun for this restack, at OpenVMM
46bfe02edand this head:cargo clippy --all-targetsandcargo doc --no-depsfor
vmcore,chipset_device_resources,virtio,vmotherboard,chipset_device_worker,virtiofs,virtio_net, andvirtio_console,without warnings, and
cargo nextest run --profile agentfor those andstate_unit, 545 passed and 2 skipped on Windows, and 550 passed and 2skipped on Linux (nvx-kvm-test, glibc), as before;
cargo xtask fmt,clean.
python scripts/nvx.py verify;python scripts/local_gates.py --base <layer 2's head> --only test-changes markdown-links test-layout openvmm-vectors openvmm-cpu-profiles --run, all passed, with no change to anexisting test and the 4 vector and 1 CPU-profile comparisons passing against
46bfe02ed;python scripts/openvmm_pin.py check-roadmap --worktreeandcheck-branch --topic --target <layer 2's head>, passed. After the rebase,git range-diffshows this layer's two commits unchanged from those thatthe gates tested, on a base with the same tree, and this head's tree is the
one that they tested;
python scripts/rebase_check.py verifylists only thelower layers' commits, now in the base, as dropped.
At the exact revisions, for marking ready: the same end-to-end reproduction,
2000 requests per run with 2 and 4 vCPUs, 3 runs per cell, in a worktree of
da8157aec, this head but for the roadmap correction, with OpenVMMcba21d109, #1424's pin and this change's base, for"before" and this pin,
46bfe02ed, for "after". OpenVMM was built on eachhost with
build-openvmm(GNU for kvm, musl for mshv, MSVC for whp), but forWHP's "before", which is the executable that #1424's CI built at
cba21d109;the guest artifacts are those of #1424's CI run, whose inputs this change
leaves alone. Reads that returned all ones:
Every run passed its 2000 boundaries and exited with status 0. Before, each
run's OpenVMM log held "device didn't respond" warnings; after, none did, and
no run panicked.
CI run 42747993772
of this head,
3beaacf6f, passed, with OpenVMM built at46bfe02ed: everymicroVM scenario passed on KVM, MSHV, and WHP, 78, 70, and 70 of them, the
snapshot, SMP, and restore scenarios among them, and the debug kernel's 8 on
MSHV, as did NVX CLI on Linux and Windows, the performance regression gate,
Required status check, andOpenVMM CI of the pinned revision, afterOpenVMM's CI of the pin,
run 42743138458,
passed the 6 jobs that
check-openvmm-cirequires. The merge group tests thispull request again, merged into the latest
dev.