Skip to content

[DO NOT REVIEW] state_unit: handle a unit in a terminal state instead of panicking - #5012

Merged
Pedro Henrique Penna (ppenna) merged 2 commits into
feature/microvm/devfrom
copilot/nvx-issue-1148-terminal-unit-requests
Nov 10, 2026
Merged

Pedro Henrique Penna (ppenna) merged 2 commits into
feature/microvm/devfrom
copilot/nvx-issue-1148-terminal-unit-requests

Conversation

@ppenna

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

Copy link
Copy Markdown
Contributor

Keeps a later lifecycle request from panicking on a state unit in a terminal state, for microsoft/nvx#1148. A unit whose task does not answer its start request is left in the terminal StartUncertain state, which only a later start refused: a later stop, reset, save, restore, or time advance that reached such a unit panicked the VM worker on run_op's state assertion, and a worker restart whose recovery start failed kept serving a VM that it marked running over stopped units, so that its next pause, or its teardown, panicked on StateUnits::stop's running assertion.

Two commits on 4c2697aef, the head of feature/microvm/dev. microsoft/nvx#1435 pins this head.

Handle a unit in a terminal state instead of panicking (78e752de1)

  • Cause. The start rollback of the chain's position 015 leaves a unit whose task does not answer its start, or its start confirmation, in the terminal StartUncertain state, and StateUnits::start refuses a set that holds one. The other state changes still assumed that every unit was Stopped or Running: run_op asserts that a unit that is not in the operation's old state is already in its new state. So a stop of a running set that holds such a unit, as after a hot-add whose start is uncertain, panicked with "unit ... in StartUncertain state, should be Running or Stopped", and a reset, save, restore, or time advance after a failed start with "should be Stopped or Stopped".
  • Change. As the later revisions of state_unit: roll back a partial start instead of panicking #4872, which proposes position 015 upstream, do:
    • reset, save, restore, and advance_time fail with a StateTransitionError that names each unit in a terminal state, before they send any unit a request (check_no_terminal_units). Unlike state_unit: roll back a partial start instead of panicking #4872, they check this before they check that the units are stopped, so that they fail rather than panic even while such a unit keeps the units running, as a later partial-start rollback that keeps a possibly running unit's dependencies running would.
    • stop also stops the units whose start is uncertain, since they may be running, in the same reverse dependency order as the others, and leaves them in StartUncertain, so that a later start still fails.
  • Scope. A unit whose task has ended still panics the stop that it does not answer (run_op's UnitRecvError), as any unit's does; openvmm: stop, save, reset or restore panics if a state unit's task has exited nvx#1363 makes that an error. state_unit: roll back a partial start instead of panicking #4872's other later changes, which keep the units running after an uncertain start, block the rollback's stop of a dependency of a unit that was not stopped, and add stop_for_teardown, are not part of this pull request.
  • Tests. In vmm_core/state_unit/src/tests/terminal.rs, a_stop_stops_a_unit_whose_start_is_uncertain adds a unit to a running set, as a hot-add does, that depends on a running unit and whose task starts it but drops its start request unanswered, and requires a stop to stop it before its dependency and to leave it terminal. requests_fail_after_a_start_leaves_a_terminal_unit and requests_fail_while_a_terminal_unit_keeps_the_set_running require a reset, a save, a restore, and a time advance each to fail, naming only that unit, without sending any unit a request, after a start that leaves a unit terminal, and while such a unit keeps the units running. Without the change, the stop and the first reset panic on the state assertion, and the reset of a running set on its running assertion.

Tear the VM down when a restart cannot resume it (6ddd6ca50)

  • Cause. A worker restart stops the state units of a running VM before it saves the VM, and starts them again when the save fails. When that start failed too, the worker reported the failure and kept serving the VM, which it still marked running although its state units were stopped, or left terminal by the failed start. The next pause, reset, or pulse save and restore, and the worker's teardown, then stopped units that did not run, and panicked on the running assertion of StateUnits::stop.
  • Change. As state_unit: roll back a partial start instead of panicking #4872 does, the worker tears the VM down after such a restart, since the VM cannot resume, and its teardown stops the state units when they run (StateUnits::is_running), rather than when the VM is marked running.
  • Scope. The microVM profile refuses worker restarts, so no NVX microVM reaches this path.
  • Tests. None: no harness of the VM worker can fail a unit's start after a failed save in a running worker, and state_unit: roll back a partial start instead of panicking #4872 has none either.

Validation

At this head, 6ddd6ca50, with Rust 1.97.1. It is 46545c262 on 46bfe02ed, which NVX's first validation tested, rebased onto 4c2697aef; git range-diff shows both patches identical, and the commits from 46bfe02ed to 4c2697aef change none of their files.

  • Windows: cargo clippy --all-targets -p state_unit -p openvmm_core -- -D warnings and cargo doc --no-deps for both with RUSTDOCFLAGS=-D warnings, without warnings; cargo nextest run --profile agent -p state_unit -p openvmm_core, 148 passed; cargo xtask fmt --fix, clean.
  • Linux (NVX's KVM and MSHV test VMs, Azure Linux 3.0, glibc and musl builds): the same clippy, rustdoc, and nextest commands, without warnings, 148 passed.
  • Without the change, the three new tests alone on 4c2697aef fail, as described above, on both Linux VMs, as they did on 46bfe02ed there and on Windows.
  • End to end, NVX's microVM lifecycle, managed-lifecycle, sandbox-lifecycle, snapshot-core, and snapshot-rollback scenarios passed with OpenVMM built from this head on KVM, MSHV, and WHP (NVX's test VMs), as they did at 46545c262. No NVX microVM reaches the panics that this fixes.

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

A unit whose task does not answer its start request is left in the
terminal StartUncertain state, which only a later start refused. Any
other state change that reached such a unit panicked the VM worker on
run_op's state assertion: a stop of a running set, as after a failed
hot-add, with "unit ... in StartUncertain state, should be Running or
Stopped", and a reset, save, restore, or time advance after a failed
start with "should be Stopped or Stopped". So a lifecycle request that
followed a failed start, such as a reset after a failed resume or
after a failed rollback of a microVM snapshot capture, took the
process down (microsoft/nvx#1148).

Those requests now handle the terminal state, as the later revisions
of #4872, which proposes this chain's start rollback,
do:

- A reset, save, restore, or time advance fails, naming each unit in a
  terminal state, before it sends any unit a request. It checks this
  before it checks that the units are stopped, so that it fails rather
  than panics even while such a unit keeps the units running.
- A stop also stops the units whose start is uncertain, since they may
  be running, in the same reverse dependency order as the others, and
  leaves them in their terminal state, so that a later start still
  fails.

A unit whose task has exited still panics the stop that it does not
answer, as any unit's does; microsoft/nvx#1363 tracks that.

Tests: a stop of a running set stops a unit whose start is uncertain
before the unit that it depends on, and the unit stays terminal; after
a start that leaves a unit terminal, and while such a unit keeps the
units running, a reset, save, restore, and time advance each fail,
naming only that unit, without sending any unit a request. Without the
change, the stop and the first reset panic on the state assertion, and
the reset of a running set on its running assertion.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A worker restart stops the state units of a running VM before it saves
the VM, and starts them again when the save fails. When that start
failed too, the worker reported the failure and kept serving the VM,
which it still marked running although its state units were stopped,
or left in a terminal state by the failed start. The next pause, reset,
or pulse save and restore then stopped units that did not run, and so
did the worker's teardown, and each panicked on the running assertion
of StateUnits::stop (microsoft/nvx#1148).

The worker now tears the VM down after such a restart, as the later
revisions of #4872 do, since the VM cannot resume. Its
teardown stops the state units when they run, rather than when the VM
is marked running, so that it does not stop them again.

The microVM profile refuses worker restarts, so no NVX microVM reaches
this path. No test covers it: no harness of the worker can fail a
unit's start after a failed save in a running worker.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot added the release-nvx Targets a branch under feature/microvm/. label Nov 10, 2026
@ppenna
Pedro Henrique Penna (ppenna) merged commit 6ddd6ca into feature/microvm/dev Nov 10, 2026
73 of 74 checks passed
@github-actions

Copy link
Copy Markdown

syeedali pushed a commit to syeedali/nvx that referenced this pull request Nov 11, 2026
A state unit whose task does not answer its start request is left in a
terminal state, which only a later start refused. A later stop, reset,
save, restore, or time advance that reached such a unit panicked the
VM worker on a state assertion, and a worker restart whose recovery
start failed left the VM marked running over stopped units, so that
the next pause, or the worker's teardown, panicked (microsoft#1148).

Pin 6ddd6ca505a7212d92e2a8e561a19635f7185d4a, the head of
microsoft/openvmm#5012, two commits on 4c2697aef, the head of
feature/microvm/dev:

- 78e752de1 state_unit: handle a unit in a terminal state instead of
  panicking
- 6ddd6ca50 openvmm_core: tear the VM down when a restart cannot
  resume it

A reset, save, restore, or time advance now fails, naming each unit
in a terminal state, before it sends a request or checks that the
units are stopped, and a stop also stops such a unit, which may be
running, and leaves it terminal, as microsoft/openvmm#4872's later
revisions do. A restart whose recovery start fails tears the VM down,
and the teardown stops the state units when they run.

Evidence: with the revision's three new state_unit tests alone on
4c2697aef, 3 of the 20 state_unit tests fail on nvx-kvm-test and
nvx-mshv-test (Linux virtual machines), as they did on 46bfe02ed there
and on Windows: a stop and a reset panic on the state assertion, and a
reset of a running set on the running assertion. At the pinned
revision, the state_unit and openvmm_core tests pass, 148 on Windows
and on both Linux hosts, with clippy and rustdoc clean. No NVX microVM
reaches these panics: a unit's task cannot end without aborting
OpenVMM, and the microVM profile refuses worker restarts and has no
hot-add. NVX's lifecycle, managed-lifecycle, sandbox-lifecycle,
snapshot-core, and snapshot-rollback scenarios pass with OpenVMM built
from the revision on nvx-kvm-test (KVM), nvx-mshv-test (MSHV), and
nvx-whp-test (WHP).

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, as the
openvmm_vectors and openvmm_cpu_profiles comparisons show.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
syeedali pushed a commit to syeedali/nvx that referenced this pull request Nov 11, 2026
Map positions 241 and 242, 78e752de1 and 6ddd6ca50, which
microsoft/openvmm#5012 proposes for feature/microvm/dev on its head,
position 240, 4c2697aef, which microsoft/openvmm#5010 merged, and move
NVX's pin to position 242, 111 commits past the mapped tip. Position
241 has a stop of the state units also stop a unit in the terminal
state in which PR09's position 015 leaves a unit whose task does not
answer its start, and has a reset, save, restore, or time advance fail
while a unit is in that state, which only a later start refused.
Position 242 has the VM worker tear the VM down when the start again of
a failed restart, which position 015 adds, fails, and has its teardown
stop the state units when they run.

Both are therefore PR09 fixups, recorded as the PR12 fixup at v5.1
position 221 was: the DAG gives them a fixup step, PR09's summary row,
graph node, and mapping count them, and the fold sentence after the
DAG sends them into position 015, and position 241's check of a time
advance, with its test, into PR10's position 019, which adds the time
advance. Replaying them on upstream main, ba105dd7f, conflicts in four
of their five files, all but the new test file, since upstream main
lacks the start rollback of position 015 and the time advance of
position 019, so they follow PR09 upstream; microsoft/openvmm#4872's
head makes the same changes in its form of position 015.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
syeedali pushed a commit to syeedali/nvx that referenced this pull request Nov 11, 2026
Map positions 243-245, 2fcd1573d, 5a750a862, and a8a0e3517, which
microsoft/openvmm#5013 proposes for feature/microvm/dev on its head,
position 242, 6ddd6ca50, which microsoft/openvmm#5012 merged with
position 241, and move NVX's pin to position 245, 114 commits past the
mapped tip.

Position 243 has the rollback of a partial start, which PR09's position
015 adds, stop the units that started again in reverse dependency
order, without panicking on a unit whose task does not answer, as
microsoft/openvmm#4872's head does. It is therefore a PR09 fixup,
recorded as positions 241 and 242 are: the DAG's PR09 fixup step,
PR09's summary row, graph node, and mapping count it, and the fold
sentence after the DAG sends it into position 015, and its description
of the snapshot rollback into PR17's position 072.

Positions 244 and 245 have a stop, and a reset, save, restore, or time
advance, fail instead of panicking when a unit does not answer, which
no mapped commit adds, so they stay unassigned, with remarks on the
chain commits whose callers they change. microsoft/openvmm#4937
proposes position 244's change for upstream's code, so the paragraph on
it no longer says that it proposes no chain commit.

Replaying them on upstream main, ba105dd7f, conflicts in all three
files of position 243, 12 of the 20 of position 244, and two of the
three of position 245, since upstream main lacks the start rollback of
position 015 and the other chain commits that they build on.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant