main/postmarketos-initramfs: use loop device for subpartitions

This reworks the subpartition init to use loop devices instead of
kpartx/dm mappings. This allows us to use the same logic for resizing
as we do for other partitioning schemes (and refactors that code a bit).
This also helps duranium, because systemd tooling (repart, sysupdate,
gpt-auto-generator) can't properly handle GPT subpartitions exposed via
kpartx dm mappings, but works correctly with loop devices created with
partition scanning enabled.

After this change, subpartitions show up as loop devices, e.g.:

$ ls /dev/loop*
/dev/loop0p1
/dev/loop0p2

There *should* be no impact to existing installs.

This also drops the dependency on multipath-tools, which seems to have
been added years ago as a workaround for installing kpartx (like maybe
multipath-tools used to provide kpartx?), see 7573f5fce4. Anyways, we
don't use anything in this pkg in the initramfs AFAIK.

Signed-off-by: Clayton Craft <craftyguy@postmarketos.org>
Part-of: <https://gitlab.postmarketos.org/postmarketOS/pmaports/-/merge_requests/7932>
This commit is contained in:
Clayton Craft 2026-02-05 00:01:38 -08:00 committed by The Friendly Meow (merge) Bot
parent fd38701c35
commit 86bdb82116
No known key found for this signature in database
5 changed files with 59 additions and 65 deletions

View file

@ -5,7 +5,7 @@
/sbin/blkid
/usr/bin/iskey
/usr/bin/unudhcpd
/usr/sbin/kpartx
/usr/sbin/losetup
/usr/share/deviceinfo/deviceinfo
/usr/share/initramfs/init_functions.sh:/init_functions.sh
/usr/share/initramfs/init.sh:/init

View file

@ -7,7 +7,6 @@
/usr/lib/udev/rules.d/60-persistent-input.rules
/usr/lib/udev/rules.d/60-persistent-storage.rules
/usr/lib/udev/rules.d/64-btrfs.rules
/usr/lib/udev/rules.d/66-kpartx.rules
/usr/lib/udev/rules.d/70-mouse.rules
/usr/lib/udev/rules.d/70-touchpad.rules
/usr/lib/udev/rules.d/80-drivers.rules

View file

@ -1,7 +1,7 @@
# Co-Maintainer: Clayton Craft <clayton@craftyguy.net>
maintainer="Casey Connolly <kcxt@postmarketos.org>"
pkgname=postmarketos-initramfs
pkgver=3.8.12
pkgver=3.9.0
pkgrel=0
pkgdesc="Base files for the postmarketOS initramfs / initramfs-extra"
url="https://postmarketos.org"
@ -28,8 +28,8 @@ depends="
iskey
kmod
libinput-libs
losetup
lz4
multipath-tools
parted
postmarketos-fde-unlocker
postmarketos-mkinitfs>=2.2
@ -117,12 +117,12 @@ sha512sums="
22cdd663c8d153781284511140b7c994cd60f0231a2819dafa67f5a11e2963ac6e392e8f7a9e3b75e7fe5d6d7b0b5e262e1ff1a695637354a124560a5ec3ed8d 00-default.modules
ace852ba267b3408998970df6042603c8bec1d033066d1c30ed65f1be955fee8644b57882898f10228ec43b912f8f03718b34ddd741b431e5a5c2e76f060a494 00-default-extra.modules
9c0e8f6f61d5da191e03a1aa9d5d0ceb5baf1eae6dbb9bfb0af59817783525119ac8394b135f303f7b6434a3eab0b49185fb90379e06823db847a4999c75ce33 00-initramfs-base.dirs
9b5f5bc68ede0b06b85260d9ad301892e7b45ebad7e78300be17c8a55e3fdf392b3302587bd47011ce52f213e034a0cb49d0a2b96ab012fb5dce0514f4575aa7 00-initramfs-base.files
3c021f6ede0c13469097a8aaeb15810baf2f3be52e10928f3475ac3568d855e3ab8e747b960d47ac6af6f7f223fca5e7da12098810502e0dae55aaf6bf4f293c 00-initramfs-extra-base.files
26e391a2c45e4317549153630d7398f01cf374d9a95e2587f0f7153017c50b6640950af60eab3b3fcadef2e8826295445ac1f45567716d3bd5d12e9c87df599b 00-initramfs-base.files
cc4db00caba184ad78062505415b3dadb8a32a94fe8484e4860bb6e63cd8700c8450066ce1242c496d9f063234bbab0fa40668f9c5112f3baeee30c5d405a1eb 00-initramfs-extra-base.files
e90596540805662211bd2a2e427ce7cc38f6a30023267f902e23f2bae136b6cd8f4f4716b8fb611be9d671a964edd2ecce03fa32bc8024e29b8375b0097fde0c init.sh
8b0f15b84795588822a8b07b1e43ef0034da5f982ab92f0e7d3b9359fc61121f3f961006ba7d3f98f16d127d37ba833926654831b39e2df83d7384eebc786d3d init_functions.sh
3fd828e3ae67df2c3c1de9a0c2cdd087a4bc2a34029035b3fb74d410c9b46fd37b7e908eacdd65ee88b41cadb950a14f2b7c75c32bee413acbf5382dd5d1f7f2 init_functions.sh
6b4881f9b43c90ebcc70d7b7a192d26a2e3ce01c43b8536fe900c2ffaf74ef035803b9aa083e7a9d5c49c75be8ba6ff22997a037ae4f399e6ee5e1978c4b3f9c init_2nd.sh
de14f6f678856ae316f28c003a6293a383aa6b7cbb19951b981430eb0e3b91d0634dedf62d29d105845b6e172daa18e6b6e45e03342d72ae806ca611a1236d18 init_functions_2nd.sh
61acb470a163fb50ad46752781b5ccc5dba6db9170e4250b4dcdfc7572d0316a7a36bc5a383026887a7a59364ee30917790e429b3fce9de590543d1d8410589c init_functions_2nd.sh
675e7d5bee39b2df7d322117f8dcaccc274d61beaf4d50ead19bbf2109446d64b1c0aa0c5b4f9846eb6c1c403418f28f6364eff4537ba41120fbfcbc484b7da7 mdev.conf
ba3275a9af788c7c782322a22a0f144d5e50e3498ea6886486a29331f23ae89cd32d500a3635cfa7cab369afba92edc18aeca64ccbf0cd589061cce23d15b46c unudhcpd.conf
"

View file

@ -7,6 +7,7 @@
PMOS_BOOT="${PMOS_BOOT:-}"
PMOS_ROOT="${PMOS_ROOT:-}"
SUBPARTITION_DEV="${SUBPARTITION_DEV:-}"
SUBPARTITION_LOOP="${SUBPARTITION_LOOP:-}"
CONFIGFS="/config/usb_gadget"
CONFIGFS_ACM_FUNCTION="acm.usb0"
@ -18,6 +19,7 @@ deviceinfo_name="${deviceinfo_name:-}"
deviceinfo_codename="${deviceinfo_codename:-}"
deviceinfo_create_initfs_extra="${deviceinfo_create_initfs_extra:-}"
deviceinfo_no_framebuffer="${deviceinfo_no_framebuffer:-}"
deviceinfo_rootfs_image_sector_size="${deviceinfo_rootfs_image_sector_size:-}"
# Does word start with prefix?
startswith() {
@ -356,6 +358,10 @@ mount_subpartitions() {
[ -e "$x" ] && android_parts="$android_parts $x"
done
local losetup_args="--show -Pfv --direct-io=on"
if [ -n "$deviceinfo_rootfs_image_sector_size" ]; then
losetup_args="$losetup_args --sector-size $deviceinfo_rootfs_image_sector_size"
fi
attempt_start=$(get_uptime_seconds)
wait_seconds=10
echo "Trying to mount subpartitions for $wait_seconds seconds..."
@ -366,26 +372,30 @@ mount_subpartitions() {
for partition in $partitions; do
# Skip whole disks - only check partitions and logical device-mapper devices for subpartitions
[ -e "/sys/class/block/$(basename "$partition")/partition" ] || [ -d "/sys/class/block/$(basename "$partition")/dm" ] || continue
case "$(kpartx -l "$partition" 2>/dev/null | wc -l)" in
2)
echo "Mount subpartitions of $partition"
SUBPARTITION_DEV="$partition"
kpartx -afs "$partition"
# Ensure that this was the *correct* subpartition
# Some devices have mmc partitions that appear to have
# subpartitions, but aren't our subpartition.
find_root_partition
if [ -n "$PMOS_ROOT" ]; then
break
fi
kpartx -d "$partition"
local part_count
part_count="$(parted -s "$partition" print 2>/dev/null | grep -c '^ [0-9]')"
# It's probably the right "disk" if it has 2 partitions on it
if [ "$part_count" -eq 2 ]; then
echo "Mount subpartitions of $partition"
SUBPARTITION_DEV="$partition"
# shellcheck disable=SC2086
SUBPARTITION_LOOP="$(losetup $losetup_args "$partition")"
if [ -z "$SUBPARTITION_LOOP" ]; then
echo "WARNING: failed to create loop device for $partition"
SUBPARTITION_DEV=""
continue
;;
*)
continue
;;
esac
fi
# Ensure that this was the *correct* subpartition
# Some devices have mmc partitions that appear to have
# subpartitions, but aren't our subpartition.
find_root_partition
if [ -n "$PMOS_ROOT" ]; then
break
fi
[ -n "$SUBPARTITION_LOOP" ] && losetup -vd "$SUBPARTITION_LOOP"
SUBPARTITION_DEV=""
SUBPARTITION_LOOP=""
fi
done
if [ "$(get_uptime_seconds)" -ge $(( attempt_start + wait_seconds )) ]; then
echo "ERROR: failed to mount subpartitions!"

View file

@ -31,42 +31,23 @@ resize_root_partition() {
return
fi
# Only resize the partition if it's inside the device-mapper, which means
# that the partition is stored as a subpartition inside another one.
# In this case we want to resize it to use all the unused space of the
# external partition.
if [ -z "${partition##"/dev/mapper/"*}" ] || [ -z "${partition##"/dev/dm-"*}" ]; then
# Get physical device
if [ -n "$SUBPARTITION_DEV" ]; then
partition_dev="$SUBPARTITION_DEV"
else
partition_dev=$(dmsetup deps -o blkdevname "$partition" | \
awk -F "[()]" '{print "/dev/"$2}')
fi
if has_unallocated_space "$partition_dev"; then
echo "Resize root partition ($partition)"
# unmount subpartition, resize and remount it
kpartx -d "$partition"
parted -f -s "$partition_dev" resizepart 2 100%
kpartx -afs "$partition_dev"
else
echo "Not resizing root partition ($partition): no free space left"
fi
local resize_dev="" check_dev="" partnum=2
# Always resize if using subpartitions, which means the partition
# is stored as a nested GPT inside another partition. In this case we want to
# resize the GPT so the inner root partition can make use of all the available
# space.
if [ -n "$SUBPARTITION_LOOP" ]; then
#
resize_dev="$SUBPARTITION_LOOP"
check_dev="$SUBPARTITION_LOOP"
# Resize the root partition (non-subpartitions). Usually we do not want
# this, except for QEMU devices and non-android devices (e.g.
# PinePhone). For them, it is fine to use the whole storage device and
# so we pass PMOS_FORCE_PARTITION_RESIZE as kernel parameter.
elif [ "$force_partition_resize" = "y" ]; then
partition_dev="$(echo "$partition" | sed -E 's/p?2$//')"
if has_unallocated_space "$partition_dev"; then
echo "Resize root partition ($partition)"
parted -f -s "$partition_dev" resizepart 2 100%
partprobe
else
echo "Not resizing root partition ($partition): no free space left"
fi
check_dev="$(echo "$partition" | sed -E 's/p?2$//')"
resize_dev="$check_dev"
# Resize the root partition (non-subpartitions) on Chrome OS devices.
# Match $deviceinfo_cgpt_kpart not being empty instead of cmdline
# because it does not make sense here as all these devices use the same
@ -74,17 +55,21 @@ resize_root_partition() {
# second, because these devices have an additional kernel partition
# at the start.
elif [ -n "$deviceinfo_cgpt_kpart" ]; then
partition_dev="$(echo "$partition" | sed -E 's/p?3$//')"
if has_unallocated_space "$partition_dev"; then
echo "Resize root partition ($partition)"
parted -f -s "$partition_dev" resizepart 3 100%
partprobe
else
echo "Not resizing root partition ($partition): no free space left"
fi
check_dev="$(echo "$partition" | sed -E 's/p?3$//')"
resize_dev="$check_dev"
partnum=3
else
echo "Unable to resize root partition: failed to find qualifying partition"
return
fi
# Resize if needed
if has_unallocated_space "$check_dev"; then
echo "Resize root partition ($partition)"
parted -f -s "$resize_dev" resizepart "$partnum" 100%
partprobe
else
echo "Not resizing root partition ($partition): no free space left"
fi
}