feat(iso): split the live medium into semantic SquashFS layers
Booting via BMC virtual CD reads the ~2.8 GB filesystem squashfs sequentially during the live-boot toram copy; a mid-read drop of the redirected medium loses the whole copy and fails the boot (v14). Split the rootfs into self-contained semantic layers so a retry re-reads at most one ~500-700 MiB layer, not everything. This is a resilience / reduced-re-read mechanism, not a fix for the virtual-media instability. NVIDIA variants now ship 7 layers (00-base, 05-firmware, 08-desktop, 10-nvidia-driver, 20-nvidia-platform, 30-nvidia-cuda-libs, 40-nvidia-dcgm-cuda) plus an explicit live/filesystem.module that fixes their OverlayFS order; amd/nogpu keep a single squashfs. - lib/squashfs-layers.sh: deterministic classifier (dpkg file ownership plus explicit rules for build.sh-injected files, never a path substring), per-layer mksquashfs, 800 MiB hard ceiling, unsquashfs -s plus strict extraction of every layer, merged-rootfs bootability check. - build.sh: split the monolith after the full lb build, verify and merge, write the module file, delete the monolith only then; abort before ISO assembly on any failure. Runs the builder test suites up front. - fast-path: force a full build for a multi-layer medium; fast_path_repack_squashfs hard-refuses (it would drop layers). - iso-validation.sh: validate_iso_squashfs_layers (module vs layer set match, size ceiling, no lone giant squashfs) and validate_iso_media_integrity (xorriso -check_media). - bee-install: honour filesystem.module order, abort on any layer failure. - 9013-toram-retry: record the real rsync exit code (it printed a false rc=0) and correct the "resumes the tail" comment (rsync without --partial keeps only fully-copied layers). No unsafe partial resume. - tests: test-squashfs-layers.sh plus a multi-layer guard in test-build-libs.sh; both run at the top of every build. - docs: bible-local architecture and decision, iso/README, iso-build-rules. Verified by a full nvidia build: 7 layers 622/199/256/466/37/567/562 MiB, every validator passes, xorriso -check_media good, merged rootfs bootable. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
bc57b85d3f
commit
b8c45d54c1
@@ -62,7 +62,30 @@ for tool in parted mkfs.vfat mkfs.ext4 unsquashfs grub-install update-grub; do
|
||||
fi
|
||||
done
|
||||
|
||||
mapfile -t SQUASHFS_FILES < <(find /run/live/medium/live -maxdepth 1 -type f -name '*.squashfs' | sort)
|
||||
# Order the squashfs layers exactly as live-boot stacks them: if the medium
|
||||
# carries live/filesystem.module, honour that list verbatim (it is the same
|
||||
# order OverlayFS uses, last entry = highest priority); otherwise fall back to a
|
||||
# lexical sort, which the NN- numeric prefixes make equivalent.
|
||||
LIVE_DIR=/run/live/medium/live
|
||||
MODULE_FILE="${LIVE_DIR}/filesystem.module"
|
||||
read_squashfs_layers() {
|
||||
SQUASHFS_FILES=()
|
||||
if [ -f "$MODULE_FILE" ]; then
|
||||
while IFS= read -r name; do
|
||||
[ -n "$name" ] || continue
|
||||
case "$name" in \#*) continue ;; esac
|
||||
if [ -f "${LIVE_DIR}/${name}" ]; then
|
||||
SQUASHFS_FILES+=("${LIVE_DIR}/${name}")
|
||||
else
|
||||
echo "ERROR: filesystem.module lists ${name} but it is missing from the medium" >&2
|
||||
exit 1
|
||||
fi
|
||||
done < "$MODULE_FILE"
|
||||
else
|
||||
mapfile -t SQUASHFS_FILES < <(find "$LIVE_DIR" -maxdepth 1 -type f -name '*.squashfs' | sort)
|
||||
fi
|
||||
}
|
||||
read_squashfs_layers
|
||||
if [ "${#SQUASHFS_FILES[@]}" -eq 0 ]; then
|
||||
echo "ERROR: no squashfs files found under /run/live/medium/live" >&2
|
||||
echo " The live medium may have been disconnected." >&2
|
||||
@@ -182,7 +205,7 @@ while true; do
|
||||
fi
|
||||
[ "$UNPACK_ATTEMPTS" -gt 1 ] && log " Retry attempt $UNPACK_ATTEMPTS / $UNPACK_MAX ..."
|
||||
|
||||
mapfile -t SQUASHFS_FILES < <(find /run/live/medium/live -maxdepth 1 -type f -name '*.squashfs' | sort)
|
||||
read_squashfs_layers
|
||||
if [ "${#SQUASHFS_FILES[@]}" -eq 0 ]; then
|
||||
log " SOURCE LOST: no squashfs files found under /run/live/medium/live."
|
||||
log " Reconnect the disc and run 'bee-remount-medium --wait' in another terminal,"
|
||||
@@ -198,17 +221,28 @@ while true; do
|
||||
find "$MOUNT_ROOT" -mindepth 1 -maxdepth 1 -exec rm -rf {} + 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Unpack every layer in module order. unsquashfs -f makes a later layer
|
||||
# overwrite an earlier one, matching live-boot's OverlayFS precedence. A
|
||||
# failed layer aborts this attempt: a partial multi-layer unpack must never
|
||||
# be treated as a usable install.
|
||||
UNPACK_OK=0
|
||||
UNPACK_TMP=$(mktemp)
|
||||
for sf in "${SQUASHFS_FILES[@]}"; do
|
||||
log " Unpacking $(basename "$sf") ..."
|
||||
unsquashfs -f -d "$MOUNT_ROOT" "$sf" 2>&1 | \
|
||||
grep -E '^\[|^inod|^created|^extract|^ERROR|failed' | \
|
||||
while IFS= read -r line; do log " $line"; done || UNPACK_OK=$?
|
||||
[ "$UNPACK_OK" -eq 0 ] || break
|
||||
rc=0
|
||||
unsquashfs -f -d "$MOUNT_ROOT" "$sf" > "$UNPACK_TMP" 2>&1 || rc=$?
|
||||
grep -E '^\[|^inod|^created|^extract|^ERROR|failed' "$UNPACK_TMP" \
|
||||
| while IFS= read -r line; do log " $line"; done || true
|
||||
if [ "$rc" -ne 0 ]; then
|
||||
log " ERROR: unsquashfs failed for $(basename "$sf") (rc=$rc)"
|
||||
UNPACK_OK=$rc
|
||||
break
|
||||
fi
|
||||
done
|
||||
rm -f "$UNPACK_TMP"
|
||||
|
||||
# Check squashfs is still reachable (gone = disc pulled during copy)
|
||||
mapfile -t SQUASHFS_FILES < <(find /run/live/medium/live -maxdepth 1 -type f -name '*.squashfs' | sort)
|
||||
read_squashfs_layers
|
||||
if [ "${#SQUASHFS_FILES[@]}" -eq 0 ]; then
|
||||
log " WARNING: source medium lost during unpack — will retry after remount."
|
||||
log " Run 'bee-remount-medium --wait' in another terminal, then press Enter."
|
||||
@@ -216,9 +250,16 @@ while true; do
|
||||
continue
|
||||
fi
|
||||
|
||||
# Verify the unpack produced a usable root (presence of /etc is a basic check)
|
||||
if [ -d "${MOUNT_ROOT}/etc" ]; then
|
||||
log " Unpack complete."
|
||||
if [ "$UNPACK_OK" -ne 0 ]; then
|
||||
log " A layer failed to unpack — retrying the whole unpack."
|
||||
[ "$UNPACK_ATTEMPTS" -lt "$UNPACK_MAX" ] && sleep 5
|
||||
continue
|
||||
fi
|
||||
|
||||
# Verify the unpack produced a usable root: /etc from the base layer and
|
||||
# /usr/sbin/init must both be present after all layers are applied.
|
||||
if [ -d "${MOUNT_ROOT}/etc" ] && [ -e "${MOUNT_ROOT}/usr/sbin/init" ]; then
|
||||
log " Unpack complete (${#SQUASHFS_FILES[@]} layer(s))."
|
||||
break
|
||||
else
|
||||
log " WARNING: unpack produced no /etc — squashfs may be corrupt or incomplete."
|
||||
|
||||
Reference in New Issue
Block a user