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.