One layout, one name for the image, and a fingerprint that cannot be shifted - #1
Merged
Merged
Conversation
…shifted Three changes, all of them removing a way for two things to disagree. **One layout.** The same four files had three shapes: what the build extracted into _output/, what the tarball carried under usr/share/spin-stack/, and what a consumer rearranged them into — with a translation step between each pair and a discovery function guessing which shape it had been handed. The builds now write the release tree directly, so `_output/` and the tarball are the same shape byte for byte, and `machine.Open` reads either. It checks rather than trusting: a release with a hole in it says which file is missing, instead of surfacing three seconds later as a QEMU that exits for want of an option ROM. That also removes COMPAT_KERNEL_NAME, the symlink hatch that existed so a consumer resolving the kernel under another name would not have to change. **base.qcow2 is rootfs.qcow2.** `base` names the role — a qcow2 backing file — which the directory and the prose already say, and it collides with "base image" in the container sense. `rootfs` names what the file holds. **Fingerprint is length-prefixed.** It hashed `key=value\n` lines whose values are a CPU model, a device list and a line out of /proc/cpuinfo — none of them guaranteed free of the separator, so two different machines could produce one byte stream. It also now states which three things a restore is allowed to differ in and why each is safe: the vsock context id is not in the migration stream and the guest re-reads it after the transport reset, a disk is cold-plugged and found with a PCI rescan, and what sits behind a NIC is a host file descriptor the guest never sees. Verified: qemu:build, kernel:build and image:build all write the release tree; a guest booted from an overlay on the renamed image mounts its ext4 root; `task release` packs the tarball and `spin-machine fingerprint --release` reads the unpacked tree with no path fixed up on the way. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019GHRRFvbnZi5q3KSTvyW5a
This was referenced Sep 8, 2026
aledbf
added a commit
that referenced
this pull request
Sep 10, 2026
…ves it
The research's ranked candidate for a kernel rebuild was CONFIG_XFRM=n, on the
grounds that xfrm_init runs inside ip_rt_init and register_xfrm_state_bpf does
BTF work Docker does not need. The measurements agree right up to the last step
and then invert the conclusion.
function_graph at depth 1, silent console, dmesg read back from the guest:
inet_init 9252 us
└─ ip_rt_init 9444 us (97% of it)
└─ xfrm_init 8971 / 8638 / 9135 us over three boots
└─ register_xfrm_state_bpf 9045 / 9306 us - essentially all of it
Which reads as a 9 ms saving sitting behind one config symbol. It is not. Filter
on register_btf_kfunc_id_set instead and the boot makes 51 calls to it:
#1 9301.9 us #2 0.75 us #3 1.52 us ... #51
The first call pays the one-time parse of the 4.35 MB .BTF section and every
other call is microseconds. XFRM is not expensive; it is merely first in the
queue. CONFIG_XFRM=n would hand the same 9 ms to whichever kfunc set registers
next, and the only symbol that removes it is CONFIG_DEBUG_INFO_BTF=n - which is
the one thing here that is not up for discussion.
Recorded at the BTF assertion in kernel/Dockerfile, where the decision to keep
BTF now carries its price.
That is the third time in this session a per-function number turned out to
belong to something else: acpi_purge_cached_objects at 26x under a wide filter,
ksm_init and kcompactd_init at 3 ms of vCPU descheduling each, and now this.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019GHRRFvbnZi5q3KSTvyW5a
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Groundwork so that spinbox and storage can stop keeping their own copy of what this machine is. Three changes, each removing a way for two things to disagree.
One layout
The same four files had three shapes — what the build extracted into
_output/, what the tarball carried underusr/share/spin-stack/, and what a consumer rearranged them into — with a translation step between each pair (hack/release's moves, spinbox'splace(),internal/paths'sdiscoverQemuPath) and a discovery function guessing which shape it had. Every one of those is a place the answer can be wrong, and the way it goes wrong is a path that exists and holds the previous release's kernel.The three Dockerfiles now extract the release tree directly, so
_output/and the tarball are the same shape byte for byte, and the newmachine.Openreads either:It checks rather than trusting — four stats — so a release with a hole in it names the file, instead of surfacing later as a QEMU that exits for want of an option ROM. The TCG binary and the image are optional: a KVM-only host needs neither, and
QEMUTCG()/Rootfs()report their own absence to whoever asks.This also removes
COMPAT_KERNEL_NAME, the symlink hatch that existed so a consumer resolving the kernel under another name would not have to change.base.qcow2→rootfs.qcow2basenames the role — a qcow2 backing file — which the directory and the prose already say, and it collides with "base image" in the container sense.rootfsnames what the file holds.The fingerprint cannot be shifted
It hashed
key=value\nlines whose values are a CPU model, a device list and a line out of/proc/cpuinfo— none guaranteed free of the separator, so two different machines could produce one byte stream. Now length-prefixed. It also states which three things a restore is allowed to differ in and why each is safe: the vsock context id is not in the migration stream and the guest re-reads it after the transport reset, a disk is cold-plugged and found with a PCI rescan, and what sits behind a NIC is a host file descriptor the guest never sees.Verified
qemu:build,kernel:buildandimage:buildall write the release tree; a guest booted from an overlay on the renamed image mounts its ext4 root;task releasepacks the tarball andspin-machine fingerprint --releasereads the unpacked tree with no path fixed up on the way. New tests coverOpennaming each missing file, the optional parts, andSpec()deciding nothing a release does not know.This is a breaking release: every existing template stops matching, which is what changing the machine means. Nothing consumes one yet.
🤖 Generated with Claude Code
https://claude.ai/code/session_019GHRRFvbnZi5q3KSTvyW5a