Skip to content

Commit c9e86c1

Browse files
pothoschewi
andcommitted
Use a minimal initrd to switch to the full initrd stored in /usr
The growth of binaries over time and the inclusion of new features filled the available boot partition space, so that the kernel+initrd almost couldn't fit twice anymore as required for updates. We employed workarounds such as wrapper scripts for ignition, afterburn and other binaries so that they are loaded from /usr. However, this was still not enough and we would have to do the same for (network) kernel modules and firmware. To avoid making this ever more complex we can use a dedicated initrd focused on loading the full initrd from /usr and then this full initrd can use dracut as before and even drop all the workarounds we accumulated. Generate a minimal initrd to use instead of the full bootengine initrd. The bootengine initrd gets stored as squashfs on /usr. The minimal initrd still includes the early_cpio for amd64 microcode updates. We have a fixed list of modules or module directories to include, only focused on loading /usr and any emergency console interaction. This requires also checking for module dependencies to copy over. The busybox, veritysetup, and kmod binaries are needed and get their required libraries resolved and copied over. They are not static and use shared libraries which should be ok for now. The resulting vmlinuz file is 27 MB for amd64, down from ~60 MB, so we have enough room to include more kernel modules and so on for the next years while we also grow the boot partition and wait for users to redeploy until we can rely on a larger boot partition and eventually drop the minimal initrd again. Pulls in flatcar/bootengine#110 for the minimal initrd script and flatcar/seismograph#12 for making the device mapper discovery for the "rootdev" command more reliable. This also requied a backport of a kernel patch from 2017 that exposes the PARTUUID in the /sys uevent file. Co-authored-by: James Le Cuirot <[email protected]> Signed-off-by: Kai Lueke <[email protected]>
1 parent c041603 commit c9e86c1

File tree

9 files changed

+160
-3
lines changed

9 files changed

+160
-3
lines changed

build_library/build_image_util.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,8 @@ finish_image() {
582582
local image_initrd_contents="${11}"
583583
local image_initrd_contents_wtd="${12}"
584584
local image_disk_space_usage="${13}"
585+
local image_realinitrd_contents="${14}"
586+
local image_realinitrd_contents_wtd="${15}"
585587

586588
local install_grub=0
587589
local disk_img="${BUILD_DIR}/${image_name}"
@@ -877,6 +879,20 @@ EOF
877879
rm -rf "${BUILD_DIR}/tmp_initrd_contents"
878880
fi
879881

882+
if [[ -n ${image_realinitrd_contents} || -n ${image_realinitrd_contents_wtd} ]]; then
883+
mkdir -p "${BUILD_DIR}/tmp_initrd_contents"
884+
sudo mount "${root_fs_dir}/usr/lib/flatcar/bootengine.img" "${BUILD_DIR}/tmp_initrd_contents"
885+
if [[ -n ${image_realinitrd_contents} ]]; then
886+
write_contents "${BUILD_DIR}/tmp_initrd_contents" "${BUILD_DIR}/${image_realinitrd_contents}"
887+
fi
888+
889+
if [[ -n ${image_realinitrd_contents_wtd} ]]; then
890+
write_contents_with_technical_details "${BUILD_DIR}/tmp_initrd_contents" "${BUILD_DIR}/${image_realinitrd_contents_wtd}"
891+
fi
892+
sudo umount "${BUILD_DIR}/tmp_initrd_contents"
893+
rm -rf "${BUILD_DIR}/tmp_initrd_contents"
894+
fi
895+
880896
if [[ -n "${image_disk_space_usage}" ]]; then
881897
write_disk_space_usage "${root_fs_dir}" "${BUILD_DIR}/${image_disk_space_usage}"
882898
fi

build_library/prod_image_util.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ create_prod_image() {
8383
local image_initrd_contents="${image_name%.bin}_initrd_contents.txt"
8484
local image_initrd_contents_wtd="${image_name%.bin}_initrd_contents_wtd.txt"
8585
local image_disk_usage="${image_name%.bin}_disk_usage.txt"
86+
local image_realinitrd_contents="${image_name%.bin}_realinitrd_contents.txt"
87+
local image_realinitrd_contents_wtd="${image_name%.bin}_realinitrd_contents_wtd.txt"
8688
local image_sysext_base="${image_name%.bin}_sysext.squashfs"
8789

8890
start_image "${image_name}" "${disk_layout}" "${root_fs_dir}" "${update_group}"
@@ -180,7 +182,9 @@ EOF
180182
"${image_kconfig}" \
181183
"${image_initrd_contents}" \
182184
"${image_initrd_contents_wtd}" \
183-
"${image_disk_usage}"
185+
"${image_disk_usage}" \
186+
"${image_realinitrd_contents}" \
187+
"${image_realinitrd_contents_wtd}"
184188

185189
# Official builds will sign and upload these files later, so remove them to
186190
# prevent them from being uploaded now.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Reduced the kernel+initrd size on `/boot` by half. Flatcar now uses a minimal first stage initrd just to access the `/usr` partition and then switches to the full initrd that does the full system preparation as before. Since this means that the set of kernel modules available in the first initrd is reduced, please report any impact.

ci-automation/image_changes.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,15 @@ function print_image_reports() {
729729
echo "Note that vmlinuz-a also contains the kernel code, which might have changed too, so the reported difference does not accurately describe the change in initrd."
730730
echo
731731

732+
yell "Real/full init ramdisk (bootengine.img) differences compared to ${previous_version_description}"
733+
underline "Real/full init ramdisk (bootengine.img) file changes, compared to ${previous_version_description}:"
734+
env \
735+
"${package_diff_env[@]}" FILE=flatcar_production_image_realinitrd_contents.txt FILESONLY=1 CUTKERNEL=1 \
736+
"${flatcar_build_scripts_repo}/package-diff" "${package_diff_params[@]}" 2>&1 || true
737+
738+
underline "Real/full init ramdisk (bootengine.img) file size changes, compared to ${previous_version_description}:"
739+
"${size_changes_invocation[@]}" "${size_change_report_params[@]/%/:realinitrd-wtd}" 2>&1 || true
740+
732741
local base_sysext
733742
for base_sysext in "${base_sysexts[@]}"; do
734743
yell "Base sysext ${base_sysext} changes compared to ${previous_version_description}"

sdk_container/src/third_party/coreos-overlay/sys-apps/seismograph/seismograph-9999.ebuild

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ EGIT_REPO_URI="https://github.com/flatcar/seismograph.git"
77
if [[ "${PV}" == 9999 ]]; then
88
KEYWORDS="~amd64 ~arm ~arm64 ~x86"
99
else
10-
EGIT_COMMIT="e32ac4d13ca44333dc77e5872dbf23f964b6f1e2" # main
10+
EGIT_COMMIT="231f8b31c576133f75151d34cb90890bfaf15ebe" # main
1111
KEYWORDS="amd64 arm arm64 x86"
1212
fi
1313

sdk_container/src/third_party/coreos-overlay/sys-kernel/bootengine/bootengine-9999.ebuild

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ EGIT_REPO_URI="https://github.com/flatcar/bootengine.git"
77
if [[ "${PV}" == 9999 ]]; then
88
KEYWORDS="~amd64 ~arm ~arm64 ~x86"
99
else
10-
EGIT_COMMIT="31ba2964ce5e77ae5553eb0a3624afcc7078bb09" # flatcar-master
10+
#EGIT_COMMIT="31ba2964ce5e77ae5553eb0a3624afcc7078bb09" # flatcar-master
11+
EGIT_BRANCH="kai/initrd-in-usr"
1112
KEYWORDS="amd64 arm arm64 x86"
1213
fi
1314

@@ -23,6 +24,7 @@ src_install() {
2324
insinto /usr/lib/dracut/modules.d/
2425
doins -r dracut/.
2526
dosbin update-bootengine
27+
dosbin minimal-init
2628

2729
# must be executable since dracut's install scripts just
2830
# re-use existing filesystem permissions during initrd creation.

sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-kernel/coreos-kernel-6.12.48.ebuild

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ DEPEND="
2626
coreos-base/coreos-init:=
2727
sys-apps/azure-vm-utils[dracut]
2828
sys-apps/baselayout
29+
sys-apps/busybox
2930
sys-apps/coreutils
3031
sys-apps/findutils
3132
sys-apps/grep
@@ -72,6 +73,17 @@ src_prepare() {
7273
use amd64 && config_update "CONFIG_EXTRA_FIRMWARE_DIR=\"${fw_dir}\""
7374
}
7475

76+
copy_in() {
77+
# Simple setup, assume we only have /lib64 to care about
78+
cp "${ESYSROOT}"/usr/"$1" ./"$1" || die
79+
local LIBFILE
80+
for LIBFILE in $(patchelf --print-needed ./"$1"); do
81+
if [[ ! -e ./lib64/${LIBFILE} ]]; then
82+
copy_in /lib64/"${LIBFILE}"
83+
fi
84+
done
85+
}
86+
7587
src_compile() {
7688
local BE_ARGS=()
7789

@@ -89,6 +101,79 @@ src_compile() {
89101

90102
tc-export PKG_CONFIG
91103
"${ESYSROOT}"/usr/bin/update-bootengine -k "${KV_FULL}" -o "${S}"/build/bootengine.cpio "${BE_ARGS[@]}" || die
104+
# Copy full initrd over to /usr as filesystem image
105+
mkdir "${S}"/build/bootengine || die
106+
pushd "${S}"/build/bootengine || die
107+
sudo lsinitrd --unpack "${S}"/build/bootengine.cpio || die
108+
sudo mksquashfs . "${S}"/build/bootengine.img -noappend -xattrs-exclude ^btrfs. || die
109+
popd || die
110+
# Create minimal initrd
111+
if use amd64; then
112+
local -i microcode=$(cpio -t < "${S}"/build/bootengine.cpio 2>&1 > /dev/null | cut -d " " -f 1)
113+
# Only keep early cpio for microcode
114+
truncate -s $((microcode*512)) "${S}"/build/bootengine.cpio || die
115+
# Debug: List contents after truncation
116+
cpio -t < "${S}"/build/bootengine.cpio
117+
else
118+
# No early cpio, drop full initrd
119+
> "${S}"/build/bootengine.cpio
120+
fi
121+
mkdir "${S}"/build/minimal || die
122+
pushd "${S}"/build/minimal || die
123+
mkdir -p {etc,bin,sbin,dev,proc,sys,dev,lib,lib64,usr/bin,usr/sbin,usr/lib,usr/lib64,realinit,sysusr/usr}
124+
mkdir -p lib/modules/"${KV_FULL}"/
125+
# Instead from ESYSROOT we can also copy kernel modules from the dracut pre-selection
126+
cp "${S}"/build/bootengine/usr/lib/modules/"${KV_FULL}"/modules.* lib/modules/"${KV_FULL}"/
127+
mkdir -p lib/modprobe.d/
128+
cp "${S}"/build/bootengine/lib/modprobe.d/* lib/modprobe.d/
129+
# Only include modules related to mounting /usr and for interacting with the emergency console
130+
local -a MODULES=("fs/overlayfs" "fs/squashfs" "drivers/md/dm-verity.ko.xz" "drivers/md/dm-mod.ko.xz" "drivers/block/loop.ko.xz" "fs/btrfs" "drivers/nvme" "drivers/scsi" "drivers/ata" "drivers/block" "drivers/pci" "drivers/char/virtio_console.ko.xz" "drivers/hv" "drivers/input/serio" "drivers/mmc" "drivers/usb" "drivers/hid" "security/keys")
131+
local MODULE DEP DEP_DIR
132+
for MODULE in "${MODULES[@]}"; do
133+
if [[ -f ${S}/build/bootengine/usr/lib/modules/${KV_FULL}/kernel/${MODULE} ]]; then
134+
local MODULE_DIR=${MODULE%/*}
135+
mkdir -p lib/modules/"${KV_FULL}"/kernel/"${MODULE_DIR}"
136+
cp "${S}"/build/bootengine/usr/lib/modules/"${KV_FULL}"/kernel/"${MODULE}" lib/modules/"${KV_FULL}"/kernel/"${MODULE}"
137+
elif [[ -d ${S}/build/bootengine/usr/lib/modules/${KV_FULL}/kernel/${MODULE} ]]; then
138+
mkdir -p lib/modules/"${KV_FULL}"/kernel/"${MODULE}"
139+
cp -r "${S}"/build/bootengine/usr/lib/modules/"${KV_FULL}"/kernel/"${MODULE}"/* lib/modules/"${KV_FULL}"/kernel/"${MODULE}"/
140+
else
141+
die "wrong module type/not found: ${S}"/build/bootengine/usr/lib/modules/"${KV_FULL}"/kernel/"${MODULE}"
142+
fi
143+
done
144+
# Copy module dependencies
145+
for MODULE in $(find ./lib/modules/"${KV_FULL}"/ -type f); do
146+
MODULE=${MODULE##*/}
147+
MODULE=${MODULE%.ko.xz}
148+
for DEP in $(modprobe -S "${KV_FULL}" -d "${S}"/build/bootengine -D "${MODULE}" | grep "^insmod " | sed "s/^insmod //"); do
149+
DEP=${DEP#"${S}/build/bootengine"}
150+
DEP_DIR=${DEP%/*}
151+
mkdir -p ./"${DEP_DIR}"
152+
cp "${S}"/build/bootengine/"${DEP}" ./"${DEP}"
153+
done
154+
done
155+
echo '$MODALIAS=.* 0:0 660 @/sbin/modprobe "$MODALIAS"' > ./etc/mdev.conf
156+
copy_in /bin/veritysetup
157+
copy_in /bin/dmsetup
158+
copy_in /bin/busybox
159+
# We can't use busybox's modprobe because it doesn't support the globs in module.alias, breaking module loading
160+
copy_in /sbin/kmod
161+
ln -s /sbin/kmod ./sbin/modprobe
162+
if use arm64; then
163+
ln -s ../lib64/ld-linux-aarch64.so.1 ./lib/ld-linux-aarch64.so.1
164+
fi
165+
cp -a "${ESYSROOT}"/usr/bin/minimal-init ./init
166+
# Make it easier to debug by not relying too much on the first commands
167+
ln -s /bin/busybox ./bin/sh
168+
mknod ./dev/console c 5 1
169+
mknod ./dev/null c 1 3
170+
mknod ./dev/tty c 5 0
171+
mknod ./dev/urandom c 1 9
172+
mknod ./dev/random c 1 8
173+
mknod ./dev/zero c 1 5
174+
# No compression because CONFIG_INITRAMFS_COMPRESSION_XZ should take care of it
175+
find . -print0 | cpio --null --create --verbose --format=newc >> "${S}"/build/bootengine.cpio
176+
popd || die
92177
kmake "$(kernel_target)"
93178

94179
# sanity check :)
@@ -111,4 +196,7 @@ src_install() {
111196
# For easy access to vdso debug symbols in gdb:
112197
# set debug-file-directory /usr/lib/debug/usr/lib/modules/${KV_FULL}/vdso/
113198
kmake INSTALL_MOD_PATH="${ED}/usr/lib/debug/usr" vdso_install
199+
200+
insinto "/usr/lib/flatcar"
201+
doins build/bootengine.img
114202
}

sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-sources/coreos-sources-6.12.48.ebuild

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,5 @@ UNIPATCH_LIST="
4343
${PATCH_DIR}/z0006-mtd-disable-slram-and-phram-when-locked-down.patch \
4444
${PATCH_DIR}/z0007-arm64-add-kernel-config-option-to-lock-down-when.patch \
4545
${PATCH_DIR}/z0008-tools-hv-fix-cross-compilation-for-ARM64.patch \
46+
${PATCH_DIR}/z0009-block-add-partition-uuid-into-uevent.patch \
4647
"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
From 758737d86f8a2d74c0fa9f8b2523fa7fd1e0d0aa Mon Sep 17 00:00:00 2001
2+
From: Konstantin Khlebnikov <[email protected]>
3+
Date: Fri, 4 Oct 2024 17:13:43 -0700
4+
Subject: [PATCH] block: add partition uuid into uevent as "PARTUUID"
5+
6+
Both most common formats have uuid in addition to partition name:
7+
GPT: standard uuid xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
8+
DOS: 4 byte disk signature and 1 byte partition xxxxxxxx-xx
9+
10+
Tools from util-linux use the same notation for them.
11+
12+
Signed-off-by: Konstantin Khlebnikov <[email protected]>
13+
Reviewed-by: Kyle Fortin <[email protected]>
14+
[dianders: rebased to modern kernels]
15+
Signed-off-by: Douglas Anderson <[email protected]>
16+
Signed-off-by: Douglas Anderson <[email protected]>
17+
Reviewed-by: Christoph Hellwig <[email protected]>
18+
Link: https://lore.kernel.org/r/20241004171340.v2.1.I938c91d10e454e841fdf5d64499a8ae8514dc004@changeid
19+
Signed-off-by: Jens Axboe <[email protected]>
20+
---
21+
block/partitions/core.c | 2 ++
22+
1 file changed, 2 insertions(+)
23+
24+
diff --git a/block/partitions/core.c b/block/partitions/core.c
25+
index cdad05f9764768..815ed33caa1b86 100644
26+
--- a/block/partitions/core.c
27+
+++ b/block/partitions/core.c
28+
@@ -256,6 +256,8 @@ static int part_uevent(const struct device *dev, struct kobj_uevent_env *env)
29+
add_uevent_var(env, "PARTN=%u", bdev_partno(part));
30+
if (part->bd_meta_info && part->bd_meta_info->volname[0])
31+
add_uevent_var(env, "PARTNAME=%s", part->bd_meta_info->volname);
32+
+ if (part->bd_meta_info && part->bd_meta_info->uuid[0])
33+
+ add_uevent_var(env, "PARTUUID=%s", part->bd_meta_info->uuid);
34+
return 0;
35+
}
36+

0 commit comments

Comments
 (0)