bug#79720: libparted: wrong metadata length with empty GPT partition table

Pascal Hambourg <[email protected]> Sat, 1 Nov 2025 00:00:40 +0100
Newsgroups gmane.comp.gnu.parted.bugs
Organization Plouf !
Message-ID <[email protected]>
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.