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
signature.asc
Description: PGP signature
