Re: [PATCH 1/6] disk: part_efi: Size the partition entry array from the block size
Ilias Apalodimas <[email protected]> Tue, 4 Aug 2026 11:25:28 +0300
| Newsgroups | gmane.comp.boot-loaders.u-boot |
|---|---|
| Message-ID | <CAC_iWj+amWJLeGCXFTTtfpfGfzhbY5bHxBPWXmZW-E=LBMB1hQ@mail.gmail.com> |
On Fri, 31 Jul 2026 at 15:40, Alexey Charkov <[email protected]> wrote: > > gpt_fill_header() computes last_usable_lba and first_usable_lba from > hardcoded block counts that silently assumes 512-byte sectors and the > default number of partition entries. > > The partition entry array holds GPT_ENTRY_NUMBERS entries of 128 bytes > each, so the number of blocks it needs depends on both the entry count > and the block size. write_gpt_table() derives that count correctly and > writes the backup array at last_usable_lba + 1, so whenever the two > disagree the backup array no longer immediately precedes the backup GPT > header. Furthermore, on a device with 4096-byte native sectors, such as > UFS flash, and the default 128 entries, the array is 4 blocks rather than > 32. Current code reserves 34 blocks at each end of the disk for any block > size and wastes about 114 KiB at each end. > > Add a new helper gpt_pte_blocks() and use it in all four places which > currently calculate the number of blocks each in its own way, so the > layout written by gpt_fill_header() and the extent written by > write_gpt_table() cannot drift apart again. With this, first_usable_lba > on 4096-byte sectors is 6, last_usable_lba is lba - 6, and the backup > array occupies lba - 5 .. lba - 2, immediately preceding the backup > header, as the UEFI specification describes. > > Note that this changes the 512-byte layout too for boards that do not use > the default entry count. CONFIG_EFI_PARTITION_ENTRIES_NUMBERS is > "default 56 if ARCH_SUNXI" and is set to 64 by a number of Rockchip > defconfigs: > > entries array blocks first_usable_lba last_usable_lba > 56 14 34 -> 16 lba - 34 -> lba - 16 > 64 16 34 -> 18 lba - 34 -> lba - 18 > 128 32 34 -> 34 lba - 34 -> lba - 34 > > Existing partition tables stay readable either way, since is_gpt_valid() > locates the entry array from the on-disk partition_entry_lba. Only newly > written tables change. Partitions given without an explicit start= will > now be placed lower on those boards; on sunxi first_usable_lba lands on > the 8 KiB SPL offset, so such boards should keep specifying start= > explicitly. > > While here, report both LBAs when the requested layout does not fit, since > the existing "Partitions layout exceeds disk size" debug message gives no > clue as to by how much, making it less helpful in debugging. > > Co-developed-by: Anton Burticica <[email protected]> > Signed-off-by: Anton Burticica <[email protected]> > Signed-off-by: Alexey Charkov <[email protected]> > --- > disk/part_efi.c | 47 +++++++++++++++++++++++++++++++++++------------ > 1 file changed, 35 insertions(+), 12 deletions(-) > LGTM, but I'd like people that have been involved to take a closer look Acked-by: Ilias Apalodimas <[email protected]> > diff --git a/disk/part_efi.c b/disk/part_efi.c > index d8b17ec2e91a..af311867a285 100644 > --- a/disk/part_efi.c > +++ b/disk/part_efi.c > @@ -388,10 +388,23 @@ static int set_protective_mbr(struct blk_desc *desc) > return 0; > } > > +/** > + * gpt_pte_blocks() - number of blocks taken up by a partition entry array > + * > + * @desc: block device descriptor > + * @gpt_h: GPT header describing the array > + * Return: number of blocks the array occupies on @desc > + */ > +static u32 gpt_pte_blocks(struct blk_desc *desc, const gpt_header *gpt_h) > +{ > + return DIV_ROUND_UP(le32_to_cpu(gpt_h->num_partition_entries) * > + le32_to_cpu(gpt_h->sizeof_partition_entry), > + desc->blksz); > +} > + > int write_gpt_table(struct blk_desc *desc, gpt_header *gpt_h, gpt_entry *gpt_e) > { > - const int pte_blk_cnt = BLOCK_CNT((gpt_h->num_partition_entries > - * sizeof(gpt_entry)), desc); > + const int pte_blk_cnt = gpt_pte_blocks(desc, gpt_h); > u32 calc_crc32; > > debug("max lba: %x\n", (u32)desc->lba); > @@ -453,9 +466,7 @@ int gpt_fill_pte(struct blk_desc *desc, > size_t hdr_end = hdr_start + 1; > > size_t pte_start = gpt_h->partition_entry_lba; > - size_t pte_end = pte_start + > - gpt_h->num_partition_entries * gpt_h->sizeof_partition_entry / > - desc->blksz; > + size_t pte_end = pte_start + gpt_pte_blocks(desc, gpt_h); > > for (i = 0; i < parts; i++) { > /* partition starting lba */ > @@ -482,7 +493,9 @@ int gpt_fill_pte(struct blk_desc *desc, > gpt_e[i].starting_lba = cpu_to_le64(start); > > if (offset > (last_usable_lba + 1)) { > - log_debug("Partitions layout exceeds disk size\n"); > + log_debug("Partitions layout exceeds disk size: " > + LBAFU " > " LBAFU "\n", > + offset, last_usable_lba + 1); > return -E2BIG; > } > /* partition ending lba */ > @@ -604,18 +617,29 @@ static uint32_t partition_entries_offset(struct blk_desc *desc) > int gpt_fill_header(struct blk_desc *desc, gpt_header *gpt_h, char *str_guid, > int parts_count) > { > + u32 pte_sectors; > + > gpt_h->signature = cpu_to_le64(GPT_HEADER_SIGNATURE_UBOOT); > gpt_h->revision = cpu_to_le32(GPT_HEADER_REVISION_V1); > gpt_h->header_size = cpu_to_le32(sizeof(gpt_header)); > + gpt_h->num_partition_entries = cpu_to_le32(GPT_ENTRY_NUMBERS); > + gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry)); > + > + /* > + * Number of blocks occupied by the partition entry array. For the > + * default of 128 entries that is 32 blocks on 512-byte sectors, but > + * only 4 blocks on 4096-byte sectors. > + */ > + pte_sectors = gpt_pte_blocks(desc, gpt_h); > + > gpt_h->my_lba = cpu_to_le64(1); > gpt_h->alternate_lba = cpu_to_le64(desc->lba - 1); > - gpt_h->last_usable_lba = cpu_to_le64(desc->lba - 34); > + /* Reserve space for backup GPT header (1) + backup partition entries */ > + gpt_h->last_usable_lba = cpu_to_le64(desc->lba - pte_sectors - 2); > gpt_h->partition_entry_lba = > cpu_to_le64(partition_entries_offset(desc)); > gpt_h->first_usable_lba = > - cpu_to_le64(le64_to_cpu(gpt_h->partition_entry_lba) + 32); > - gpt_h->num_partition_entries = cpu_to_le32(GPT_ENTRY_NUMBERS); > - gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry)); > + cpu_to_le64(le64_to_cpu(gpt_h->partition_entry_lba) + pte_sectors); > gpt_h->header_crc32 = 0; > gpt_h->partition_entry_array_crc32 = 0; > > @@ -747,8 +771,7 @@ static void restore_primary_gpt_header(gpt_header *gpt_h, struct blk_desc *desc) > static int write_one_gpt_table(struct blk_desc *desc, gpt_header *gpt_h, > gpt_entry *gpt_e) > { > - const int pte_blk_cnt = BLOCK_CNT((gpt_h->num_partition_entries > - * sizeof(gpt_entry)), desc); > + const int pte_blk_cnt = gpt_pte_blocks(desc, gpt_h); > lbaint_t start; > int ret = 0; > > > -- > 2.54.0 >