Skip to content

nvx-rs slimming, phase 2.3: one snapshot type, activation record v2, and restores that the caller drives #1081

Closed
3 of 3 issues completed

Description

Parent: #1076. Phase: 2, the new interface, beside the old one. Needs: #1077; inside phase 2, groups of #1079, #1080 (see the table below). Unblocks: inside phase 2, groups of #1082; #1084, #1086, #1087, #1090.

Goal. The activation record carries only what the guest applies. A snapshot has one strict directory format; a capture VM launches from VmConfig and its CaptureConfig, and a finished capture leaves the snapshot's three entries. A VM restores from a snapshot through host::vm::create(from: Some), and a sans-I/O restore machine holds every rule of a restore, which the caller drives with its own I/O.

Today (dev e42b1795) and after:

Area Today After
Activation record v1, with the template reference (its store generation and key identity), the image's and the scratch's binding identities, the export's plan identity, the network's policy identity, and the workload identity. v2: the root (Fresh only), which keeps the image's expected EROFS UUID or GPT disk GUID but none of the image's or the scratch's binding identities; the view, the export with its mapping count, the network, the expected resources and the transaction ID. VERSION is 2, so an old record fails closed.
Snapshot format Each generation of the template store keeps key.bin beside snapshot/, which holds OpenVMM's manifest, memory and state. host::snapshot: Snapshot::{open, key, manifest, accepts, nic}, SnapshotKey, SnapshotManifest and the public time types. A snapshot holds exactly key.bin, snapshot.json (informational) and openvmm/{manifest.bin, memory.bin, state.bin}; open requires regular files private to their owner, the lengths that the manifest records, and a key consistent with the manifest, and never reads snapshot.json. The caller keeps a finished snapshot immutable and private.
Capture A capture transaction of the template store. host::vm::create with boot.capture launches a blockless VM only, and refuses an export; it creates the placeholder image and the dormant scratch as sparse files and records their verified geometry, has OpenVMM write the capture to <vm_dir>/openvmm, attaches the NIC under the deny-all policy, and gives a cloneable, serializable CaptureContext (the checked capture configuration, the VM's devices, the runtime identity, the hypervisor and the CPU profile) through Prepared::capture_context, which the caller persists if it may finish the capture after a restart. After a proved exit, snapshot::finish_capture(&VmDir, &CaptureContext, &Exited) runs the post-exit checks, writes key.bin and snapshot.json beside openvmm/ in the VM directory, and returns CapturedSnapshot; the caller moves those three entries into its own private, immutable snapshot directory, without the VM directory's other files. Finishing can be retried after a failure that left the VM directory intact.
Restore CloneControl and the clone launch. host::vm::create(from: Some) refuses boot, checks Snapshot::accepts, builds the hard-linked restore view, renders the restore arguments, uses the snapshot's NIC and a compatible console attachment, and binds the ready listener before any spawn; Launched::ready and VmmCommand::ready carry the listener. Prepared::{activation_record, nic} resolve against the snapshot. restore::{RestoreMachine, RestoreInput, RestoreAction} stops at Ready, and RestoreError reports the facts and their attribution. A failed restore leaves the VM's process to the caller.

Groups, in order. Each group issue lists its PRs, with their goals, contents, Needs and estimates.

Group issue Delivers PRs Needs
#1101 Activation record v2 carries only what the guest applies SL2.5a, SL2.5b, SL2.6 #1091, #1097, #1099
#1102 Snapshots have one strict format, and a capture finishes into it SL2.12a, SL2.12b, SL2.12c, SL2.13, SL2.14 #1097, #1099, #1100
#1103 A VM restores from a snapshot, through a sans-I/O restore machine SL2.15, SL2.16, SL2.18a, SL2.18b #1099, #1101, #1102

Notes.

  • Concurrent restores of one snapshot. On Linux, OpenVMM checks the snapshot files' ctime, so the hard links that a restore uses must not change while a restore of them starts. The caller holds a per-snapshot lock from create(from: Some) through the restore-ready event or the VM's verified exit, and around removing a restore's openvmm/. A restore whose caller dies can't complete, since OpenVMM checks the files before it connects the restore-ready endpoint, once, so no durable record of it is needed. NVX documents the rule and holds no lock; Windows needs none. SL2.15 proves it on real VMs; if it fails, OpenVMM must first learn to restore from any location.
  • A Fresh capture VM is blockless. It refuses an export, renders exactly one nvx_snapshot_tier=platform token and no root, view, mapping or workload tokens, and accepts only the tokens of OpenVMM's platform allowlist.
  • The restore machine has no clock. The caller feeds Expired, Cancelled, its own I/O failures (OperationFailed) and the VM's verified exit (Exited), and decides whether to connect again after SessionLost. Both connections check their peer against the VM's process.
  • Record v2 is prepared first. Before the codec changes, every reader of what v2 drops stops reading it: reattaching a clone checks its template through the clone record; the guest's apply no longer extracts, checks or propagates the workload identity, and Applied no longer returns it; the test adapter's readers and tests follow.
  • No alpha.7 compatibility. The activation record's VERSION becomes 2; the snapshot key's encoding changes without a version bump; and the release reads no alpha.7 record, key or snapshot.

Tests. Codec and fixture tests of record v2, on the host and in the guest; a v1 record fails closed. The image's optional expected EROFS UUID or GPT disk GUID still round-trips, and the guest still refuses an image that doesn't match it. Snapshot::open refuses missing, extra, irregular or non-private entries, wrong lengths, a malformed manifest and a key that doesn't match the manifest, and never trusts snapshot.json. accepts, criterion by criterion: the layered root; processors and memory between the boot size and the capacity, counts of 1, 2, 4 or 8, and 128 MiB alignment; the image's and the scratch's geometry; the NIC's presence and address; the console; the backend, the CPU profile, the runtime and the time. The capture launch: the blockless rule, the refused export, the sparse files' geometry, the token allowlist, the NIC under deny-all, and a CaptureContext that round-trips through serde with all of its checked values; finish_capture's checks and its retry. Restore creation refuses boot, fails clearly when the restore view would cross filesystems, keeps the snapshot's NIC and console rules, and binds the ready listener before the spawn; the compiled external-launcher example restores. The restore machine: the same record on every session, the transaction echo, a new connection after SessionLost, OperationFailed, Expired, Cancelled, Exited in every pending phase, the end at Ready, and each fact of RestoreError. A failure returns the error without stopping the VM; the process stays the caller's. SL2.15's gate on real Linux VMs: restores of one snapshot start while views are added and removed under the lock; a link change without the lock fails a starting restore; a controller killed before OpenVMM connects the restore-ready endpoint leaves a VMM that fails that connect and exits; and once OpenVMM has connected it, a link change no longer fails the restore.

Done when: every group issue is closed.

Metadata

Metadata

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions