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) { -- 2.55.0
