From 3a00ad5263b2429a15e4915c4124d87b0d59dbfb Mon Sep 17 00:00:00 2001 From: dann frazier Date: Sat, 27 Jan 2024 20:11:35 -0700 Subject: [PATCH] Use flock to avoid races with systemd-udevd The race causes loop device partitions to briefly disappear. LP: #2045586. --- debian/changelog | 5 +++++ live-build/functions | 31 ++++++++++++++----------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/debian/changelog b/debian/changelog index 6af5771a..4847cb4b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,14 @@ livecd-rootfs (24.04.26) UNRELEASED; urgency=medium + [ Steve Langasek ] * Share live-build/ubuntu/hooks/020-ubuntu-live.chroot_early across all flavors using new-style layered squashfs, removing need for kernel commandline options in debian-cd. + [ dann frazier ] + * Use flock to avoid races with systemd-udevd that cause loop device + partitions to briefly disappear. + -- Steve Langasek Wed, 17 Jan 2024 15:52:02 -0800 livecd-rootfs (24.04.25) noble; urgency=medium diff --git a/live-build/functions b/live-build/functions index 27baea91..85e58aa3 100644 --- a/live-build/functions +++ b/live-build/functions @@ -63,36 +63,29 @@ mount_image() { backing_img="$1" local rootpart="$2" - # As explained in excruciating detail in LP: #2045586, "losetup - # -P" (a.k.a. --partscan) appears to race with udev in a way that - # prevents the device nodes for the partitions from being - # created. So instead we run losetup without -P, wait for udev to - # settle, then run partprobe and then settle udev again (which is - # probably unnecessary but at this point a bit more superstition - # can't hurt) - - loop_device=$(losetup --show -f -v ${backing_img}) + loop_device=$(losetup --show -f -P -v ${backing_img}) if [ ! -b ${loop_device} ]; then echo "unable to find loop device for ${backing_img}" exit 1 fi - udevadm settle - partprobe ${loop_device} - udevadm settle + # As explained in excruciating detail in LP: #2045586, losetup + # races with udev in a way that can cause partition device files + # to briefly vanish. systemd docs say we can hold udev off by using + # flocks: https://systemd.io/BLOCK_DEVICE_LOCKING/ + # `udevadm lock` isn't yet usable in Ubuntu, so we'll use flock for now # Find the rootfs location rootfs_dev_mapper="${loop_device}p${rootpart}" - if [ ! -b "${rootfs_dev_mapper}" ]; then + if flock -x ${loop_device} [ ! -b "${rootfs_dev_mapper}" ]; then echo "${rootfs_dev_mapper} is not a block device"; - ls -l ${loop_device}p* exit 1 fi # Add some information to the debug logs echo "Mounted disk image ${backing_img} to ${rootfs_dev_mapper}" - blkid ${rootfs_dev_mapper} \ + flock -x ${loop_device} blkid ${rootfs_dev_mapper} \ || echo "blkid failed; continuing" return 0 @@ -225,10 +218,14 @@ mount_disk_image() { mount_partition "${rootfs_dev_mapper}" $mountpoint local boot_dev="${loop_device}p16" - if [ -b ${boot_dev} -a -e $mountpoint/boot ]; then - mount "${boot_dev}" $mountpoint/boot + if flock -x ${loop_device} \ + [ -b ${boot_dev} -a -e $mountpoint/boot ]; then + flock -x ${loop_device} mount "${boot_dev}" $mountpoint/boot fi + # Having one partition mounted should avoid udev-triggered partition + # rescans on that device, so we no longer need to flock. + local uefi_dev="${loop_device}p15" if [ -b ${uefi_dev} -a -e $mountpoint/boot/efi ]; then mount "${uefi_dev}" $mountpoint/boot/efi