Skip to content

Commit 551eb8d

Browse files
committed
the live ISO carried its kernel and initramfs twice, and the splash made that fatal
1 parent 9f8fd1d commit 551eb8d

2 files changed

Lines changed: 59 additions & 6 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@ Entries land with the change they describe; the next tag takes this section
66
as its release notes. Say what changed and what a reader has to do
77
differently. Why it changed belongs in the commit that made it.
88

9+
- **The live ISO carries its kernel and initramfs once, not twice, and
10+
fits a release asset again.** Both files shipped in two places: inside
11+
the squashfs that becomes the live root, and under `images/pxeboot`,
12+
which is the copy the boot actually loads. The boot splash grew the
13+
initramfs by 156 MB (a splash needs a framebuffer, so dracut packs
14+
every GPU driver's firmware into it), and the doubled copy took the
15+
ISO from 1.80 GB to 2.11 GB — over the 1.9 GB budget for a GitHub
16+
release asset, failing the `iso` job. The in-squashfs copies were
17+
never read: a live boot loads the pxeboot pair, and installing pulls
18+
its image from a registry. `kuma iso` now excludes both from the
19+
squashfs; the ISO lands near 1.85 GB. Nothing for a reader to do.
20+
921
## v0.18.0 (2026-08-27)
1022

1123
### Added

‎src/liveiso.rs‎

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -355,14 +355,32 @@ dnf install -y --setopt=install_weak_deps=False \
355355
work=$(mktemp -d)
356356
mkdir -p "$work"/iso-root/{images/pxeboot,LiveOS} "$work"/EFI
357357
358+
# Same single-kernel reasoning as the live Containerfile: two kernels
359+
# here would silently copy one image and boot the other's modules.
360+
# Resolved before mksquashfs because the exclude list below names the
361+
# kernel's files by version.
362+
kver="$(ls "$rootfs/usr/lib/modules")"
363+
[ "$(echo "$kver" | wc -l)" -eq 1 ] || { echo >&2 "expected exactly one kernel, got: $kver"; exit 1; }
364+
358365
# The live root filesystem, in one file.
359366
#
360367
# sysroot and ostree are an installed machine's deployment machinery and
361368
# mean nothing to a live boot, which mounts this squashfs as / directly.
369+
# The kernel and initramfs are excluded for the same reason, one level
370+
# up: they are boot artifacts, and the copies this ISO actually loads
371+
# are the ones under images/pxeboot that GRUB names. The pair inside the
372+
# rootfs serves an installed machine's kernel-update machinery, which a
373+
# throwaway live root never runs. The initramfs is the expensive one —
374+
# 242 MB since v0.18 put plymouth in it, because a splash needs a
375+
# framebuffer and dracut's drm module then packs every GPU driver's
376+
# firmware into a --no-hostonly build — and it is already a zstd
377+
# stream, so squashfs stores it at full size. Carrying it twice took
378+
# the ISO from 1.80 GB to 2.11 GB and over the release-asset budget;
379+
# measured, not estimated, on the niri image of 2026-08-27.
362380
# zstd at 19 because this number is the ISO's size: the whole point of
363381
# the exercise is fitting under a 2 GB release asset cap.
364382
#
365-
# -e goes LAST and takes both patterns, because mksquashfs treats every
383+
# -e goes LAST and takes every pattern, because mksquashfs treats every
366384
# remaining argument as an exclude pattern once it sees -e. Writing it
367385
# in the middle does not error: it silently excludes files named "-comp"
368386
# and "19", and falls back to gzip. That cost 60 MB here and it is
@@ -380,12 +398,12 @@ mkdir -p "$work"/iso-root/{images/pxeboot,LiveOS} "$work"/EFI
380398
# boot on the writable overlay rather than baking one into the image.
381399
mksquashfs "$rootfs" "$work/iso-root/LiveOS/squashfs.img" \
382400
-noappend -comp zstd -Xcompression-level 19 \
383-
-e sysroot ostree
401+
-e sysroot ostree \
402+
"usr/lib/modules/$kver/initramfs.img" \
403+
"usr/lib/modules/$kver/vmlinuz"
384404
385-
# Same single-kernel reasoning as the live Containerfile: two kernels
386-
# here would silently copy one image and boot the other's modules.
387-
kver="$(ls "$rootfs/usr/lib/modules")"
388-
[ "$(echo "$kver" | wc -l)" -eq 1 ] || { echo >&2 "expected exactly one kernel, got: $kver"; exit 1; }
405+
# The boot pair GRUB actually loads. Copied from the rootfs, not the
406+
# squashfs, so the excludes above do not touch this.
389407
cp "$rootfs/usr/lib/modules/$kver/vmlinuz" "$work/iso-root/images/pxeboot/vmlinuz"
390408
cp "$rootfs/usr/lib/modules/$kver/initramfs.img" "$work/iso-root/images/pxeboot/initrd.img"
391409
@@ -806,6 +824,29 @@ mod tests {
806824
assert!(comp < exclude, "-e must come last or it eats the compressor flags");
807825
}
808826

827+
/// The kernel and initramfs ride the ISO once, under images/pxeboot,
828+
/// because those are the copies GRUB loads. The same files inside
829+
/// the squashfs serve an installed machine's kernel-update
830+
/// machinery, which a throwaway live root never runs — and the
831+
/// initramfs is a 242 MB zstd stream that squashfs cannot shrink, so
832+
/// carrying it twice is what took the ISO from 1.80 GB to 2.11 GB
833+
/// and over the release-asset budget in v0.18. The splash grew it;
834+
/// the doubling made it fatal.
835+
#[test]
836+
fn the_squashfs_carries_no_boot_artifacts() {
837+
let script = super::BUILD_ISO_SCRIPT;
838+
assert!(
839+
script.contains("\"usr/lib/modules/$kver/initramfs.img\""),
840+
"the initramfs is the ISO's biggest file; it rides once, in pxeboot"
841+
);
842+
assert!(script.contains("\"usr/lib/modules/$kver/vmlinuz\""));
843+
// The exclude list names the kernel's files by version, so the
844+
// version has to be resolved before mksquashfs runs.
845+
let kver = script.find("kver=\"$(ls").unwrap();
846+
let exclude = script.find("usr/lib/modules/$kver/initramfs.img").unwrap();
847+
assert!(kver < exclude, "kver must exist before the exclude list names it");
848+
}
849+
809850
/// Found by booting: `-all-root` makes every file root-owned, and
810851
/// liveuser's 0700 home then belongs to root, so the live user
811852
/// cannot write to it. Symptom is a broken desktop with no obvious

0 commit comments

Comments
 (0)