From 0f23b8e37802c409d1cacd438aac19b26ea6d347 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Fri, 30 Apr 2021 13:23:21 -0400 Subject: [PATCH] rpi-resizerootfs: switch the root filesystem resizing away from a systemd oneshot service Switch away from using a systemd service for the initial root resize. Instead, we resize the root partition and filesystem in the initrd. To simplify things, the initrd script will check whether it should resize the partition on every boot. It does this by checking if the entire disk (ignoring an empty 4MB) is in use. However, the scripts themselves are deleted from the system after the initrd is generated. After the image is installed, the resize script should exist only in the initrd. When the kernel gets upgraded (eg, for a security update) or a new initrd is generated due to a package install, the new initrd will not contain the resize script. At that point, nothing will remain from the image's initial resize bootstrapping process. This process (but not the scripts) is similar to what cloud-initramfs-growroot does. However, that particular package has an indirect dependency on Python, and we don't necessarily want that overhead in our images just for resizing. --- raspi_master.yaml | 17 +++++-- .../initramfs-tools/hooks/rpi-resizerootfs | 23 +++++++++ .../scripts/local-bottom/rpi-resizerootfs | 50 +++++++++++++++++++ .../systemd/system/rpi-resizerootfs.service | 13 ----- rootfs/usr/sbin/rpi-resizerootfs | 22 -------- 5 files changed, 86 insertions(+), 39 deletions(-) create mode 100755 rootfs/etc/initramfs-tools/hooks/rpi-resizerootfs create mode 100755 rootfs/etc/initramfs-tools/scripts/local-bottom/rpi-resizerootfs delete mode 100644 rootfs/etc/systemd/system/rpi-resizerootfs.service delete mode 100755 rootfs/usr/sbin/rpi-resizerootfs diff --git a/raspi_master.yaml b/raspi_master.yaml index ef48f15..928388a 100644 --- a/raspi_master.yaml +++ b/raspi_master.yaml @@ -59,6 +59,16 @@ steps: __OTHER_APT_ENABLE__ unless: rootfs_unpacked + - copy-file: /etc/initramfs-tools/hooks/rpi-resizerootfs + src: rootfs/etc/initramfs-tools/hooks/rpi-resizerootfs + perm: 0755 + unless: rootfs_unpacked + + - copy-file: /etc/initramfs-tools/scripts/local-bottom/rpi-resizerootfs + src: rootfs/etc/initramfs-tools/scripts/local-bottom/rpi-resizerootfs + perm: 0755 + unless: rootfs_unpacked + - chroot: / shell: | apt-get update @@ -97,10 +107,9 @@ steps: mkdir -p "${ROOT?}/etc/systemd/system/basic.target.requires/" ln -s /etc/systemd/system/rpi-set-sysconf.service "${ROOT?}/etc/systemd/system/basic.target.requires/rpi-set-sysconf.service" - install -m 755 -o root -g root rootfs/usr/sbin/rpi-resizerootfs "${ROOT?}/usr/sbin/rpi-resizerootfs" - install -m 644 -o root -g root rootfs/etc/systemd/system/rpi-resizerootfs.service "${ROOT?}/etc/systemd/system/" - mkdir -p "${ROOT?}/etc/systemd/system/systemd-remount-fs.service.requires/" - ln -s /etc/systemd/system/rpi-resizerootfs.service "${ROOT?}/etc/systemd/system/systemd-remount-fs.service.requires/rpi-resizerootfs.service" + # Resize script is now in the initrd for first boot; no need to ship it. + rm -f "${ROOT?}/etc/initramfs-tools/hooks/rpi-resizerootfs" + rm -f "${ROOT?}/etc/initramfs-tools/scripts/local-bottom/rpi-resizerootfs" install -m 644 -o root -g root rootfs/etc/systemd/system/rpi-reconfigure-raspi-firmware.service "${ROOT?}/etc/systemd/system/" mkdir -p "${ROOT?}/etc/systemd/system/multi-user.target.requires/" diff --git a/rootfs/etc/initramfs-tools/hooks/rpi-resizerootfs b/rootfs/etc/initramfs-tools/hooks/rpi-resizerootfs new file mode 100755 index 0000000..f20edb2 --- /dev/null +++ b/rootfs/etc/initramfs-tools/hooks/rpi-resizerootfs @@ -0,0 +1,23 @@ +#!/bin/sh +set -e + +# +# List the soft prerequisites here. This is a space separated list of +# names, of scripts that are in the same directory as this one, that +# must be run before this one can be. +# +PREREQS="" +case $1 in + prereqs) echo "$PREREQS"; exit 0;; +esac + +. /usr/share/initramfs-tools/hook-functions + +# XXX: tail and realpath are included by default, right? +#copy_exec /usr/bin/realpath +#copy_exec /usr/bin/tail +copy_exec /sbin/blkid +copy_exec /bin/lsblk +copy_exec /sbin/sfdisk +copy_exec /sbin/partprobe +copy_exec /sbin/resize2fs diff --git a/rootfs/etc/initramfs-tools/scripts/local-bottom/rpi-resizerootfs b/rootfs/etc/initramfs-tools/scripts/local-bottom/rpi-resizerootfs new file mode 100755 index 0000000..8bfdae5 --- /dev/null +++ b/rootfs/etc/initramfs-tools/scripts/local-bottom/rpi-resizerootfs @@ -0,0 +1,50 @@ +#!/bin/sh +set -e + +# +# List the soft prerequisites here. This is a space separated list of +# names, of scripts that are in the same directory as this one, that +# must be run before this one can be. +# +PREREQS="" +case $1 in + prereqs) echo "$PREREQS"; exit 0;; +esac + +. /scripts/functions + +# Given the root partition, get the underlying device and partition number +rootpart=$(realpath $ROOT) +rootpart_nr=$(blkid -sPART_ENTRY_NUMBER -o value -p $rootpart) +rootdev="/dev/$(lsblk -no pkname "$rootpart")" + +# Check if there's free space on the device (note: we align the first +# partition at 4MB, so there's always at least 3MB free) +free_space="$(sfdisk -qF $rootdev | tail -n1 | grep -v [^0-9]3M)" +if test -z "$free_space"; then + # Great, we already resized; nothing left to do! + exit 0 +fi + +log_begin_msg "$0 resizing $ROOT" + +# Unmount for safety +umount "${rootmnt}" + +# Expand the partition size to fill the entire device +sfdisk -f $rootdev -N $rootpart_nr <