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.