Sashiko AI code review pointed out, during arm64 kexec image placement retry loops in image_load(), the loader repeatedly attempts to find a suitable memory hole for the kernel and its associated segments (initrd, dtb, etc.). When a placement attempt fails midway, the core framework rolls back `image->nr_segments` to its initial state to purge the failed segments logically.
However, this truncation causes a severe background memory leak. Any CMA pages successfully allocated via kexec_add_buffer() during the failed attempt are recorded in the `image->segment_cma` array. Since the subsequent global kimage_free_cma() cleanup only iterates up to the truncated (smaller) `nr_segments` boundary, these allocated CMA pages outside the new boundary become completely orphaned and permanently leaked. Fix this by leverage the newly introduced generic kexec_free_segment_cma() helper to execute fine-grained memory reclamation before any truncation occurs: 1. In image_load(), explicitly invoke kexec_free_segment_cma() to release the CMA buffer allocated for the current failed kernel segment before decrementing `image->nr_segments`. 2. In the error path of load_other_segments(), iterate backward from the failed segment index down to `orig_segments`, sequentially freeing each orphan CMA segment allocation before restoring the initial segment count. This guarantees that all temporary CMA pages allocated during placement failures are cleanly returned to the contiguous memory allocator, eliminating silent background memory leaks across all retry paths. Cc: Catalin Marinas <[email protected]> Cc: Will Deacon <[email protected]> Cc: Breno Leitao <[email protected]> Cc: Pratyush Yadav <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Yeoreum Yun <[email protected]> Cc: Kees Cook <[email protected]> Cc: "Rob Herring (Arm)" <[email protected]> Cc: Baoquan He <[email protected]> Cc: Coiby Xu <[email protected]> Cc: Alexander Graf <[email protected]> Cc: Pasha Tatashin <[email protected]> Cc: [email protected] Fixes: 07d24902977e4 ("kexec: enable CMA based contiguous allocation") Signed-off-by: Jinjie Ruan <[email protected]> --- arch/arm64/kernel/kexec_image.c | 1 + arch/arm64/kernel/machine_kexec_file.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c index b70f4df15a1a..ffcb7f9075e6 100644 --- a/arch/arm64/kernel/kexec_image.c +++ b/arch/arm64/kernel/kexec_image.c @@ -107,6 +107,7 @@ static void *image_load(struct kimage *image, * We couldn't find space for the other segments; erase the * kernel segment and try the next available hole. */ + kexec_free_segment_cma(image, kernel_segment_number); image->nr_segments -= 1; kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz; kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c index e31fabed378a..13c247c28866 100644 --- a/arch/arm64/kernel/machine_kexec_file.c +++ b/arch/arm64/kernel/machine_kexec_file.c @@ -195,7 +195,10 @@ int load_other_segments(struct kimage *image, return 0; out_err: - image->nr_segments = orig_segments; + while (image->nr_segments > orig_segments) { + kexec_free_segment_cma(image, image->nr_segments - 1); + image->nr_segments--; + } kvfree(dtb); return ret; } -- 2.34.1
