From 4e0eabd40118c2607e52009c39a936c2054e6153 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Sat, 4 Apr 2026 22:24:47 +0000 Subject: [PATCH] udev: also trigger loop device for boot disk when partition scanning is unsupported MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Previously, probe_gpt_sector_size_mismatch() would bail out early when the GPT sector size matched the device sector size. However, some devices (e.g. certain CD-ROM drives) do not support kernel partition scanning even when sector sizes match. In that case, the kernel still cannot parse the partition table, and we need to set up a loop device to expose the partitions — just as we do for the sector size mismatch case. Check blockdev_partscan_enabled() when sector sizes match, and only skip the boot partition check if partition scanning is actually supported. Also rename the function, udev property, and log messages to reflect the broader scope: - probe_gpt_sector_size_mismatch() -> probe_gpt_boot_disk_needs_loop() - ID_PART_GPT_AUTO_ROOT_DISK_SECTOR_SIZE_MISMATCH -> ID_PART_GPT_AUTO_ROOT_DISK_NEEDS_LOOP --- rules.d/99-systemd.rules.in | 8 ++++---- src/udev/udev-builtin-blkid.c | 34 ++++++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/rules.d/99-systemd.rules.in b/rules.d/99-systemd.rules.in index da2d311ce49..98f483503e2 100644 --- a/rules.d/99-systemd.rules.in +++ b/rules.d/99-systemd.rules.in @@ -89,10 +89,10 @@ SUBSYSTEM=="module", KERNEL=="configfs", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sy SUBSYSTEM=="tpmrm", KERNEL=="tpmrm[0-9]*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="tpm2.target" SUBSYSTEM=="tpm", KERNEL=="tpm[0-9]*", TAG+="systemd" -# If the GPT sector size doesn't match the device's native sector size (e.g. 512-byte GPT on a -# 2048-byte CD-ROM booted via El Torito), trigger a loop device to re-expose it with the correct -# sector size so the kernel can parse the partition table. -SUBSYSTEM=="block", ENV{ID_PART_GPT_AUTO_ROOT_DISK_SECTOR_SIZE_MISMATCH}=="1", \ +# If the kernel cannot parse the GPT partition table on the boot disk (e.g. due to a sector size +# mismatch on a CD-ROM booted via El Torito, or because the device does not support partition +# scanning), trigger a loop device to expose the partitions. +SUBSYSTEM=="block", ENV{ID_PART_GPT_AUTO_ROOT_DISK_NEEDS_LOOP}=="1", \ ENV{SYSTEMD_WANTS}+="systemd-loop@.service" LABEL="systemd_end" diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c index b5fb87437c0..49bb0fbff37 100644 --- a/src/udev/udev-builtin-blkid.c +++ b/src/udev/udev-builtin-blkid.c @@ -422,7 +422,7 @@ notloop: return 0; } -static int probe_gpt_sector_size_mismatch(UdevEvent *event, int fd) { +static int probe_gpt_boot_disk_needs_loop(UdevEvent *event, int fd) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); int r; @@ -431,7 +431,11 @@ static int probe_gpt_sector_size_mismatch(UdevEvent *event, int fd) { * check if this is the boot disk by comparing GPT partition UUIDs with the ESP/XBOOTLDR UUID * exported by the boot loader. If it matches, set a property so that udev rules can set up a * loop device with the correct sector size — the kernel can't parse the partition table itself - * in this case. */ + * in this case. + * + * Even if the sector sizes match, if the device does not support partition scanning (e.g. some + * CD-ROM drives), the kernel still can't parse the partition table. In that case, if the disk + * contains the ESP we booted from, we still need a loop device to expose the partitions. */ _cleanup_free_ void *entries = NULL; uint32_t n_entries, entry_size; @@ -446,11 +450,21 @@ static int probe_gpt_sector_size_mismatch(UdevEvent *event, int fd) { if (r < 0) return log_device_debug_errno(dev, r, "Failed to get device sector size: %m"); - if ((uint32_t) gpt_ssz == device_ssz) - return 0; + bool sector_size_mismatch = (uint32_t) gpt_ssz != device_ssz; + + if (!sector_size_mismatch) { + r = blockdev_partscan_enabled(dev); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to check if partition scanning is enabled: %m"); + if (r > 0) + return 0; + } - log_device_debug(dev, "GPT sector size %zi does not match device sector size %" PRIu32 ".", - gpt_ssz, device_ssz); + if (sector_size_mismatch) + log_device_debug(dev, "GPT sector size %zi does not match device sector size %" PRIu32 ".", + gpt_ssz, device_ssz); + else + log_device_debug(dev, "Device does not support partition scanning."); sd_id128_t loader_part_uuid; r = efi_loader_get_device_part_uuid(&loader_part_uuid); @@ -471,10 +485,10 @@ static int probe_gpt_sector_size_mismatch(UdevEvent *event, int fd) { if (!sd_id128_equal(efi_guid_to_id128(entry->unique_partition_guid), loader_part_uuid)) continue; - log_device_debug(dev, "Found boot partition (ESP/XBOOTLDR) on disk with sector size mismatch."); - udev_builtin_add_property(event, "ID_PART_GPT_AUTO_ROOT_DISK_SECTOR_SIZE_MISMATCH", "1"); + log_device_debug(dev, "Found boot partition (ESP/XBOOTLDR) on disk where kernel cannot scan partitions."); + udev_builtin_add_property(event, "ID_PART_GPT_AUTO_ROOT_DISK_NEEDS_LOOP", "1"); udev_builtin_add_propertyf(event, "ID_PART_GPT_SECTOR_SIZE", "%zi", gpt_ssz); - return 1; /* mismatch detected and handled */ + return 1; /* boot disk needs loop device */ } return 0; @@ -548,7 +562,7 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[]) { } if (offset == 0) { - r = probe_gpt_sector_size_mismatch(event, fd); + r = probe_gpt_boot_disk_needs_loop(event, fd); if (r > 0) return 0; } -- 2.47.3