Skip to content

openvmm: pin refusing a FIFO snapshot artifact without waiting - #1424

Merged
Pedro Henrique Penna (ppenna) merged 3 commits into
devfrom
agents/issue-1154-fifo-artifact
Nov 10, 2026
Merged

Pedro Henrique Penna (ppenna) merged 3 commits into
devfrom
agents/issue-1154-fifo-artifact

Conversation

@ppenna

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

Copy link
Copy Markdown
Contributor

Fixes #1154

What and why

On Linux, a FIFO without a writer in place of a snapshot's manifest.bin,
state.bin, memory.bin, or paired scratch.img made a restore wait
forever, before it validated anything or claimed a resume snapshot: OpenVMM's
--restore-snapshot, and a management-RPC CreateVm with a restore_path,
never returned.

Root cause: OpenVMM opens each artifact without following a final link and
then checks the type of the file that it opened.
OpenedSnapshotDirectory::open_regular_file
(openvmm_helpers/src/snapshot/fs.rs) opened it with
openat(O_RDONLY | O_CLOEXEC | O_NOFOLLOW), and a read-only open of a FIFO
waits, in the kernel's wait_for_partner, until a writer opens the FIFO, so
the open never returned to the check. The path-based open_regular_file_impl,
which the claimed scratch link and write_snapshot's memory backing file use,
waited the same way.

microsoft/openvmm#5004, openvmm_helpers: refuse a FIFO artifact without waiting for a writer, opens artifacts with O_NONBLOCK in both Unix openers,
so that the open of a FIFO returns at once and the existing check refuses it
like any other file that is not a regular file: "<artifact> is not a regular
file". A new accept_opened_regular_file, which both openers call, makes that
check and then clears O_NONBLOCK on a regular file's descriptor, since the
handles outlive validation: as restore guards, as the descriptor that the VM
worker maps as RAM, and as the scratch source. Windows needs no change: NTFS
holds no FIFOs, and the AF_UNIX sockets and WSL FIFOs that it can hold are
reparse points, which the relative open opens as themselves, without waiting,
and refuses. OpenVMM's snapshot format guide says that Linux opens artifacts
with O_NONBLOCK.

Commits:

Decisions:

cba21d109 is the commit that the validation before this restack tested,
904a33c32 on d501e5066, rebased onto ac3dc27a7: git range-diff shows
the patch identical, and of its three files, the commits between change only
fs.rs, where position 234 changes the publication's rename.

Stack

This is layer 2 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. Layer 1 has landed, so this pull request now targets
dev, and microsoft/openvmm#5004 and microsoft/openvmm#5005 now target
feature/microvm/dev.

Layer NVX pull request (base) Issue OpenVMM pull request (base) Pinned OpenVMM revision
1, merged #1423 (dev) #1364 microsoft/openvmm#5003 (feature/microvm/dev), landed ac3dc27a7, position 236
2, this one #1424 (dev) #1154 microsoft/openvmm#5004 (feature/microvm/dev) cba21d109, position 237
3 #1425 (agents/issue-1154-fifo-artifact) #1138 microsoft/openvmm#5005 (feature/microvm/dev) 46bfe02ed, position 238
4 #1427 (agents/issue-1138-input-gate-lock) #544, part 2 none 46bfe02ed, layer 3's

Landing order, bottom first, one layer at a time; each OpenVMM pull request
lands before its NVX pull request merges:

  1. Land [DO NOT REVIEW] openvmm_helpers: compute memory-expansion ranges without overflow openvmm#5003 by fast-forwarding feature/microvm/dev to
    ac3dc27a738808d38e1148d3caefc5e89111ee32, since OpenVMM's merge button
    squashes 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 this pull
    request to dev.
  2. Retarget [DO NOT REVIEW] openvmm_helpers: refuse a FIFO artifact without waiting for a writer openvmm#5004 to feature/microvm/dev
    (gh pr edit 5004 --repo microsoft/openvmm --base feature/microvm/dev),
    fast-forward feature/microvm/dev to
    cba21d109eeb99fbc573c79b2ed9f4754f734b25, and merge this pull request.
  3. Retarget [DO NOT REVIEW] vmotherboard: gate a device's input without closing it to the vCPUs openvmm#5005 the same way, fast-forward
    feature/microvm/dev to 46bfe02ed65697e858f66ce55eb60831b3ac3461, and
    merge openvmm: pin input gating that keeps devices open to the vCPUs #1425.
  4. Merge nvx-rs: activate a clone from its restore packet's record #1427, which moves no pin.

Validation

Before this restack, with OpenVMM 904a33c32 (the same patch on d501e5066)
for "after":

Check Profile Backend, build Host type Before After
End to end: a FIFO in place of each of the four artifacts of a workload-start and an instance-checkpoint snapshot, then a restore with a 30 s bound (8 cases) nvx-kvm-test kvm, glibc virtual machine release v0.1.0-dev.a0173e7b7d97 (OpenVMM 6cb6ba87c): 8 of 8 wait in wait_for_partner until killed 8 of 8 exit with status 1 in 0.01 s, "<artifact> is not a regular file"; none claims the checkpoint
The same nvx-mshv-test mshv, musl virtual machine 8 of 8 wait until killed 8 of 8 exit with status 1 in 0.01 s; none claims the checkpoint
An AF_UNIX socket, a reparse point, in place of the manifest, state, or memory file, and a directory in place of manifest.bin local workstation Windows - that release refuses each at once, in 0.03-0.05 s: no wait on Windows unchanged
artifact_opens_refuse_a_writerless_fifo_without_waiting, restore_refuses_a_writerless_fifo_artifact_without_waiting nvx-kvm-test, nvx-mshv-test glibc, musl virtual machine without the O_NONBLOCK flags, both fail after their 10 s bound pass
openvmm_helpers local workstation; nvx-kvm-test; nvx-mshv-test Windows; glibc; musl -; virtual machine - 123 of 123; 131 of 131; 131 of 131
test-microvm --scenario snapshot-tiers --scenario scratch-snapshot --processors 1 nvx-kvm-test; nvx-mshv-test; local workstation kvm; mshv; whp virtual machine; virtual machine; - - pass

On nvx-kvm-test, removing only the directory-relative flag failed both new
tests; only the path-based flag, the opener test; and only the clearing of
O_NONBLOCK, the opener test's flag assertion. The nvx-rs vector and CPU
profile comparisons passed against 904a33c32.

Rerun for this restack, at OpenVMM cba21d109 and this head:

  • OpenVMM, Rust 1.97.1: cargo nextest run --profile agent -p openvmm_helpers,
    127 passed on Windows, where the new tests do not build, and 135 on Linux
    (nvx-kvm-test, glibc), both new tests among them; cargo clippy --all-targets and cargo doc --no-deps for openvmm_helpers, and
    cargo check --all-targets on Linux, without warnings; cargo xtask fmt at
    the stack's top OpenVMM head, 46bfe02ed, clean.
  • NVX: python scripts/nvx.py verify; python scripts/local_gates.py --base <layer 1's head> --only test-changes markdown-links test-layout openvmm-vectors openvmm-cpu-profiles --run, all passed, with no change to an
    existing test and the 4 vector and 1 CPU-profile comparisons passing against
    cba21d109; python scripts/openvmm_pin.py check-roadmap --worktree and
    check-branch --topic --target <layer 1's head>, passed. After the rebase,
    git range-diff shows this layer's three commits unchanged from those that
    the 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 verify lists only
    layer 1's commits, now in the base, as dropped.

At the exact pin, cba21d109, and this head, 15a8a836c, for marking ready:

Check Profile Backend, build Host type Result
End to end, the same 8 cases: a writerless FIFO in place of each of manifest.bin, state.bin, memory.bin, and scratch.img of a workload-start and an instance-checkpoint snapshot, captured with the snapshot-tiers scenario's commands, then its restore command bounded at 30 s; OpenVMM built in a worktree of this head with build-openvmm, guest artifacts from this head's CI run nvx-kvm-test kvm, glibc virtual machine 8 of 8 exit with status 1 in 0.01 s, "snapshot manifest", "saved state", "snapshot memory", or "scratch.img is not a regular file"; none claims the checkpoint, and every other payload is unchanged
The same nvx-mshv-test mshv, musl virtual machine 8 of 8 exit with status 1 in 0.01-0.66 s, with the same messages; none claims the checkpoint, and every other payload is unchanged
OpenVMM's CI of the pin, run 42731957734 - - - the 6 jobs that check-openvmm-ci requires passed; unit tests [x64-linux] ran 6414 tests, both new FIFO tests among them, all passed
CI of this head, run 42741003559 CI runners kvm; mshv; whp virtual machine passed: snapshot-tiers and scratch-snapshot passed on each backend with OpenVMM built at the pin, as did OpenVMM CI of the pinned revision, NVX CLI on Linux and Windows, the rest of the microVM matrix, the performance regression gate, and Required status check

Windows needs no new end-to-end case: the pin adds O_NONBLOCK only to the
Unix openers, and the Windows type check that refused the socket, reparse
point, and directory cases above is unchanged. The merge group tests this
pull request again, merged into the latest dev.

Pins cba21d109eeb99fbc573c79b2ed9f4754f734b25, the head of
microsoft/openvmm#5004, one commit on ac3dc27a7, the head of
microsoft/openvmm#5003, on which it stacks, which follows b4028c1aa,
the head of feature/microvm/dev:

- cba21d109 openvmm_helpers: refuse a FIFO artifact without waiting for
  a writer

A FIFO without a writer in place of a snapshot's manifest.bin,
state.bin, memory.bin, or paired scratch.img made restore wait forever
before it validated anything (#1154). OpenVMM opened each artifact
without following a final link and only then checked the type of the
file that it opened, and a read-only open of a FIFO waits until a
writer opens it.

The pinned revision opens artifacts with O_NONBLOCK on Unix, so it
refuses such a FIFO at once, with "<artifact> is not a regular file",
before a restore can claim a resume snapshot, and then makes a regular
file's descriptor blocking again. Windows is unchanged: its relative
opens never wait for a file's type. The protocol vectors, the excerpts
and contract versions that nvx-rs copies from OpenVMM, and its CPU
profiles match the revision's.

With 904a33c32, the same patch on d501e5066, on nvx-kvm-test and
nvx-mshv-test (KVM and MSHV virtual machines), a FIFO in place of each
artifact of a workload-start and an instance-checkpoint snapshot made
the OpenVMM of release v0.1.0-dev.a0173e7b7d97, at 6cb6ba87c, wait in
the kernel's wait_for_partner until it was killed 30 s later, while
the fix's glibc and musl builds exited with status 1 and that error
within 0.01 s; none of the 32 restores claimed the instance
checkpoint. On Windows, an AF_UNIX socket, which is a reparse point, in
place of each artifact made that release's openvmm.exe refuse it at
once, so WHP had no such wait. The snapshot-tiers and scratch-snapshot
scenarios passed with it on KVM, MSHV, and WHP.

Tests: OpenVMM's openvmm_helpers tests pass at the pinned revision,
135 of 135 on Linux (glibc) and 127 of 127 on Windows, as they did at
904a33c32, 131 of 131 on Linux, glibc and musl, and 123 of 123 on
Windows, where the two new ones failed without the change. The
openvmm_vectors and openvmm_cpu_profiles comparisons pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The validation section of the snapshot artifact model said that Linux
hosts open a snapshot's artifacts without following symbolic links.
With the previous commit's pin, they open them without waiting too, so
a FIFO in place of an artifact, which a blocking open would wait on
until a writer opened it, is refused for its type, as any other file
that is not a regular file is, instead of holding restore forever
(#1154).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Maps NVX's new pin, cba21d109, the head of microsoft/openvmm#5004, at
position 237, after position 236, ac3dc27a7, the head of
microsoft/openvmm#5003, on which it stacks, which follows position 235,
b4028c1aa, the head of feature/microvm/dev. The pin is 106 commits past
the mapped tip, and positions 132-237 stay unassigned.

Position 237 changes the artifact openers of the snapshot file system
module that PR11's position 032 adds, with the path-based opener and
the type check, and its position 033 extends with the
directory-relative opener, through which PR12's position 035 restores:
on Unix both now open with O_NONBLOCK, so that the type check refuses
a FIFO without waiting for a writer, and then make a regular file's
descriptor blocking again. It adds tests beside positions 032's and
035's, and extends the restore paragraph that PR12's position 036 adds
to the snapshot format guide. Replaying it on upstream main conflicts
in all three of its files, since upstream main lacks the file system
module of position 032, the directory-relative restore of position 035,
and that paragraph, so it follows PR11, PR12, and PR19 upstream.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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

Snapshot-tiers, scratch-snapshot, and end-to-end FIFO acceptance checks remain outstanding for OpenVMM pin cba21d109 on KVM, MSHV, and WHP, requiring runtime evidence before landing.

No open issues 🎉

What changed in this PR

This PR integrates OpenVMM’s fix for #1154 so Linux snapshot restores reject writerless FIFO artifacts instead of hanging. The reviewed documentation describes the behavior and records the new pin’s upstream dependencies.

Changes:

  • Document prompt rejection of FIFO snapshot artifacts while preserving existing descriptor and identity checks.
  • Update the OpenVMM roadmap to pin cba21d109 at position 237 and map its changes and upstream prerequisites.
File Description
doc/​openvmm-upstream-roadmap.md Records the new pin, chain counts, and upstream mapping for FIFO rejection.
doc/​design/​5.4-snapshot-artifact-and-attachment-model.md Explains that Linux refuses FIFO artifacts without waiting for a writer.

Review effort: Balanced

@ppenna

Copy link
Copy Markdown
Contributor Author

On the overview's note that the snapshot-tiers, scratch-snapshot, and end-to-end FIFO checks remained outstanding at the pin: no change needed here; they have now run at the exact pin, cba21d109, and this head, 15a8a836c, and passed.

  • End to end, on nvx-kvm-test (kvm, glibc) and nvx-mshv-test (mshv, musl), with OpenVMM built at cba21d109 in a worktree of this head and this head's CI guest artifacts: a writerless FIFO in place of each of manifest.bin, state.bin, memory.bin, and scratch.img of a workload-start and an instance-checkpoint snapshot, captured with the snapshot-tiers scenario's commands, then its restore command bounded at 30 s. 8 of 8 on each host exit with status 1 in 0.01-0.66 s with "... is not a regular file"; none claims the checkpoint, and every other payload is unchanged.
  • CI run 42741003559 of this head passed, with snapshot-tiers and scratch-snapshot passing on KVM, MSHV, and WHP with OpenVMM built at the pin.
  • OpenVMM's CI of the pin, run 42731957734, passed the 6 jobs that check-openvmm-ci requires; its unit tests [x64-linux] job passed both new FIFO tests.
  • WHP needs no new end-to-end case: the pin adds O_NONBLOCK only to the Unix openers, and the Windows type check is unchanged.

The Validation section now records these results.

@ppenna
Pedro Henrique Penna (ppenna) added this pull request to the merge queue Nov 10, 2026
Merged via the queue into dev with commit 9904566 Nov 10, 2026
90 checks passed
@ppenna
Pedro Henrique Penna (ppenna) deleted the agents/issue-1154-fifo-artifact branch November 10, 2026 03:01
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.

openvmm: a writerless FIFO snapshot artifact hangs restore before validation

2 participants