summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorPratyush Yadav (Google) <pratyush@kernel.org>2026-10-14 15:15:44 +0200
committerMike Rapoport (Microsoft) <rppt@kernel.org>2026-10-15 11:37:32 +0300
commit9a6a70aefe77f6fb9ff2b3037dcf87f6dff65c8c (patch)
tree87e2d029112386000ca25821c1583dd33ba5a7fd /kernel
parent48e6e4202e12af36671c6479b9ebcb8212d37cbb (diff)
downloadlinux-9a6a70aefe77f6fb9ff2b3037dcf87f6dff65c8c.tar.gz
linux-9a6a70aefe77f6fb9ff2b3037dcf87f6dff65c8c.zip
kho: do not reserve empty per-node bootmem areas
Some nodes do not allocate any early boot memory. An example is hotpluggable nodes with movable_node enabled. So the bootmem size for them ends up being zero. Zero size allocations normally don't play well with memblock. Memblock returns an address, but then doesn't actually reserve anything. This address ends up being recorded in kho_bootmem with a size of 0. In case of hotpluggable nodes with movable_nodes, the allocation on the node actually fails because memblock refuses to allocate there, and so KHO fails to initialize. Skip bootmem reservation for such nodes entirely. To keep the code more robust, avoid overloading kho_bootmem_cnt. use max_nr_bootmem to store the size of kho_bootmem array. This ensures that the location of kho_bootmem_cnt assignment does not affect the cleanup paths. Fixes: 3dc92c311498 ("kexec: add Kexec HandOver (KHO) generation helpers") Reported-by: Bing Jiao <bingjiao@google.com> Signed-off-by: Pratyush Yadav (Google) <pratyush@kernel.org> Link: https://patch.msgid.link/20261014131547.259138-1-pratyush@kernel.org Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/liveupdate/kexec_handover.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
index 7018e25e4eda..6f1f55fe3181 100644
--- a/kernel/liveupdate/kexec_handover.c
+++ b/kernel/liveupdate/kexec_handover.c
@@ -831,8 +831,8 @@ bool kho_bootmem_overlap(phys_addr_t phys, size_t size)
*/
static void __init kho_reserve_bootmem(void)
{
+ int nid, i = 0, max_nr_bootmem;
phys_addr_t addr, size;
- int nid, i = 0;
if (!kho_enable)
return;
@@ -840,8 +840,8 @@ static void __init kho_reserve_bootmem(void)
bootmem_size_update();
/* FIXME: deal with node hot-plug/remove */
- kho_bootmem_cnt = nodes_weight(node_states[N_MEMORY]) + 2;
- size = kho_bootmem_cnt * sizeof(*kho_bootmem);
+ max_nr_bootmem = nodes_weight(node_states[N_MEMORY]) + 2;
+ size = max_nr_bootmem * sizeof(*kho_bootmem);
kho_bootmem = memblock_alloc(size, PAGE_SIZE);
if (!kho_bootmem) {
pr_err("Failed to reserve bootmem array\n");
@@ -882,6 +882,9 @@ static void __init kho_reserve_bootmem(void)
*/
for_each_node_state(nid, N_MEMORY) {
size = bootmem_size_node(nid);
+ if (!size)
+ continue;
+
addr = memblock_alloc_range_nid(size, BOOTMEM_ALIGNMENT_BYTES,
0, MEMBLOCK_ALLOC_ACCESSIBLE,
nid, true);
@@ -895,13 +898,19 @@ static void __init kho_reserve_bootmem(void)
i++;
}
+ /*
+ * Nodes that needed no bootmem were skipped, so fewer areas than
+ * initially estimated may have been reserved.
+ */
+ kho_bootmem_cnt = i;
+
return;
err_free_bootmem_areas:
for (i--; i >= 0; i--)
memblock_phys_free(kho_bootmem[i].addr, kho_bootmem[i].size);
err_free_bootmem_desc:
- memblock_free(kho_bootmem, kho_bootmem_cnt * sizeof(*kho_bootmem));
+ memblock_free(kho_bootmem, max_nr_bootmem * sizeof(*kho_bootmem));
err_disable_kho:
pr_warn("Failed to reserve bootmem, disabling kexec handover\n");
kho_enable = false;