On Fri, 31 Jul 2026 at 15:40, Alexey Charkov <[email protected]> wrote:
>
> Add a test that runs gpt_fill_header() and gpt_fill_pte() over a range of
> block sizes and checks that the partition entry array is sized and placed
> consistently, in particular that the backup array ends exactly where the
> backup GPT header begins.
>
> Neither function performs any block I/O, so the test builds a synthetic
> struct blk_desc rather than needing a block device with a configurable
> block size. The expected array size is taken from the GPT header fields
> rather than from GPT_ENTRY_NUMBERS, so the test still holds for builds
> with a non-default CONFIG_EFI_PARTITION_ENTRIES_NUMBERS, such as
> ARCH_SUNXI with 56 entries.
>
> Without the preceding fixes this fails on the first block size other than
> 512:
>
>   test/dm/part.c:313, dm_test_part_gpt_blksz():
>       entry_lba + pte_blks == first_lba: Expected 0x12 (18), got 0x22 (34)
>
> Signed-off-by: Alexey Charkov <[email protected]>
> ---

Acked-by: Ilias Apalodimas <[email protected]>

>  test/dm/part.c | 100 
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 100 insertions(+)
>
> diff --git a/test/dm/part.c b/test/dm/part.c
> index ad37d7f406f4..4b48322fb807 100644
> --- a/test/dm/part.c
> +++ b/test/dm/part.c
> @@ -5,6 +5,8 @@
>
>  #include <dm.h>
>  #include <env.h>
> +#include <malloc.h>
> +#include <memalign.h>
>  #include <mmc.h>
>  #include <part.h>
>  #include <part_efi.h>
> @@ -248,3 +250,101 @@ static int dm_test_part_get_info_by_uuid(struct 
> unit_test_state *uts)
>         return 0;
>  }
>  DM_TEST(dm_test_part_get_info_by_uuid, UTF_SCAN_PDATA | UTF_SCAN_FDT);
> +
> +/*
> + * Check that the GPT layout adapts to the block size of the device. Neither
> + * gpt_fill_header() nor gpt_fill_pte() does any block I/O, so a synthetic
> + * descriptor is enough here; partition_entries_offset() reads the device 
> tree
> + * '/config' node, which is available without scanning for devices.
> + */
> +static int dm_test_part_gpt_blksz(struct unit_test_state *uts)
> +{
> +       static const struct {
> +               unsigned long blksz;
> +               lbaint_t lba;
> +       } cases[] = {
> +               {   512, 0x2000 },      /* 4MB, the traditional 34-block 
> layout */
> +               {  1024, 0x1000 },
> +               {  2048,  0x800 },
> +               {  4096,  0x400 },      /* 4K native media, e.g. UFS */
> +               {  8192,  0x200 },
> +               { 16384,  0x100 },      /* the array fits in a single 
> block... */
> +               { 32768,   0x40 },      /* ...on a device smaller than 34 
> blocks */
> +       };
> +
> +       char str_disk_guid[UUID_STR_LEN + 1] =
> +               "8d60b397-1bb6-4d33-80ee-b1587d24c2f8";
> +       struct disk_partition part;
> +       struct blk_desc desc;
> +       gpt_header gpt_h;
> +       gpt_entry *gpt_e;
> +       int i;
> +
> +       gpt_e = calloc(GPT_ENTRY_NUMBERS, sizeof(gpt_entry));
> +       ut_assertnonnull(gpt_e);
> +
> +       for (i = 0; i < ARRAY_SIZE(cases); i++) {
> +               u64 entry_lba, first_lba, last_lba;
> +               u32 pte_blks;
> +
> +               memset(&desc, '\0', sizeof(desc));
> +               memset(&gpt_h, '\0', sizeof(gpt_h));
> +               desc.blksz = cases[i].blksz;
> +               desc.log2blksz = LOG2(desc.blksz);
> +               desc.lba = cases[i].lba;
> +
> +               ut_assertok(gpt_fill_header(&desc, &gpt_h, str_disk_guid, 1));
> +
> +               /*
> +                * Size the array with BLOCK_CNT() rather than the
> +                * DIV_ROUND_UP() that gpt_pte_blocks() uses, so that this
> +                * checks the layout instead of restating the implementation.
> +                */
> +               pte_blks = BLOCK_CNT(le32_to_cpu(gpt_h.num_partition_entries) 
> *
> +                                    
> le32_to_cpu(gpt_h.sizeof_partition_entry),
> +                                    (&desc));
> +               entry_lba = le64_to_cpu(gpt_h.partition_entry_lba);
> +               first_lba = le64_to_cpu(gpt_h.first_usable_lba);
> +               last_lba = le64_to_cpu(gpt_h.last_usable_lba);
> +
> +               ut_asserteq_64(1, le64_to_cpu(gpt_h.my_lba));
> +               ut_asserteq_64(desc.lba - 1, 
> le64_to_cpu(gpt_h.alternate_lba));
> +
> +               /* the primary array ends where the usable area begins */
> +               ut_assert(entry_lba >= 2);
> +               ut_asserteq_64(entry_lba + pte_blks, first_lba);
> +               ut_assert(first_lba < last_lba);
> +
> +               /*
> +                * write_gpt_table() puts the backup array at
> +                * last_usable_lba + 1, so it has to end exactly where the
> +                * backup header begins
> +                */
> +               ut_asserteq_64(le64_to_cpu(gpt_h.alternate_lba),
> +                              last_lba + 1 + pte_blks);
> +
> +               /* a partition with no start and no size fills the disk */
> +               memset(&part, '\0', sizeof(part));
> +               disk_partition_set_uuid(&part, str_disk_guid);
> +               ut_assertok(gpt_fill_pte(&desc, &gpt_h, gpt_e, &part, 1));
> +               ut_asserteq_64(first_lba, le64_to_cpu(gpt_e[0].starting_lba));
> +               ut_asserteq_64(last_lba, le64_to_cpu(gpt_e[0].ending_lba));
> +
> +               /* a partition overlapping the entry array is rejected */
> +               part.start = entry_lba;
> +               part.size = 1;
> +               ut_asserteq(-ENOSPC,
> +                           gpt_fill_pte(&desc, &gpt_h, gpt_e, &part, 1));
> +
> +               /* so is one running past the end of the usable area */
> +               part.start = first_lba;
> +               part.size = last_lba - first_lba + 2;
> +               ut_asserteq(-E2BIG,
> +                           gpt_fill_pte(&desc, &gpt_h, gpt_e, &part, 1));
> +       }
> +
> +       free(gpt_e);
> +
> +       return 0;
> +}
> +DM_TEST(dm_test_part_gpt_blksz, 0);
>
> --
> 2.54.0
>

Reply via email to