Skip to content

nvx-rs slimming, phase 2.2: a VM's lifecycle: create, spawn, stop, exits and reattach #1080

Closed
2 of 2 issues completed

Description

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

Goal. A caller creates a VM in a private directory with fixed, documented names; inspects it, or hands it to its own launcher; spawns it with no child left behind on failure; stops it only with a confirmed exit; proves an exit after its own restart; and verifies and reattaches a running VM from values that it saved.

Today (dev e42b1795) and after:

Area Today After
VM directory Store-owned layouts: SandboxStore uses fixed internal names, but callers get no public VM directory or outputs. VmDir, created private (0700, or an owner-only protected DACL) by host::vm::create_private_dir, with fixed, documented names. VmOutputs names the log, the outcome report, the control endpoint and the console. nvx generates the Capability and returns it, and never writes it; its Debug is redacted, and as_bytes gives its bytes.
Launch A store-coupled supervisor. host::vm::create returns Prepared (the capability, the outputs, the handles to inherit, the opened log and the arguments), then host::vm::spawn returns Launched. A cold create(from: None) requires VmConfig::boot. InheritedHandle owns each handle added through Prepared::inherit, with conversions from the platform's owned descriptor or handle. A caller can instead turn Prepared into a VmmCommand with into_command(), for its own launcher.
Restore-ready event Inside the clone path. protocol::restore_ready::parse_ready_event parses OpenVMM's exact restore-ready event. restore::ReadyListener, with into_std, is a socket in the VM directory on Linux or a pipe on Windows, and accepts only the VM's process. #1081 binds it before a restore's spawn.
Stop Through the store. host::vm::stop returns Stopped { self_exited, forced, report } only after a confirmed exit; otherwise it fails with the error kind StillRunning.
Exits Process::wait returns a bool. Process::wait(deadline) returns Option<Exited>; Process::open returns Opened::{Running, Exited}; Process::exit_handle gives async callers a duplicated pidfd or process handle, or none when the host only polls; and report::read returns Result<Option<Report>>.
Reattach Through the sandbox store. host::vm::{SavedVm, verify, reattach, Reattached}, with the runtime identity check: verify checks the identity and the process without connecting, and reattach then connects and attaches; another runtime is an error of the new kind RuntimeMismatch. host::transport::{Transport, connect_verified, HostConnection} checks who serves the endpoint before it attaches.

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

Group issue Delivers PRs Needs
#1099 A VM is created in a private directory, with its restore-ready listener, then spawned SL2.7, SL2.8, SL2.8b, SL2.17, SL2.9 #1091, #1098
#1100 A VM stops only with a proved exit, and can be reattached SL2.9a, SL2.10, SL2.10b, SL2.11a, SL2.11b #1099

Notes.

  • The Windows spawn lock is private to host::vm::spawn. A Windows caller must not start other processes while a VM starts, for example by holding its own lock around host::vm::spawn and its other spawns.
  • No half-made VMs. A failed create removes what it made; if spawn fails, no child is left running; if it succeeds, the caller owns a VM that outlives it.
  • Persist what recovery needs before the spawn. nvx never writes the Capability. A caller that recovers or reattaches journals Prepared::capability() and Prepared::outputs() before the spawn, then records the process reference once the spawn succeeds.
  • In-place changes update their callers. Process::wait and report::read change their signatures in place; a crate-private wait keeps the old wrappers stable until their callers go in phase 4.
  • Restores come later. create refuses from: Some until nvx-rs slimming, phase 2.3: one snapshot type, activation record v2, and restores that the caller drives #1081.

Tests. Unit tests of the directory's checks, reserved names and private creation, on both platforms; Capability::as_bytes, its redacted Debug, and no capability file written. A failed create removes everything that it made, and a failed spawn leaves no child. A cold create(from: None) refuses a missing Boot; Prepared::into_command hands over the opened log and the inherited handles without reopening them. stop returns Stopped only after a confirmed exit, and fails with StillRunning when it can't confirm one; an unreadable or malformed outcome report is an Io error in Stopped::report, and a missing one is Ok(None). Process::wait returns None at its deadline, and an Exited proof after the exit; Process::open returns Exited when the recorded process is gone, its ID now belongs to a process with another start time, or the boot has changed; exit_handle gives a duplicated handle, or none on a host that only polls. connect_verified refuses an endpoint that another process serves, and verify and reattach refuse another runtime with RuntimeMismatch, and verify connects to nothing. protocol::restore_ready accepts the exact event and refuses malformed input; ReadyListener::into_std hands the listener over; and, on Linux and Windows, the listener refuses a client that isn't the VM's process. A compiled example launches a cold VM through an external launcher.

Done when: every group issue is closed.

Activity

  1. ppenna commented on Nov 11, 2026

    @ppenna
    Contributor

    Both groups of this subphase are complete and closed: #1099 (SL2.7, SL2.8, SL2.8b, SL2.17, SL2.9) and #1100 (SL2.9a, SL2.10, SL2.10b, SL2.11a, SL2.11b). Every PR has merged into feature/nvx-refactor, whose post-merge CI run at 394c89025e passed: https://github.com/microsoft/nvx/actions/runs/42952780739. Closing the subphase as complete.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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