On 31/10/2025 at 22:53, Brian C. Lane wrote:

When libparted reads an existing empty GPT partition table, it wrongly
creates the main and backup virtual metadata partitions with a length based
on GPT_DEFAULT_PARTITION_ENTRIES (128) instead of the actual partition table
length based on NumberOfPartitionEntries in the GPT header. Only after an
active partition is added (either read from the on-disk partition table or
new), the metadata partitions have the correct length.

Looking at libparted/label/gpt.c, it seems that gpt_read() initializes the
partition table object with GPT_DEFAULT_PARTITION_ENTRIES and does not
trigger an update of metadata and free space after parsing the GPT header
but only when partitions are added.

I've tried to figure out where this could be going wrong, but am not
seeing it. When gpt_alloc is called it sets gpt_disk_data->entry_count
to the default. But when gpt_read is called it calls _parse_header, and
parse_header sets entry_count from the value it read from the header
(gpt->NumberOfPartitionEntries).

Here is the (trimmed) call chain as I understand it:

ped_disk_new
  ped_disk_new_fresh
    type->ops->alloc (-> gpt_alloc)
      _ped_disk_alloc
      gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES
    _disk_pop_update_mode <- update metadata and free space
  type->ops->read (-> gpt_read)
    ped_disk_delete_all
    gpt_read_headers
    _parse_header
      gpt_disk_data->entry_count = gpt->NumberOfPartitionEntries
    gpt_read_PE_array
    for each active partition entry
      _parse_part_entry
      ped_disk_add_partition
        _disk_push_update_mode
        _disk_raw_add
        _disk_pop_update_mode <- update metadata and free space

Indeed _parse_header updates entry_count, but then _disk_pop_update_mode (which updates metadata and free space partitions) is called only if the partition table has at least one active partition. Or later when a new partition is created, or the pmbr_boot flag is set.

I quickly tested that surrounding the call to type->ops->read with _disk_push_update_mode and _disk_pop_update_mode in ped_disk_new seems to fix the issue:

diff --git a/libparted/disk.c b/libparted/disk.c
index 2d6b9d49..768f4681 100644
--- a/libparted/disk.c
+++ b/libparted/disk.c
@@ -199,8 +199,10 @@ ped_disk_new (PedDevice* dev)
        if (!disk)
                goto error_close_dev;
+       _disk_push_update_mode (disk);
        if (!type->ops->read (disk))
                goto error_destroy_disk;
+       _disk_pop_update_mode (disk);
        disk->needs_clobber = 0;
        ped_device_close (dev);
        return disk;

But I am now working on a larger patch which aims to stay in update mode and avoid useless transient metadata and free space partition updates until after reading the partition table. Would it be welcome ?

I do agree that parted has problems with relocated partition tables, I
think the first thing to do there is to detect that and raise an
exception instead of rewriting it to LBA 2.
I observed this issue and found related bug #68379. But IMO it is a totally unrelated issue which should be addressed separately.



Reply via email to