Repository navigation
nvx-rs: reread a clone's GPT partition table and require a fresh upper - #957
Pedro Henrique Penna (ppenna) merged 3 commits into
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
The guest-only snapshot lacks end-to-end restore coverage for the privileged partition reread, leaving #961’s GPT and used-upper VM scenarios and validation on KVM, MSHV, and WHP unconfirmed.
No open issues 🎉
What changed in this PR
This PR implements the guest-side portion of #845’s GPT clone activation: refreshing partition devices before root assembly and requiring a fresh upper, while preserving cold-boot scratch reuse. Host-side GPT support and VM scenarios remain in #961 for the final restack.
Changes:
- Add a
BLKRRPARTwrapper and reread GPT partition tables before clone root assembly. - Reject nonempty
upperorworkdirectories during clone activation. - Extend tests and documentation for partition rereads, freshness checks, and activation failure status 54.
| File | Description |
|---|---|
tests/runtime-adapter/tests/guest_session.rs |
Simulate partition rereads and verify activation failures. |
tests/runtime-adapter/src/worker/activation.rs |
Update failure documentation and GPT error tests. |
tests/runtime-adapter/src/worker.rs |
Document GPT rereads and fresh-upper requirements. |
tests/runtime-adapter/README.md |
Describe updated activation behavior and failures. |
nvx-rs/src/guest/sys/mod.rs |
Re-export the partition-table reread wrapper. |
nvx-rs/src/guest/sys/ioctl.rs |
Add and test the BLKRRPART wrapper. |
nvx-rs/src/guest/root/tests.rs |
Test freshness checks, reread errors, and kernel partition refresh. |
nvx-rs/src/guest/root/kernel.rs |
Add real and fake kernel reread operations. |
nvx-rs/src/guest/root/block.rs |
Resolve the distro device and request its partition reread. |
nvx-rs/src/guest/root.rs |
Add clone-only freshness enforcement and typed errors. |
nvx-rs/src/guest/clone/activation/apply/tests.rs |
Verify GPT inputs, reread ordering, and failure handling. |
nvx-rs/src/guest/clone/activation/apply.rs |
Enable GPT assembly after rereading, with a fresh upper. |
nvx-rs/src/guest/clone.rs |
Document the updated clone activation contract. |
nvx-rs/README.md |
Update the library’s clone activation overview. |
Review effort: Balanced
fb968b6 to
8d328fc
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
GPT activation relies on privileged partition-device rebuilding after snapshot restore, and pending KVM, MSHV, and WHP VM suites must confirm layout replacement and used-scratch rejection beyond the supplied loop-device validation.
No open issues 🎉
Review effort: Balanced
8614f20 to
179d982
Compare
1c62dcf to
311deb2
Compare
abe6a88 to
21b9983
Compare
A clone's activation refused a GPT image, since the kernel created the block devices of the disk's partitions when it found the template's placeholder, so they need not be the clone's. It now assembles one: - Before the assembly, nvx::guest::clone::apply asks the kernel to reread the distro disk's partition table with BLKRRPART, once the device appeared, through a new wrapper beside BLKFLSBUF in guest::sys::ioctl. The kernel drops the placeholder's partitions and creates the clone's, with their nodes, from the same read-only bytes that the assembly then reads and checks against the record's disk GUID and first-partition bound, as at a cold boot. A reread that fails, before anything is mounted, is ApplyError::Gpt, which now carries the root::Error, with the new DeviceStep::Reread when the kernel refuses it. - A clone's root must start as its image alone, so its assembly takes a crate-private option that refuses an upper whose `upper` or `work` directory exists and is not empty, with the new root::Error::NotFresh, once the upper is mounted and before the overlay. The check reads the directory's status and at most one entry, and no file's content. A cold sandbox's root::assemble keeps a scratch's upper across boots, as before. Both failures end the runtime adapter's clone with the existing activation status 54, whose documentation already covers them. The adapter's fake session and its README follow the new error. The tests cover the reread before the assembly, its errors, and the freshness check and its bound, without a VM, and an ignored test checks the reread against the kernel with a loop device, as root. The VM tests of a GPT clone come with the restore of clones in VMs. Part of #845 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 80932e09-af82-4b79-b417-70a241303cda
A clone's plan refused a GPT disk as its image before any VMM started: the kernel of a clone's guest had created the block devices of the partitions of the template's placeholder, and no clone rebuilt them. The guest of a GPT clone now asks the kernel to reread the disk's partition table before it assembles the root, so the plan takes a GPT disk as it takes an EROFS layer. The record of a GPT clone names the disk: the identity of its binding, the GUID that the adapter's plan expects of it, and the bound of its first partition, which CloneRequest gains, as first_partition_bound, beside the journal policy. An EROFS layer has no partitions, so the record of a clone of one leaves the bound out. A bound of 0 is a setting that no record holds, and the plan refuses it before it opens anything, as it refuses the request's other Activate settings, with the evidence InvalidActivate. InvalidFormat now names only an image that is not of the format and identity that its binding names. The plan checks a GPT disk as it checks an EROFS layer, from its metadata alone: the check of its binding, and the geometry of the template's placeholder, whatever the placeholder's format. As at a cold launch, the guest reads and checks the partition table with nvx::gpt before it assembles the root, so the host reads none of the disk, and hashes nothing. The test adapter's clone requests bound a GPT disk's first partition by 64 KiB, the default of a launch's guest. Part of #845 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 80932e09-af82-4b79-b417-70a241303cda
A clone's guest rereads a GPT disk's partition table before it assembles the root, and refuses an upper that is not fresh, and the host now plans GPT clones. These VM tests start such clones through runtime-adapter-host start, on the hypervisor. start takes --first-partition-bound BYTES for a GPT disk, as launch does, and clone::Request takes the bound, 64 KiB unless given. In vm_clone, one template, whose placeholder is a GPT disk of two layers, serves four clones at once: the EROFS image over a scratch image and in RAM, a GPT disk of one layer in RAM, and one of three layers over a scratch image, with a bound that its first partition meets exactly. The disks' layer partitions start where none of the placeholder's do, nor each other's, so a clone whose kernel kept the placeholder's partitions would fail its assembly. Each GPT clone's root stacks the layers of its own disk's table, read-only, and returns its own first partition. A disk whose first partition is one byte larger than the bound ends the clone with status 54, as does a scratch image that an earlier clone used, whose upper is not fresh. The GPT writer moves from vm_layered into tests/common/gpt.rs, with the small ext2 layers and the CRC, and writes disks of any layout and length. vm_layered writes the same disks as before through it. Part of #845 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 80932e09-af82-4b79-b417-70a241303cda
311deb2 to
5102663
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
A maintainer must confirm exact-head KVM, MSHV, and WHP VM results for GPT partition replacement after snapshot restore and used-upper rejection, since source-only review cannot validate these privileged kernel behaviors.
No open issues 🎉
Review effort: Balanced
Part of #845 (PR 1 of 3: GPT images and the fresh-scratch check).
Stacked on #954: this PR targets its branch,
esaurez/844-pr5-clones-in-vms-20261025, and is rebased and retargeted with it.Chain: #951 → #954 → this PR → #959 → #960, on
dev; #879, #881, #885, #886, #877, #932, #884, #887, #933, #880, #936, #937, #939, #940, #941, #888, #949, and #950 have merged.What and why
A clone's activation refused a GPT image, since the kernel created the block devices of the disk's partitions when it found the template's placeholder, so they need not be the clone's. It now assembles one, and a clone's plan takes one.
nvx-rs: reread a clone's GPT partition table and require a fresh upper
nvx::guest::clone::applyasks the kernel to reread the distro disk's partition table withBLKRRPART, once the device appeared, through a new wrapper besideBLKFLSBUFinguest::sys::ioctl. It waits for the device as the assembly does, but never past the activation's deadline. The kernel drops the placeholder's partitions and creates the clone's, with their nodes, from the same read-only bytes that the assembly then reads and checks against the record's disk GUID and first-partition bound, as at a cold boot. A reread that fails, before anything is mounted, isApplyError::Gpt, which now carries theroot::Error, with the newDeviceStep::Rereadwhen the kernel refuses it.upperorworkdirectory exists and is not empty, with the newroot::Error::NotFresh, once the upper is mounted and before the overlay. The check reads the directory's status and at most one entry, and no file's content. A cold sandbox'sroot::assemblekeeps a scratch's upper across boots, as before.Both failures end the test adapter's clone with the existing activation status 54, whose documentation already covers them. The adapter's fake session and its README follow the new error.
nvx-rs: restore clones of GPT disks
A clone's plan refused a GPT disk as its image before any VMM started, since no clone's guest rebuilt the partitions that its kernel created for the template's placeholder. With the reread, the plan takes a GPT disk as it takes an EROFS layer:
CloneRequestgains, asfirst_partition_bound, beside the journal policy. An EROFS layer has no partitions, so the record of a clone of one leaves the bound out.InvalidActivate.InvalidFormatnow names only an image that is not of the format and identity that its binding names.nvx::gptbefore it assembles the root, so the host reads none of the disk, and hashes nothing.runtime-adapter: start GPT clones, and refuse a used upper, in VMs
runtime-adapter-host starttakes--first-partition-bound BYTESfor a GPT disk, aslaunchdoes, andclone::Requesttakes the bound, 64 KiB unless given.In
vm_clone, one template, whose placeholder is a GPT disk of two layers, serves four clones at once: the EROFS image over a scratch image and in RAM, a GPT disk of one layer in RAM, and one of three layers over a scratch image, with a bound that its first partition meets exactly. The disks' layer partitions start where none of the placeholder's do, nor each other's, so a clone whose kernel kept the placeholder's partitions would fail its assembly. Each GPT clone's root stacks the layers of its own disk's table, read-only, and returns its own first partition. A disk whose first partition is one byte larger than the bound ends the clone before it is ready, as does a scratch image that an earlier clone used, whose upper is not fresh: status 8, with the record of a failure of the request, by the evidence of an unusable root, with the guest's status 54.The GPT writer moves from
vm_layeredintotests/common/gpt.rs, with the small ext2 layers and the CRC, and writes disks of any layout and length.vm_layeredwrites the same disks as before through it.Not in this PR
Validation
Each commit of this PR, on #954's head 21b9983, with OpenVMM at 832d5bb4, the pin of its base: fmt, Clippy with
-D warningsin every configuration of the library and of the test adapter, and the check thatnvx-rs/README.mdgives each module a short row and a section. At this PR's head:tests/host_modules.rs; the library'shost::templateandhost::storetests; the test adapter's protocol-only tests, and its host tests of the library, the binaries,host_sessionandclone_start.guest::cloneandguest::roottests; the test adapter's musl guest library tests andguest_session; and, as root, the ignored test that checks the partition-table reread against the kernel with a loop device, and, in a process of their own, the privileged tests ofguest::mappings.-D warnings, the MSRV checks of the library and of the test adapter's three configurations, and the Markdown links.At #960's head, the top of the stack, with OpenVMM at 832d5bb4:
-D warningswith all features and on the library with and without default features; the tests with all features and with the default ones; the library without default features; the documentation with-D warnings; and the MSRV check, with the aarch64-apple-darwin check on Linux.guest::mappings, ofguest::clone::activation::apply, and of the partition-table reread with a loop device, each in a process of its own:guest::mappings' privileged tests can find a mount busy at their teardown when another test of the same process starts a child, as they do at runtime-adapter: start clones of templates #954's head.devwere skipped.vm_clone, 16 scenarios, with this PR's two: the GPT clones, and the used upper;vm_layered, 43;vm_restart, 3;vm_steps, 3; andvm_template, 9.