From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>
To: Mike Rapoport <rppt@kernel.org>,
Pasha Tatashin <pasha.tatashin@soleen.com>,
Pratyush Yadav <pratyush@kernel.org>
Cc: Alexander Graf <graf@amazon.com>,
Andrew Morton <akpm@linux-foundation.org>,
Chen Pei <cp0613@linux.alibaba.com>,
George Guo <guodongtai@kylinos.cn>,
Kexin Liu <liukexin@kylinos.cn>,
Sourabh Jain <sourabhjain@linux.ibm.com>,
kexec@lists.infradead.org, linux-kernel@vger.kernel.org,
linux-mm@kvack.org
Subject: [PATCH 2/2] kho: fix bootmem sizing
Date: Tue, 03 Nov 2026 13:49:50 +0200 [thread overview]
Message-ID: <20261103-kho-bootmem-sizing-v1-2-45aa74098f34@kernel.org> (raw)
In-Reply-To: <20261103-kho-bootmem-sizing-v1-0-45aa74098f34@kernel.org>
Bootmem areas are sized from overlapping views of the memory reserved in
memblock:
* the global area is sized from all reserved memory, including memory
allocated on specific nodes, so on NUMA systems everything allocated
on a node is accounted in both the global area and the area of that
node.
* per-node sizes are calculated after the lowmem and the global areas
are reserved. With CONFIG_NUMA=n all memblock regions belong to node 0,
so the lowmem and the global areas are accounted in the size of node 0
area and scaled once again.
As a result, bootmem is about twice bigger than it should be on NUMA
systems and about four times bigger with CONFIG_NUMA=n. On small systems
reservation of the bootmem may fail and then KHO gets disabled.
Make the areas cover separate parts of the reserved memory: the lowmem
area covers allocations below ARCH_LOW_ADDRESS_LIMIT, per-node areas
cover allocations above it on each node and the global area covers
allocations that are not bound to any node. Calculate all sizes before
reserving any of the areas.
With CONFIG_NUMA=n the global area becomes empty and it is not reserved.
Bootmem sizes in MiB in x86 QEMU VMs, before -> after:
CONFIG_NUMA=y CONFIG_NUMA=n
1G, 1 node 176 -> 92 320 -> 80
4G, 1 node 508 -> 332 1264 -> 316
16G, 2 nodes 1268 -> 704 2944 -> 736
32G, 4 nodes 2296 -> 1224 5196 -> 1300
64G, 4 nodes 4344 -> 2248 9664 -> 2420
Fixes: 3dc92c311498 ("kexec: add Kexec HandOver (KHO) generation helpers")
Reported-by: Kexin Liu <liukexin@kylinos.cn>
Reported-by: George Guo <guodongtai@kylinos.cn>
Closes: https://lore.kernel.org/all/20260904025101.9959-1-dongtai.guo@linux.dev
Reported-by: Sourabh Jain <sourabhjain@linux.ibm.com>
Closes: https://lore.kernel.org/all/20260922131217.698809-1-sourabhjain@linux.ibm.com
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
kernel/liveupdate/kexec_handover.c | 83 ++++++++++++++++++++------------------
1 file changed, 44 insertions(+), 39 deletions(-)
diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
index f268c57413a7e..eaeb895bb7595 100644
--- a/kernel/liveupdate/kexec_handover.c
+++ b/kernel/liveupdate/kexec_handover.c
@@ -684,6 +684,7 @@ static unsigned int bootmem_scale __initdata = 200;
static phys_addr_t bootmem_size_global __initdata;
static phys_addr_t bootmem_size_pernode __initdata;
static phys_addr_t bootmem_size_lowmem __initdata;
+static phys_addr_t bootmem_size_node[MAX_NUMNODES] __initdata;
static int __init kho_parse_bootmem_size(char *p)
{
@@ -753,29 +754,48 @@ static int __init kho_parse_bootmem_size(char *p)
}
early_param("kho_bootmem", kho_parse_bootmem_size);
+static phys_addr_t __init reserved_mem_size(phys_addr_t limit, int nid)
+{
+ return memblock_reserved_kern_size(limit, nid) -
+ memblock_reserved_hugetlb_size(limit, nid);
+}
+
+static phys_addr_t __init bootmem_scale_size(phys_addr_t size)
+{
+ return size * bootmem_scale / 100;
+}
+
+/*
+ * The lowmem area covers allocations below ARCH_LOW_ADDRESS_LIMIT, per-node
+ * areas cover allocations above it on each node and the global area covers
+ * allocations that are not bound to any node.
+ *
+ * All sizes must be calculated before any area is reserved, otherwise the
+ * areas reserved first will be accounted in the sizes of the others.
+ */
static void __init bootmem_size_update(void)
{
- /*
- * If fixed sizes are not provided via command line, calculate them now.
- * Remove HugeTLB allocations from it because they never get allocated
- * from bootmem.
- */
+ int nid;
+
if (bootmem_scale) {
- phys_addr_t size;
-
- size = memblock_reserved_kern_size(ARCH_LOW_ADDRESS_LIMIT,
- NUMA_NO_NODE);
- size -= memblock_reserved_hugetlb_size(ARCH_LOW_ADDRESS_LIMIT,
- NUMA_NO_NODE);
- size = size * bootmem_scale / 100;
- bootmem_size_lowmem = size;
-
- size = memblock_reserved_kern_size(MEMBLOCK_ALLOC_ANYWHERE,
- NUMA_NO_NODE);
- size -= memblock_reserved_hugetlb_size(MEMBLOCK_ALLOC_ANYWHERE,
- NUMA_NO_NODE);
- size = size * bootmem_scale / 100 - bootmem_size_lowmem;
- bootmem_size_global = size;
+ phys_addr_t lowmem, global, size;
+
+ lowmem = reserved_mem_size(ARCH_LOW_ADDRESS_LIMIT, NUMA_NO_NODE);
+ global = reserved_mem_size(MEMBLOCK_ALLOC_ANYWHERE, NUMA_NO_NODE);
+ global -= lowmem;
+
+ for_each_node_state(nid, N_MEMORY) {
+ size = reserved_mem_size(MEMBLOCK_ALLOC_ANYWHERE, nid) -
+ reserved_mem_size(ARCH_LOW_ADDRESS_LIMIT, nid);
+ bootmem_size_node[nid] = bootmem_scale_size(size);
+ global -= size;
+ }
+
+ bootmem_size_lowmem = bootmem_scale_size(lowmem);
+ bootmem_size_global = bootmem_scale_size(global);
+ } else {
+ for_each_node_state(nid, N_MEMORY)
+ bootmem_size_node[nid] = bootmem_size_pernode;
}
/*
@@ -784,24 +804,9 @@ static void __init bootmem_size_update(void)
*/
bootmem_size_lowmem = round_up(bootmem_size_lowmem, BOOTMEM_ALIGNMENT_BYTES);
bootmem_size_global = round_up(bootmem_size_global, BOOTMEM_ALIGNMENT_BYTES);
-}
-
-static phys_addr_t __init bootmem_size_node(int nid)
-{
- phys_addr_t size;
-
- if (bootmem_scale) {
- size = memblock_reserved_kern_size(MEMBLOCK_ALLOC_ANYWHERE,
- nid);
- /* Do not count HugeTLB pages. */
- size -= memblock_reserved_hugetlb_size(MEMBLOCK_ALLOC_ANYWHERE,
- nid);
- size = size * bootmem_scale / 100;
- } else {
- size = bootmem_size_pernode;
- }
-
- return round_up(size, BOOTMEM_ALIGNMENT_BYTES);
+ for_each_node_state(nid, N_MEMORY)
+ bootmem_size_node[nid] = round_up(bootmem_size_node[nid],
+ BOOTMEM_ALIGNMENT_BYTES);
}
bool kho_bootmem_overlap(phys_addr_t phys, size_t size)
@@ -891,7 +896,7 @@ static void __init kho_reserve_bootmem(void)
* memoryless nodes, as we can not allocate bootmem areas there.
*/
for_each_node_state(nid, N_MEMORY) {
- if (kho_reserve_bootmem_area(&i, bootmem_size_node(nid),
+ if (kho_reserve_bootmem_area(&i, bootmem_size_node[nid],
MEMBLOCK_ALLOC_ACCESSIBLE, nid)) {
pr_err("Failed to reserve nid %d bootmem\n", nid);
goto err_free_bootmem_areas;
--
2.53.0
next prev parent reply other threads:[~2026-11-03 11:50 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-03 11:49 [PATCH 0/2] " Mike Rapoport (Microsoft)
2026-11-03 11:49 ` [PATCH 1/2] kho: skip zero-sized lowmem and global bootmem areas Mike Rapoport (Microsoft)
2026-11-03 14:14 ` Pratyush Yadav
2026-11-03 18:32 ` Mike Rapoport
2026-11-03 19:48 ` Pasha Tatashin
2026-11-03 11:49 ` Mike Rapoport (Microsoft) [this message]
2026-11-03 16:01 ` [PATCH 2/2] kho: fix bootmem sizing Pratyush Yadav
2026-11-03 18:36 ` Mike Rapoport
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261103-kho-bootmem-sizing-v1-2-45aa74098f34@kernel.org \
--to=rppt@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=cp0613@linux.alibaba.com \
--cc=graf@amazon.com \
--cc=guodongtai@kylinos.cn \
--cc=kexec@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=liukexin@kylinos.cn \
--cc=pasha.tatashin@soleen.com \
--cc=pratyush@kernel.org \
--cc=sourabhjain@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®