]> sourceware.org Git - lvm2.git/commitdiff
filter: partitioned: also detect non-empty GPT partition table
authorPeter Rajnoha <prajnoha@redhat.com>
Wed, 4 Sep 2024 13:30:42 +0000 (15:30 +0200)
committerPeter Rajnoha <prajnoha@redhat.com>
Wed, 2 Oct 2024 09:54:01 +0000 (11:54 +0200)
We already detect msdos partition table. If it is empty, that is, there
is just the partition header and no actual partitions defined, then the
filter-partitioned passes, otherwise not.

Do the same for GPT partition table.

lib/device/dev-type.c

index c7c2a838d57300699d4beeb81145c307a25488e5..e26adcc317804fb4ac90c45211b0257f6cf0a96b 100644 (file)
@@ -505,6 +505,11 @@ int dev_get_partition_number(struct device *dev, int *num)
 #define PART_MAGIC 0xAA55
 #define PART_MAGIC_OFFSET UINT64_C(0x1FE)
 #define PART_OFFSET UINT64_C(0x1BE)
+#define PART_TYPE_GPT_PMBR UINT8_C(0xEE)
+
+#define PART_GPT_HEADER_OFFSET_LBA 0x01
+#define PART_GPT_MAGIC 0x5452415020494645UL /* "EFI PART" string */
+#define PART_GPT_ENTRIES_FIELDS_OFFSET UINT64_C(0x48)
 
 struct partition {
        uint8_t boot_ind;
@@ -570,6 +575,65 @@ static int _is_partitionable(struct dev_types *dt, struct device *dev)
        return 1;
 }
 
+static int _has_gpt_partition_table(struct device *dev)
+{
+       unsigned int pbs, lbs;
+       uint64_t entries_start;
+       uint32_t nr_entries, sz_entry, i;
+
+       struct {
+               uint64_t magic;
+               /* skip fields we're not interested in */
+               uint8_t skip[PART_GPT_ENTRIES_FIELDS_OFFSET - sizeof(uint64_t)];
+               uint64_t part_entries_lba;
+               uint32_t nr_part_entries;
+               uint32_t sz_part_entry;
+       } __attribute__((packed)) gpt_header;
+
+       struct {
+               uint64_t part_type_guid;
+               /* not interested in any other fields */
+       } __attribute__((packed)) gpt_part_entry;
+
+       if (!dev_get_direct_block_sizes(dev, &pbs, &lbs))
+               return_0;
+
+       if (!dev_read_bytes(dev, PART_GPT_HEADER_OFFSET_LBA * lbs, sizeof(gpt_header), &gpt_header))
+               return_0;
+
+       /* the gpt table is always written using LE on disk */
+
+       if (le64_to_cpu(gpt_header.magic) != PART_GPT_MAGIC)
+               return_0;
+
+       entries_start = le64_to_cpu(gpt_header.part_entries_lba) * lbs;
+       nr_entries = le32_to_cpu(gpt_header.nr_part_entries);
+       sz_entry = le32_to_cpu(gpt_header.sz_part_entry);
+
+       for (i = 0; i < nr_entries; i++) {
+               if (!dev_read_bytes(dev, entries_start + i * sz_entry,
+                                   sizeof(gpt_part_entry), &gpt_part_entry))
+                       return_0;
+
+               /* just check if the guid is nonzero, no need to call le64_to_cpu here */
+               if (gpt_part_entry.part_type_guid)
+                       return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Check if there's a partition table present on the device dev, either msdos or gpt.
+ * Returns:
+ *
+ *   1 - if it has a partition table with at least one real partition defined
+ *       (note: the gpt's PMBR partition alone does not count as a real partition)
+ *
+ *   0 - if it has no partition table,
+ *     - or if it does have a partition table, but without any partition defined,
+ *     - or on error
+ */
 static int _has_partition_table(struct device *dev)
 {
        int ret = 0;
@@ -594,10 +658,20 @@ static int _has_partition_table(struct device *dev)
                                break;
                        }
                        /* Must have at least one non-empty partition */
-                       if (buf.part[p].nr_sects)
-                               ret = 1;
+                       if (buf.part[p].nr_sects) {
+                               /*
+                                * If this is GPT's PMBR, then also
+                                * check for gpt partition table.
+                                */
+                               if (buf.part[p].sys_ind == PART_TYPE_GPT_PMBR)
+                                       ret = _has_gpt_partition_table(dev);
+                               else
+                                       ret = 1;
+                       }
                }
-       }
+       } else
+               /* Check for gpt partition table. */
+               ret = _has_gpt_partition_table(dev);
 
        return ret;
 }
This page took 0.039427 seconds and 5 git commands to generate.