diff --git a/rules.d/99-systemd.rules.in b/rules.d/99-systemd.rules.in index da2d311ce4..98f483503e 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 b5fb87437c..49bb0fbff3 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; - log_device_debug(dev, "GPT sector size %zi does not match device sector size %" PRIu32 ".", - 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; + } + + 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; }