Skip to content

openvmm: let a platform restore attach an aggregate to a dormant filesystem slot - #948

Open
Pedro Henrique Penna (ppenna) wants to merge 4 commits into
devfrom
agents/issue-540-logical-commits-pr-guidelines
Open

Pedro Henrique Penna (ppenna) wants to merge 4 commits into
devfrom
agents/issue-540-logical-commits-pr-guidelines

Conversation

@ppenna

@ppenna Pedro Henrique Penna (ppenna) commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #540. Pins microsoft/openvmm#4775 at d7892ffa857d4b01aef0ee309969dda3e95fee44, which lets the restore of a microVM platform snapshot attach an aggregate of host directories and files, with its access policy and owner, to the filesystem slot that the capture left dormant, validated as at a cold boot, before any vCPU runs. It adds a microVM scenario that restores one platform snapshot with such an aggregate on KVM, MSHV, and WHP.

Based on dev at dce536f1d. microsoft/openvmm#4775 is two commits directly on d2338ea22, the head of feature/microvm/dev and the revision that dev pins, so this branch's four commits are its whole diff.

Change

Commit Files Change
0ba6a0a8d openvmm openvmm d2338ea22 → d7892ffa8: the two commits of microsoft/openvmm#4775
e6a86186f doc doc/openvmm-upstream-roadmap.md Records them as positions 350 and 351, unassigned like positions 346-349 because position 351 changes the dormant-slot restore of PR18's position 113, which position 293 limited to one --mount; moves the NVX pin; and records that microsoft/openvmm#4769 merged positions 348 and 349 into feature/microvm/dev
b11d20ce5 doc doc/run.md A Platform filesystem exports section for direct OpenVMM restores; the virtio-fs mapping section, whose nvx-rs run rule still holds, links it
4cf5d4afe scripts scripts/nvx_tools/microvm_tests.py, scripts/nvx_tools/microvm_test_scripts/platform-aggregate-export.sh, scripts/test_microvm_tests.py, scripts/nvx_tools/microvm_shards.json, doc/ci.md, doc/usage.md New default-suite scenario platform-aggregate-export; filesystem-snapshot also refuses an aggregate on its untiered dormant slot; shards replanned

OpenVMM changes

  • The device takes a dormant slot's state into an aggregate (5ab722b73). A capture that leaves the slot dormant saves a dormant device state, without an attachment, a policy, objects, or an initialized FUSE session, which the device restores into any attached device. A new unit test checks it for an aggregate of a read-write directory and a read-only file, and that the device then saves the aggregate rather than the dormant slot. Only a test changes.
  • A platform restore attaches an aggregate to the dormant slot (d7892ffa8). At the restore of a platform snapshot whose slot is dormant, --mount-aggregate with its --mount-child options, and their --mount-deny, --mount-allow, --mount-write, and --mount-owner policy, attach an aggregate. The restore builds it with a cold boot's code, so it validates the children's kinds, modes, names, overlaps, and limits, the policy paths, and the owner as a cold boot does, and refuses what a cold boot refuses, before any vCPU runs. The slot's device keeps the stable ID, tag, MMIO range, interrupt, features, and queues that the snapshot recorded, and the guest keeps its captured command line, which names no filesystem: OpenVMM exposes no layout, and the guest learns of the export over its own control channel (nvx-rs: aggregate exports for clones #857). The restore contract still records the dormant slot. Only the platform tier changes: the dormant slot of a workload-start, instance-checkpoint, or untiered snapshot still binds only a --mount, a snapshot that predates the dormant slot binds nothing, and a snapshot that captured a filesystem still requires exactly that filesystem. --mount, and a restore without an attachment, behave as before.

Tests

  • platform-aggregate-export captures a platform snapshot with sandbox blocks and without a filesystem, and restores it with the aggregate of the filesystem-shares scenario: a read-write workspace and a read-only tool cache, each with a denied path, a read-write data directory whose root exposes only its allowed paths and whose notes alone are writable, and a read-only and a read-write file, each without its directory. The clone keeps its captured command line, so its guest checks that no virtfs_ or nvx_share= token appeared, mounts the aggregate itself, finds the five children in the read-only root that only root can enter, checks each child's kind, mode, and policy, and binds a directory and a file child; the host then requires exactly the writes that the policy admits. Before the guest runs, OpenVMM must refuse the restores whose aggregates a cold boot refuses: overlapping directories, a file inside a directory child, a directory as a file and a file as a directory, a repeated name, a policy path of a file child, one outside every child, and a relative one, and on a Windows host caller ownership. A refused restore must print none of the guest's lines, and no restore may change the snapshot or the shared trees. It runs with the Alpine sandbox-control guest only, like platform-filesystem, and joins shard 2 on KVM and MSHV and shard 1 on WHP, each planned with the scenario's time in the bare-metal default suite below.
  • filesystem-snapshot also requires OpenVMM to refuse an aggregate for the dormant slot of its untiered snapshot, which still binds a --mount.
  • Unit tests cover the guest's checks, the capture's and the restore's arguments, each refusal's aggregate against the host's trees, the Windows-only refusal, a missing report, a guest failure, writes beyond the policy, and the snapshot's and the trees' integrity. [DONT REVIEW] microVM: let a platform restore attach an aggregate to a dormant filesystem slot openvmm#4775 adds unit tests for the device's restore of a dormant slot's state into an aggregate; for a dormant-slot restore that resolves an aggregate of directory and file children, with mixed modes and denied, allowed, and writable paths, to a cold boot's configuration, roots, and identities; for its refusal of what a cold boot refuses, with a cold boot's errors; for --mount-owner; for snapshots without the dormant slot and of a single directory; and for the tier rule at every tier.

Of #540's acceptance cases, the scenario covers a restore of a dormant slot with an aggregate of directory and file children, with mixed modes and policies, and the refusal of invalid aggregates, on every backend. Snapshots with a captured attachment keep their exact-match rules: filesystem-shares and filesystem-snapshot, which restore captured aggregates and directories, pass unchanged in the default suite, as do OpenVMM's exact-match unit tests. A current OpenVMM cannot capture a snapshot without the dormant slot's version, so OpenVMM's unit tests cover that refusal, and the tier rule's unit test covers workload and instance snapshots, as filesystem-snapshot does for an untiered one.

Evidence

On the bare-metal hosts prometheus32 (Linux/KVM), prometheus30 (Linux/MSHV), and prometheus28 (Windows/WHP), each in a separate worktree at 02838f0ae with OpenVMM built there from d7892ffa8 and the guest of development release v0.1.0-dev.1ee6489241a8:

Check KVM MSHV WHP
platform-aggregate-export with the fix Passes (3.4 s) Passes (4.1 s) Passes (9.1 s)
filesystem-snapshot with the fix Passes (4.8 s) Passes (5.0 s) Passes (8.8 s)
Default microVM suite with the fix 41/41 (47 executions), 509.1 s 41/41 (47 executions), 488.7 s 41/41 (47 executions), 655.6 s
platform-aggregate-export in the default suite 3.4 s 4.5 s 9.1 s

With that release's unpatched OpenVMM d2338ea22 on MSHV, the capture succeeds and the clone's restore fails at a dormant-slot snapshot can attach only a --mount on restore.

Every clone reported NVX-POST-RESTORE-OK: tier=platform and NVX-PLATFORM-AGGREGATE-OK, and every refusal failed before the guest ran, with: microVM filesystem host paths must not overlap (overlapping directories, and a file inside a directory child); invalid --mount-child 0, caused by the root's not being a regular file or a plain directory; invalid --mount-aggregate or --mount-child options, caused by a child name that is not unique; --mount-child 4 exposes the file ...; microVM denied path resolves outside the filesystem export roots; with --mount-aggregate, --mount-deny requires an absolute host path: secrets; on WHP, --mount-owner caller requires a Linux host; and for filesystem-snapshot's untiered snapshot, --mount-aggregate on a dormant filesystem slot requires a platform snapshot.

On prometheus28, nvx-rs download fails with curl: (43) A libcurl function was given a bad argument under the host's curl 8.8.0, so its guest artifacts came from the same release through nvx-rs download on another Windows machine, with curl 8.21.0, and their SHA-256 digests matched after the copy.

Equivalence and validation

  • Hosts. The hosts ran the default suite at 02838f0ae, on dev at d77908efc, and platform-aggregate-export and filesystem-snapshot again at this head, where the scenario passes in 3.4 s on KVM, 4.0 s on MSHV, and 8.8 s on WHP. This head differs from 02838f0ae in the scenario only by the review fix: the integrity check after the refused restores also compares the workspace. It also differs in the shard partition, which the hosts' unsharded runs don't read and which is planned with their in-suite times, in the scenario commit's message, and in its base: dev gained nvx-rs: capture templates into their store, and publish them #887 and tests: capture templates in VMs through the runtime adapter #933, which change nvx-rs's template store and the runtime adapter and none of this branch's files, and git range-diff shows each rebase left the four commits' patches unchanged.
  • OpenVMM, on [DONT REVIEW] microVM: let a platform restore attach an aggregate to a dormant filesystem slot openvmm#4775's head, on Windows. cargo clippy --all-targets and cargo doc --no-deps for virtiofs and openvmm_entry, cargo nextest run --profile agent for both (339 passed), and cargo xtask fmt --fix (clean). The protocol vectors and CPU profiles that nvx-rs copies are unchanged: openvmm_vectors and openvmm_cpu_profiles pass with --ignored.
  • NVX, on Windows. At this head: nvx.py verify, the Markdown link check, ruff check, ruff format --check, pyright for Linux and Windows, and test_microvm_tests.py, test_nvx_tools.py, test_module_diagrams.py, and test_markdown_links.py (913 tests, 45 skipped). At 321888b05, before the review fix and the latest rebases: compileall, the whole validate-nvx unittest list (1,359 tests, 53 skipped; the 18 shell cases of test_setup_azure.py, which need a Linux bash, fail the same way on dev here), test_adversarial.py, test_hosts.py, and the CLI --help checks.
  • Not run locally. Those shell cases; shellcheck and shfmt, which run in Docker, although no checked shell script changed; check-nvx-rs, since nvx-rs doesn't change; and the OpenVMM VMM tests, which cannot reach an aggregate through the management RPC. CI runs all of them.

Notes

Exact NVX head submitted to CI: 4cf5d4afefe4bce1d0dd1b52ca354519ff9deb3b.

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.

🟡 Changes recommended

The refused-restore integrity check omits the workspace, allowing token overwrites to go undetected; workspace comparison and a regression case for mutation during refusal are needed.

1 open issue
What changed in this PR

This PR integrates OpenVMM support for attaching aggregate filesystem exports to dormant slots during platform snapshot restore, addressing #540 and enabling clone exports planned in #857.

Changes:

  • Advances the OpenVMM pin and documents platform-only aggregate attachment rules.
  • Adds a default-suite scenario covering mixed directory/file exports, access policies, invalid attachments, and snapshot integrity.
  • Adds unit coverage and rebalances the KVM, MSHV, and WHP test shards.
File Description
scripts/​test_microvm_tests.py Tests scenario arguments, refusals, guest reports, and integrity checks.
scripts/​nvx_tools/​microvm_tests.py Adds the aggregate restore scenario and untiered-snapshot refusal check.
scripts/​nvx_tools/​microvm_test_scripts/​platform-aggregate-export.sh Checks guest mounts, child types, access policies, and bind mounts.
scripts/​nvx_tools/​microvm_shards.json Includes the scenario and rebalances platform shards.
doc/​usage.md Lists the scenario’s sandbox-control guest requirement.
doc/​run.md Documents direct OpenVMM platform aggregate restores.
doc/​openvmm-upstream-roadmap.md Records the new pin and its two OpenVMM commits.
doc/​ci.md Describes aggregate restore coverage and rejection cases.

Review effort: Balanced

Comment thread scripts/nvx_tools/microvm_tests.py
Pin microsoft/openvmm#4775 at d7892ffa857d4b01aef0ee309969dda3e95fee44,
two commits on d2338ea22, the previous pin, which is the head of
feature/microvm/dev.

A platform snapshot captured without a filesystem keeps the fixed
virtio-fs slot dormant, and its restore could bind only one directory
to it with --mount, although a cold boot attaches several host
directories and files as the children of one aggregate. A template
could therefore give its clones only part of what cold boots export.

The first commit tests that the device takes a dormant slot's state,
whose FUSE session the guest never initialized, into the device of an
aggregate, which then saves the aggregate. The second lets the restore
of a platform snapshot whose slot is dormant attach an aggregate with
--mount-aggregate and its --mount-child options, and their
--mount-deny, --mount-allow, --mount-write, and --mount-owner policy.
The restore builds it with a cold boot's code, so it validates the
children, the policy, and the owner as a cold boot does, and refuses
what a cold boot refuses, before any vCPU runs. The slot's device and
the captured command line, which names no filesystem, do not change,
so OpenVMM exposes no layout and the guest learns of the export from
its host. The dormant slot of a workload-start, instance-checkpoint,
or untiered snapshot still binds only a --mount, a snapshot that
predates the dormant slot binds nothing, and a snapshot that captured
a filesystem still requires exactly that filesystem.

Part of #540

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Record the two commits that the previous commit pins as positions 350
and 351 of the microVM chain, and move the NVX pin to d7892ffa8.

Position 350 tests that the virtio-fs device takes the state of a
dormant filesystem slot into the device of an aggregate. Position 351
lets a platform restore bind an aggregate to the slot that the
snapshot left dormant, with its children, policy paths, and owner,
validated as at a cold boot. They add behavior rather than fix a
mapped commit, and position 351 changes the dormant-slot restore of
PR18's position 113, which position 293 limited to one --mount when it
added aggregates, so they stay unassigned, like positions 346-349.
Note in the table's remarks that assigning them means revisiting that
work. The pin is now 194 commits past the mapped tip.

Positions 348 and 349 are no longer only a proposal:
microsoft/openvmm#4769 merged them, so position 349, d2338ea22, is the
head of feature/microvm/dev. Say so in the scope, and name
microsoft/openvmm#4775 as the proposal of positions 350 and 351.

Part of #540

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
OpenVMM now lets the restore of a platform snapshot bind an aggregate
of host directories and files to the filesystem slot that the capture
left dormant, and Run documented only that a snapshot captured without
a mapping restores with one new --mount.

Add a Platform filesystem exports section beside Platform NIC templates
for direct OpenVMM restores. It shows a template's restore with
--mount-aggregate, --mount-child options of directories and a file,
and a --mount-deny path, and says that OpenVMM validates them as a cold
boot's before any vCPU runs; that the slot's device and the guest's
command line stay as captured, so the guest learns of the export from
its host and mounts and binds it itself; and that other tiers, and
snapshots captured with an export, keep their rules.

The virtio-fs host mapping section's rule for nvx-rs run still holds,
since nvx-rs run restores only snapshots without sandbox blocks, whose
dormant slot takes no aggregate; say so, and link the new section.

Part of #540

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
No test covered a platform restore that binds an aggregate to the
filesystem slot that the capture left dormant, which OpenVMM refused
until the pinned change. Add the platform-aggregate-export microVM
scenario to the default suite.

The scenario captures a platform snapshot with sandbox blocks and
without a filesystem, and restores it with the aggregate of the
filesystem-shares scenario: a read-write workspace and a read-only
tool cache, each with a denied path, a read-write data directory whose
root exposes only its allowed paths and whose notes alone are
writable, and a read-only and a read-write file, each without its
directory. The clone keeps its captured command line, which discovers
the slot but names no filesystem, so its guest checks that no
virtfs_ or nvx_share= token appeared, mounts the aggregate itself, and
finds its five children in the read-only root that only root can
enter. It checks each child's kind, mode, and policy through that
root, and binds a directory and a file child where it needs them, and
the host then requires exactly the writes that the policy admits.

Before the guest runs, OpenVMM must refuse the restores whose
aggregates a cold boot refuses: overlapping directories, a file inside
a directory child, a directory as a file and a file as a directory, a
repeated name, a policy path of a file child, one outside every
child, and a relative one, and on a Windows host caller ownership. A
refused restore must print none of the guest's lines, and no restore
may change the snapshot or the shared trees. filesystem-snapshot also
requires OpenVMM to refuse an aggregate for the dormant slot of its
untiered snapshot, which still binds a --mount, since only a platform
snapshot's dormant slot binds an aggregate.

The scenario shares the filesystem-shares scenario's trees, so their
creation moves into _create_shared_trees. It needs sandbox blocks, so
it runs only with the Alpine sandbox-control guest, like
platform-filesystem. In the default suite, it took 3.4 s on bare-metal
KVM, 4.5 s on MSHV, and 9.1 s on WHP, so each backend's shards are
planned again with its time, which CI's duration reports replace once
CI has run it. It joins shard 2 on KVM and MSHV and shard 1 on WHP, and
the planner moves command-line-limit on KVM, swaps platform-zero-fill
and restore-memory on MSHV, and moves virtio-net on WHP. The default
suite passed on each of those hosts. With the unpatched OpenVMM of the
latest development release, d2338ea22, the capture succeeds and the
clone's restore fails at "a dormant-slot snapshot can attach only a
--mount on restore".

Unit tests cover the guest's checks, the capture and the restore's
arguments, each refusal's aggregate against the host's trees, the
Windows-only refusal, a missing report, a guest failure, writes beyond
the policy, and the snapshot's and trees' integrity. doc/ci.md
describes the scenario, and doc/usage.md lists it among the scenarios
that need the sandbox-control guest.

Part of #540

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/issue-540-logical-commits-pr-guidelines branch from 7c9bcb6 to 4cf5d4a Compare October 28, 2026 02:06
Copilot AI balanced review requested due to automatic review settings October 28, 2026 02:06

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.

🔵 Needs a closer look

The OpenVMM pin changes snapshot-restore admission and pre-vCPU filesystem-policy enforcement across KVM, MSHV, and WHP, requiring human confirmation of the restore boundary and exact-head platform CI evidence.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

This branch has not been deployed

No deployments
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.

microvm: at a platform restore, attach an aggregate export to the dormant filesystem slot

2 participants