The lowmem and the global bootmem area are reserved unconditionally, while the per-node loop below already skips nodes whose size works out to 0. Either can legitimately be 0: the global size is the scaled total minus the lowmem one, so it is 0 whenever all measured reservations fit below ARCH_LOW_ADDRESS_LIMIT. Reserving 0 bytes still succeeds, so an area covering nothing gets recorded with a valid address. That is not neutral: kho_bootmem_overlap() reports an overlap for any request straddling that address, and memblock_alloc_hugetlb() aligns a request to its page size, so a 1G hugetlb allocation retries a free candidate on account of an area that holds nothing. A machine whose memory all starts at or above ARCH_LOW_ADDRESS_LIMIT hits the other side of the same code: the lowmem size is 0, the range below the limit is empty, the allocation fails and KHO is disabled although no lowmem area was needed. Skip a zero-sized area instead, as the per-node loop does. The descriptor count stays consistent, as kho_populate() derives it from the segment length that kho_fill_kimage() serialises. Fixes: 3dc92c311498 ("kexec: add Kexec HandOver (KHO) generation helpers") Signed-off-by: Chen Pei --- kernel/liveupdate/kexec_handover.c | 38 +++++++++++++++++------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c index 6f1f55fe3..c9c9fdfac 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -853,28 +853,32 @@ static void __init kho_reserve_bootmem(void) * next kernel */ size = bootmem_size_lowmem; - addr = memblock_phys_alloc_range(size, BOOTMEM_ALIGNMENT_BYTES, 0, - ARCH_LOW_ADDRESS_LIMIT); - if (!addr) { - pr_err("Failed to reserve lowmem bootmem\n"); - goto err_free_bootmem_desc; - } + if (size) { + addr = memblock_phys_alloc_range(size, BOOTMEM_ALIGNMENT_BYTES, + 0, ARCH_LOW_ADDRESS_LIMIT); + if (!addr) { + pr_err("Failed to reserve lowmem bootmem\n"); + goto err_free_bootmem_desc; + } - kho_bootmem[i].addr = addr; - kho_bootmem[i].size = size; - i++; + kho_bootmem[i].addr = addr; + kho_bootmem[i].size = size; + i++; + } /* reserve large contiguous area for allocations without nid */ size = bootmem_size_global; - addr = memblock_phys_alloc(size, BOOTMEM_ALIGNMENT_BYTES); - if (!addr) { - pr_err("Failed to reserve global bootmem\n"); - goto err_free_bootmem_areas; - } + if (size) { + addr = memblock_phys_alloc(size, BOOTMEM_ALIGNMENT_BYTES); + if (!addr) { + pr_err("Failed to reserve global bootmem\n"); + goto err_free_bootmem_areas; + } - kho_bootmem[i].addr = addr; - kho_bootmem[i].size = size; - i++; + kho_bootmem[i].addr = addr; + kho_bootmem[i].size = size; + i++; + } /* * Loop over nodes that have both memory and are online. Skip -- 2.50.1