On Fri, Oct 02, 2026 at 03:02:21PM +0200, Benoît Monin wrote:
> The simple malloc used in SPL has a no-op free(), so allocating the
> GPT partition entries buffer on every partition table read leaks
> memory. With repeated lookups, SPL can exhaust its small heap.
> 
> Keep a single cached buffer and reuse it while the allocation size
> does not change. The entries are re-read on every call, so the buffer
> is device- and LBA-agnostic.
> 
> It is safe to reuse the same buffer in the single-threaded xPL context
> as the returned pointer is only ever handed out within a single
> partition-table lookup and every caller consumes or copies the entries
> before the next lookup.
> 
> The change is gated on CONFIG_IS_ENABLED(SYS_MALLOC_SIMPLE), so builds
> with a real free() (U-Boot proper) keep the original malloc/free behavior.
> 
> Signed-off-by: Benoît Monin <[email protected]>
> ---
>  disk/part_efi.c | 25 +++++++++++++++++++++----
>  1 file changed, 21 insertions(+), 4 deletions(-)
> 
> diff --git a/disk/part_efi.c b/disk/part_efi.c
> index d8b17ec2e91..8a57fe911c4 100644
> --- a/disk/part_efi.c
> +++ b/disk/part_efi.c
> @@ -1141,7 +1141,7 @@ static int find_valid_gpt(struct blk_desc *desc, 
> gpt_header *gpt_head,
>  static gpt_entry *alloc_read_gpt_entries(struct blk_desc *desc,
>                                        gpt_header *pgpt_head)
>  {
> -     size_t count = 0, blk_cnt;
> +     size_t count = 0, blk_cnt, size;
>       lbaint_t blk;
>       gpt_entry *pte = NULL;
>  
> @@ -1158,10 +1158,27 @@ static gpt_entry *alloc_read_gpt_entries(struct 
> blk_desc *desc,
>                 (u32)le32_to_cpu(pgpt_head->sizeof_partition_entry),
>                 (ulong)count);
>  
> +     size = PAD_TO_BLOCKSIZE(count, desc);
> +
>       /* Allocate memory for PTE, remember to FREE */
> -     if (count != 0) {
> -             pte = memalign(ARCH_DMA_MINALIGN,
> -                            PAD_TO_BLOCKSIZE(count, desc));
> +     if (CONFIG_IS_ENABLED(SYS_MALLOC_SIMPLE)) {
> +             /*
> +              * The simple malloc has a no-op free(): keep one
> +              * buffer and reuse it. The entries are re-read on
> +              * every call, so the buffer is device- and LBA-agnostic.
> +              */
> +             static gpt_entry *cache;
> +             static size_t cache_size;
> +
> +             if (cache && cache_size == size) {
> +                     pte = cache;
> +             } else {
> +                     pte = memalign(ARCH_DMA_MINALIGN, size);
> +                     cache = pte;
> +                     cache_size = size;
> +             }
> +     } else {
> +             pte = memalign(ARCH_DMA_MINALIGN, size);
>       }
>  
>       if (count == 0 || pte == NULL) {

This doesn't seem identical in the non-SPL case, since now pte is always
assigned. Or am I missing something?

-- 
Tom

Attachment: signature.asc
Description: PGP signature

Reply via email to