From a1bafdd9632bb640627195afb8595dc75e041f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfonso=20S=C3=A1nchez-Beato?= Date: Thu, 25 Jan 2024 17:15:58 +0000 Subject: [PATCH] factory: create components compatible mount units for kernel The kernel-modules components require that /lib/{modules,firmware} can be created by composition of what is shipped with the kernel plus parts that will be shipped by said component type. For this, we need to have modinfo files in a writable directory as these files will need to be regenerated when a new kernel-modules component is installed. These files need to be readable from /lib/modules/UTS_RELEASE. Inside this directory, "kernel" and "vdso" subfolders will be bind-mounted from the kernel snap, while "updates" will have modules from the components. In the case of UC, for modules we need an additional bind mount on top of the directory coming from the base (this is not needed for hybrid systems). In the case of firmware, content from the kernel will be mounted to /lib/firmware as in the past. However, we will rely on the existence of a /lib/firmware/updates in the kernel to mount firware coming from components. The mount units for the active kernel are created at boot time and stored in /run/systemd/system so they are accessible after the switch root, and are actually mounted after the switch happens, but with dependencies set so kernel modules are not loaded before the mounts are ready. This replaces the fstab/generator that was creating the mounts for modules/firmware in UC and hybrid respectively, and now unifies the approach for both. --- factory/usr/lib/core/extra-paths | 2 - factory/usr/lib/core/kernel-mounts | 81 +++++++++++++++++++ .../system-generators/kernel-snap-generator | 57 ------------- .../lib/systemd/system/classic-mounts.service | 3 +- .../system/detect-classic-sysroot.service | 2 +- .../systemd/system/populate-writable.service | 1 + 6 files changed, 84 insertions(+), 62 deletions(-) create mode 100755 factory/usr/lib/core/kernel-mounts delete mode 100755 factory/usr/lib/systemd/system-generators/kernel-snap-generator diff --git a/factory/usr/lib/core/extra-paths b/factory/usr/lib/core/extra-paths index 70b2877a..8b1401f2 100755 --- a/factory/usr/lib/core/extra-paths +++ b/factory/usr/lib/core/extra-paths @@ -4,6 +4,4 @@ set -eu cat <>/sysroot/etc/fstab /run/mnt/data /writable none bind,x-initrd.mount 0 0 -/run/mnt/kernel/firmware /usr/lib/firmware none bind,x-initrd.mount 0 0 -/run/mnt/kernel/modules /usr/lib/modules none bind,x-initrd.mount 0 0 EOF diff --git a/factory/usr/lib/core/kernel-mounts b/factory/usr/lib/core/kernel-mounts new file mode 100755 index 00000000..7ad25acb --- /dev/null +++ b/factory/usr/lib/core/kernel-mounts @@ -0,0 +1,81 @@ +#!/bin/sh + +set -eux + +# Prepare kernel modules/firmware tree if it does not exist + +ksnap_d=/run/mnt/kernel +core=false +data_d=/run/mnt/data +if [ -d /run/mnt/base ]; then + core=true + data_d=/run/mnt/data/system-data +fi + +kernelVer= +for f in "$ksnap_d"/System.map-*; do + kernelVer=${f##"$ksnap_d"/System.map-} +done +mod_root_d="$data_d"/usr/lib/modules +mod_d="$mod_root_d"/"$kernelVer" +ksnap_mod_d="$ksnap_d"/modules/"$kernelVer" + +if [ ! -d "$mod_d" ]; then + for d in initrd kernel vdso updates; do + mkdir -p "$mod_d"/"$d" + done + # Copy modinfo files + cp "$ksnap_mod_d"/modules.* "$mod_d" +fi + +fw_root_d="$data_d"/usr/lib/firmware/updates +mkdir -p "$fw_root_d" + +sysinit_wants=/run/systemd/system/sysinit.target.wants +mkdir -p "$sysinit_wants" + +conf_mount_dir() { + what=$1 + where=$2 + options=$3 + before_deps= + if [ $# -gt 3 ]; then + before_deps=$4 + fi + + unit=$(systemd-escape -p --suffix=mount "$where") + unit_path=/run/systemd/system/"$unit" + cat < "$unit_path" +[Unit] +ConditionPathExists=!/etc/initrd-release +DefaultDependencies=no +After=systemd-remount-fs.service +Before=systemd-udev.service systemd-modules-load.service $before_deps +Before=sysinit.target +Before=umount.target +Conflicts=umount.target + +[Mount] +What=$what +Options=$options +EOF + + ln -s "$unit_path" "$sysinit_wants"/"$unit" +} + +mod_unit_dep= +if [ "$core" = true ]; then + # For classic we are actually working on the rootfs, for core + # we need to bind mount to the base that is the rootfs. + mod_where=/usr/lib/modules + mod_unit_dep=$(systemd-escape -p --suffix=mount "$mod_where") + conf_mount_dir "$mod_root_d" "$mod_where" rbind,ro +fi +conf_mount_dir "$ksnap_mod_d"/kernel "$mod_d"/kernel bind,ro "$mod_unit_dep" +conf_mount_dir "$ksnap_mod_d"/vdso "$mod_d"/vdso bind,ro "$mod_unit_dep" + +fw_where=/usr/lib/firmware +fw_unit=$(systemd-escape -p --suffix=mount "$fw_where") +conf_mount_dir "$ksnap_d"/firmware "$fw_where" rbind,ro +# Note that this will fail if the kernel snap does not have a firmware/updates dir +conf_mount_dir "$fw_root_d" /usr/lib/firmware/updates rbind,ro "$fw_unit" diff --git a/factory/usr/lib/systemd/system-generators/kernel-snap-generator b/factory/usr/lib/systemd/system-generators/kernel-snap-generator deleted file mode 100755 index e9b8dcf4..00000000 --- a/factory/usr/lib/systemd/system-generators/kernel-snap-generator +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh - -set -eu - -: "${KERNEL_MNT_POINT:=/run/mnt/kernel}" - -if ! mountpoint -q "${KERNEL_MNT_POINT}"; then - exit 0 -fi - -# FIXME use SYSTEMD_IN_INITRD when using systemd 251+ -if [ -f /etc/initrd-release ]; then - sysroot=/sysroot - sysroot_unit=sysroot - target=initrd-fs.target -else - sysroot= - sysroot_unit= - target=local-fs.target -fi - -: "${OS_RELEASE:="${sysroot}/etc/os-release"}" - -# Note that /sysroot/etc/os-release is accessible when generators are -# re-executed due to "daemon-reload" called by -# initrd-parse-etc.service - -# We generate the kernel bind mount units only -# if we are on Ubuntu Classic - -# Ubuntu Core will have those mounts declared in /etc/fstab, thus -# using systemd-fstab-generator instead. - -if ! grep -q "^ID=ubuntu$" "${OS_RELEASE}"; then - exit 0 -fi - -for entry in firmware modules; do - what="${KERNEL_MNT_POINT}/${entry}" - where="${sysroot}/usr/lib/${entry}" - unit="usr-lib-${entry}.mount" - if [ -n "${sysroot_unit}" ]; then - unit="${sysroot_unit}-${unit}" - fi - mkdir -p "${1}/${target}.requires" - ln -sf "../${unit}" "${1}/${target}.requires/${unit}" - cat <"${1}/${unit}" -[Unit] -Before=${target} - -[Mount] -What=${what} -Where=${where} -Options=bind -Type=none -EOF -done diff --git a/factory/usr/lib/systemd/system/classic-mounts.service b/factory/usr/lib/systemd/system/classic-mounts.service index d5f46931..1df74275 100644 --- a/factory/usr/lib/systemd/system/classic-mounts.service +++ b/factory/usr/lib/systemd/system/classic-mounts.service @@ -11,6 +11,5 @@ Before=initrd-fs.target [Service] Type=oneshot -# We force re-running kernel-snap-generator -ExecStart=systemctl daemon-reload +ExecStart=/usr/lib/core/kernel-mounts StandardError=journal+console diff --git a/factory/usr/lib/systemd/system/detect-classic-sysroot.service b/factory/usr/lib/systemd/system/detect-classic-sysroot.service index c80e7908..5c202590 100644 --- a/factory/usr/lib/systemd/system/detect-classic-sysroot.service +++ b/factory/usr/lib/systemd/system/detect-classic-sysroot.service @@ -3,7 +3,6 @@ Description=Detect Ubuntu classic sysroot DefaultDependencies=no Before=initrd-root-device.target After=snap-initramfs-mounts.service -Wants=classic-mounts.service ConditionPathIsMountPoint=!/run/mnt/base @@ -11,3 +10,4 @@ ConditionPathIsMountPoint=!/run/mnt/base Type=oneshot RemainAfterExit=yes ExecStart=/bin/ln -s data /run/mnt/sysroot +ExecStart=/usr/lib/core/kernel-mounts diff --git a/factory/usr/lib/systemd/system/populate-writable.service b/factory/usr/lib/systemd/system/populate-writable.service index 764ff8fd..bc5e0c55 100644 --- a/factory/usr/lib/systemd/system/populate-writable.service +++ b/factory/usr/lib/systemd/system/populate-writable.service @@ -25,3 +25,4 @@ ExecStart=/usr/bin/chroot /sysroot /usr/lib/core/handle-writable-paths / /etc/sy # TODO:UC20: move the-modeenv implementation to snap-bootstrap too ExecStart=/usr/lib/the-modeenv ExecStart=/usr/lib/core/extra-paths +ExecStart=/usr/lib/core/kernel-mounts