Skip to content

feat!: support systemd 259 with raw VM disks - #55

Merged
bketelsen merged 1 commit into
mainfrom
claude/systemd-version-requirement-504ee8
Oct 8, 2026
Merged

bketelsen merged 1 commit into
mainfrom
claude/systemd-version-requirement-504ee8

Conversation

@bketelsen

@bketelsen bketelsen commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Lowers nsl's host floor from systemd 261 to 259, the version Fedora 44 and Ubuntu 26.04 LTS ship. No stable distribution ships 260, so 259 is the useful floor. Closes #54.

Do not merge until a Fedora 44 acceptance run passes. The 259 floor rests on vmspawn 259.9's source. No 259 host has run it yet, and 259 starts virtiofsd differently from 260 and later.

Changes

  • Launch flags. Launch passes only flags vmspawn 259 accepts:
    • --user is dropped. The launch namespace (unshare --map-current-user) keeps the user's UID, so vmspawn already runs in the user's service manager.
    • --image-format and the qcow2:virtio-blk: drive prefix are gone.
  • Raw disks. vmspawn 259 attaches no other format.
    • root.raw is a FICLONE clone of the cached image. Without shared extents, it is a copy that skips holes and zero blocks. Either way it is extended to 16 GiB, synced and renamed into place.
    • data.raw is a sparse file that grows by extension. Growth still records its target first and resumes after an interruption.
    • The data disk checks are ownership, type, mode and exact size. The qcow2 header parsing and every qemu-img call are gone, so qemu-img is no longer a prerequisite.
  • doctor and launch refuse a vmspawn older than 259 and name both versions. Launch refuses before changing any state.
  • Firmware. doctor reads the descriptors --firmware=list returns, in order, and applies the selection rules systemd 259 to 262 share. vmspawn 259 has no --firmware=describe.
  • Docs. ADR-0005 records the floor, the disk format and the alternatives. ADR-0008, the CLI and VM image specs, the lifecycle design, the site, the README and the implementation plan are updated to match.

Breaking change

State directories created before this change hold root.qcow2 and data.qcow2, and nothing migrates them. With this build, a VM from such a directory boots on a new blank data.raw and fails readiness; the old disks are left untouched. To keep a VM, convert its data disk while the VM is stopped:

qemu-img convert -f qcow2 -O raw data.qcow2 data.raw && chmod 600 data.raw

Validation

Host: systemd 262 (262-1), kernel 7.2.8, QEMU 10.0.13, virtiofsd 1.13.2, NVMe btrfs. VM image r10.

  • make ci and make site
  • probe-vm.py: all nine checks pass with raw disks and no --user
  • probe-machines.py --isolated with Debian r5, Fedora 44 r4 and an isolated Debian machine: every check passes except one item. In Fedora's tally, reinstalling tzdata failed because the cached r4 image's version has left Fedora's repositories; its time-zone link was correct.
  • doctor picks /usr/share/OVMF/OVMF_CODE_4M.fd, the same firmware as vmspawn 262's --firmware=describe --secure-boot=no
  • Root cost: the clone takes 130 µs. The fallback copy takes 0.34–0.39 s and allocates 965 MB; writing every block would take 0.7 s and 2.7 GB.
  • Fedora 44 (systemd 259.9): probe-vm.py and probe-machines.py --isolated, covering virtiofs shares, the read-only image cache, update, recover, resize and an isolated machine
  • Ubuntu 26.04 on ext4: time recover for the shared VM and an isolated machine

🤖 Generated with Claude Code

vmspawn 259, which Fedora 44 and Ubuntu 26.04 LTS ship, lacks --user,
--image-format and disk formats in --extra-drive; 261 added
--firmware=describe. Launch now passes only flags 259 accepts (ADR-0005):

- --user is dropped: the launch namespace keeps the user's UID, so vmspawn
  already runs in the user's service manager.
- The root is root.raw, a FICLONE clone of the cached image or a copy that
  skips holes and zero blocks, extended to 16 GiB. The data disk is a sparse
  data.raw that grows by extension; growth still records its target first
  and resumes. qemu-img is no longer a prerequisite.
- doctor and launch refuse a vmspawn older than 259 and name both versions.
  doctor then finds firmware through --firmware=list and the selection rules
  systemd 259 to 262 share.

probe-vm.py and probe-machines.py --isolated pass on systemd 262. A Fedora 44
acceptance run is still required before a release claims 259.

BREAKING CHANGE: VM disks are raw. State directories with root.qcow2 and
data.qcow2 are not migrated: convert data.qcow2 with
`qemu-img convert -f qcow2 -O raw` before starting their VM.

Refs #54

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@bsherman bsherman 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.

Approving after a Fedora 44 acceptance run of d0cd063.

Host: Fedora 44, systemd 259.9-1.fc44, kernel 7.2.8, btrfs, QEMU and virtiofsd from the Fedora packages. Image: VM r10 and Debian trixie machine r5, both from the cache.

Build and doctor

  • make build and go test ./... pass. I did not run make ci.
  • nsl doctor exits 0 and reports OK systemd 259. It picks /usr/share/edk2/ovmf/OVMF_CODE_4M.qcow2, and qemu-img is no longer listed.

probe-vm.py: all nine checks pass (readiness, formatting, allowlist, ownership, sockets, root replacement, growth, refusal, binding). Boot takes about 8 s. virtiofs shares and the read-only image cache work, so virtiofsd under systemd-socket-activate and the LISTEN_FDS fd passing both work on 259.9.

probe-machines.py --isolated: one Debian trixie machine and one isolated machine. Every check passes except broker on the normal machine. There, nsl-open reports "no desktop session" because waypipe is not installed on this host, which doctor flags as optional. This is not related to this change. Persistence passes for both machines after a VM restart.

Manual resize and recover with a live machine

  • Data disk 128 → 160 GiB. data.raw grows by extension, stays sparse, and the guest filesystem grows on the next start.
  • recover makes a fresh root.raw, and the data disk, machine and keys are unchanged. A marker file survives both.
  • resize --disk 40 is refused with "shrinking the data disk is not supported".

Not covered: Ubuntu 26.04 on ext4, and the recover timing there.

With the Fedora 44 items ticked, I have no objection to merging.

@bketelsen
bketelsen merged commit 14293a7 into main Oct 8, 2026
4 checks passed
@bketelsen
bketelsen deleted the claude/systemd-version-requirement-504ee8 branch October 8, 2026 20:09
bketelsen added a commit that referenced this pull request Oct 9, 2026
The plan still listed the Fedora 44 run as required. bsherman ran it on
systemd 259.9 against d0cd063 before #55 merged: probe-vm.py passed all nine
checks, probe-machines.py --isolated passed but for broker on a host without
Waypipe, and manual growth, recover and shrink refusal behaved. Only the
Ubuntu 26.04 ext4 timing stays open.

Refs #54

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

doctor: check the required systemd version and fail when it is not met

2 participants