* [PATCH v2 0/3] kho: fix bootmem sizing
@ 2026-11-04 16:50 Mike Rapoport (Microsoft)
2026-11-04 16:50 ` [PATCH v2 1/3] kho: walk bootmem areas in address order Mike Rapoport (Microsoft)
` (2 more replies)
0 siblings, 3 replies; 18+ messages in thread
From: Mike Rapoport (Microsoft) @ 2026-11-04 16:50 UTC (permalink / raw)
To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav
Cc: Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu,
Sourabh Jain, kexec, linux-kernel, linux-mm
There were several reports about issues with KHO bootmem sizing.
The bootmem areas are sized from overlapping views of the memory reserved
in memblock, so on NUMA systems memory allocated on a node is accounted
twice and with CONFIG_NUMA=n the lowmem and the global areas are accounted
once again in the area of node 0. Besides, the lowmem and the global areas
are reserved even when they are empty.
The first patch makes kexec walk the bootmem areas in address order.
Otherwise kexec on arm64 may fail if a small area at the top of the memory
is the first in the list, and with smaller bootmem areas this becomes more
likely.
The second patch skips empty bootmem areas and the third one makes the
lowmem, per-node and global areas cover separate parts of the reserved
memory.
---
Changes in v2:
- add a patch that walks bootmem areas in address order
- update kho_bootmem_cnt directly in kho_reserve_bootmem_area() (Pratyush)
- don't reserve the lowmem area if ARCH_LOW_ADDRESS_LIMIT covers all
memory (Pratyush)
- extend the comment above bootmem_size_update() (Pratyush)
- Link to v1: https://patch.msgid.link/20261103-kho-bootmem-sizing-v1-0-45aa74098f34@kernel.org
---
Mike Rapoport (Microsoft) (3):
kho: walk bootmem areas in address order
kho: skip zero-sized lowmem and global bootmem areas
kho: fix bootmem sizing
kernel/liveupdate/kexec_handover.c | 212 ++++++++++++++++++++++---------------
1 file changed, 128 insertions(+), 84 deletions(-)
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20261103-kho-bootmem-sizing-5d6aed47a243
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v2 1/3] kho: walk bootmem areas in address order 2026-11-04 16:50 [PATCH v2 0/3] kho: fix bootmem sizing Mike Rapoport (Microsoft) @ 2026-11-04 16:50 ` Mike Rapoport (Microsoft) 2026-11-04 18:57 ` Pasha Tatashin ` (3 more replies) 2026-11-04 16:50 ` [PATCH v2 2/3] kho: skip zero-sized lowmem and global bootmem areas Mike Rapoport (Microsoft) 2026-11-04 16:50 ` [PATCH v2 3/3] kho: fix bootmem sizing Mike Rapoport (Microsoft) 2 siblings, 4 replies; 18+ messages in thread From: Mike Rapoport (Microsoft) @ 2026-11-04 16:50 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm kexec_add_buffer() users may depend on the order in which memory holes are searched. For instance, arm64 places the kernel bottom-up and then requires the DTB to be above the kernel. kho_walk_bootmem() walks the bootmem areas in the order they were reserved, so if the kernel lands in a small area at the top of the memory there is no room left for the DTB and kexec fails. For example, on an arm64 VM with 2G of RAM and kho_bootmem=8M,64M,64M, the lowmem area is reserved first at the top of the memory, the kernel image takes most of it and kexec fails with kexec_file(Image): Could not find any suitable kernel location! Sort the bootmem areas by address and walk them in ascending order, or in descending order for top-down searches, like kexec_walk_resources() does. Fixes: 3bdecc3c93f9 ("kexec: add KHO support to kexec file loads") Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org> --- kernel/liveupdate/kexec_handover.c | 57 ++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c index 6f1f55fe31819..2ac5d94f33fd4 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -26,6 +26,7 @@ #include <linux/list.h> #include <linux/memblock.h> #include <linux/page-isolation.h> +#include <linux/sort.h> #include <linux/unaligned.h> #include <linux/vmalloc.h> @@ -820,6 +821,14 @@ bool kho_bootmem_overlap(phys_addr_t phys, size_t size) return false; } +static int __init kho_bootmem_cmp(const void *_a, const void *_b) +{ + const struct kho_bootmem *a = _a; + const struct kho_bootmem *b = _b; + + return cmp_int(a->addr, b->addr); +} + /** * kho_reserve_bootmem - Reserve a contiguous chunk of memory for kexec * @@ -904,6 +913,9 @@ static void __init kho_reserve_bootmem(void) */ kho_bootmem_cnt = i; + sort(kho_bootmem, kho_bootmem_cnt, sizeof(*kho_bootmem), + kho_bootmem_cmp, NULL); + return; err_free_bootmem_areas: @@ -2081,20 +2093,40 @@ int kho_fill_kimage(struct kimage *image) return 0; } -static int kho_walk_bootmem(struct kexec_buf *kbuf, - int (*func)(struct resource *, void *)) +static int kho_bootmem_walk_one(struct kexec_buf *kbuf, + const struct kho_bootmem *area, + int (*func)(struct resource *, void *)) +{ + struct resource res = { + .start = area->addr, + .end = area->addr + area->size - 1, + }; + + /* Try to fit the kbuf into our KHO bootmem region */ + return func(&res, kbuf); +} + +static int kho_bootmem_walk_top_down(struct kexec_buf *kbuf, + int (*func)(struct resource *, void *)) { int ret = 0; - int i; - for (i = 0; i < kho_bootmem_cnt; i++) { - struct resource res = { - .start = kho_bootmem[i].addr, - .end = kho_bootmem[i].addr + kho_bootmem[i].size - 1, - }; + for (int i = kho_bootmem_cnt - 1; i >= 0; i--) { + ret = kho_bootmem_walk_one(kbuf, &kho_bootmem[i], func); + if (ret) + break; + } + + return ret; +} - /* Try to fit the kimage into our KHO bootmem region */ - ret = func(&res, kbuf); +static int kho_bootmem_walk_bottom_up(struct kexec_buf *kbuf, + int (*func)(struct resource *, void *)) +{ + int ret = 0; + + for (int i = 0; i < kho_bootmem_cnt; i++) { + ret = kho_bootmem_walk_one(kbuf, &kho_bootmem[i], func); if (ret) break; } @@ -2110,7 +2142,10 @@ int kho_locate_mem_hole(struct kexec_buf *kbuf, if (!kho_enable || kbuf->image->type == KEXEC_TYPE_CRASH) return 1; - ret = kho_walk_bootmem(kbuf, func); + if (kbuf->top_down) + ret = kho_bootmem_walk_top_down(kbuf, func); + else + ret = kho_bootmem_walk_bottom_up(kbuf, func); return ret == 1 ? 0 : -EADDRNOTAVAIL; } -- 2.53.0 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/3] kho: walk bootmem areas in address order 2026-11-04 16:50 ` [PATCH v2 1/3] kho: walk bootmem areas in address order Mike Rapoport (Microsoft) @ 2026-11-04 18:57 ` Pasha Tatashin 2026-11-04 22:14 ` Jose A. Perez de Azpillaga ` (2 subsequent siblings) 3 siblings, 0 replies; 18+ messages in thread From: Pasha Tatashin @ 2026-11-04 18:57 UTC (permalink / raw) To: Mike Rapoport (Microsoft) Cc: Pasha Tatashin, Pratyush Yadav, Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm On Wed, 04 Nov 2026 18:50:09 +0200, Mike Rapoport (Microsoft) <rppt@kernel.org> wrote: > kexec_add_buffer() users may depend on the order in which memory holes are > searched. For instance, arm64 places the kernel bottom-up and then > requires the DTB to be above the kernel. > > kho_walk_bootmem() walks the bootmem areas in the order they were > reserved, so if the kernel lands in a small area at the top of the memory > there is no room left for the DTB and kexec fails. For example, on an > arm64 VM with 2G of RAM and kho_bootmem=8M,64M,64M, the lowmem area is > reserved first at the top of the memory, the kernel image takes most of > it and kexec fails with > > [...] Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com> -- Pasha ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/3] kho: walk bootmem areas in address order 2026-11-04 16:50 ` [PATCH v2 1/3] kho: walk bootmem areas in address order Mike Rapoport (Microsoft) 2026-11-04 18:57 ` Pasha Tatashin @ 2026-11-04 22:14 ` Jose A. Perez de Azpillaga 2026-11-10 16:52 ` Pratyush Yadav 2026-11-12 6:32 ` Mukesh Pilaniya 3 siblings, 0 replies; 18+ messages in thread From: Jose A. Perez de Azpillaga @ 2026-11-04 22:14 UTC (permalink / raw) To: Mike Rapoport (Microsoft), Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm On 11/4/26 5:50 PM, Mike Rapoport (Microsoft) wrote: > kexec_add_buffer() users may depend on the order in which memory holes are > searched. For instance, arm64 places the kernel bottom-up and then > requires the DTB to be above the kernel. > > kho_walk_bootmem() walks the bootmem areas in the order they were > reserved, so if the kernel lands in a small area at the top of the memory > there is no room left for the DTB and kexec fails. For example, on an > arm64 VM with 2G of RAM and kho_bootmem=8M,64M,64M, the lowmem area is > reserved first at the top of the memory, the kernel image takes most of > it and kexec fails with > > kexec_file(Image): Could not find any suitable kernel location! > > Sort the bootmem areas by address and walk them in ascending order, or in > descending order for top-down searches, like kexec_walk_resources() does. > > Fixes: 3bdecc3c93f9 ("kexec: add KHO support to kexec file loads") > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org> Reviewed-by: Jose A. Perez de Azpillaga <azpijr@gmail.com> -- cheers, jose a. p-a ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/3] kho: walk bootmem areas in address order 2026-11-04 16:50 ` [PATCH v2 1/3] kho: walk bootmem areas in address order Mike Rapoport (Microsoft) 2026-11-04 18:57 ` Pasha Tatashin 2026-11-04 22:14 ` Jose A. Perez de Azpillaga @ 2026-11-10 16:52 ` Pratyush Yadav 2026-11-12 6:32 ` Mukesh Pilaniya 3 siblings, 0 replies; 18+ messages in thread From: Pratyush Yadav @ 2026-11-10 16:52 UTC (permalink / raw) To: Mike Rapoport (Microsoft) Cc: Pasha Tatashin, Pratyush Yadav, Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm On Wed, Nov 04 2026, Mike Rapoport (Microsoft) wrote: > kexec_add_buffer() users may depend on the order in which memory holes are > searched. For instance, arm64 places the kernel bottom-up and then > requires the DTB to be above the kernel. > > kho_walk_bootmem() walks the bootmem areas in the order they were > reserved, so if the kernel lands in a small area at the top of the memory > there is no room left for the DTB and kexec fails. For example, on an > arm64 VM with 2G of RAM and kho_bootmem=8M,64M,64M, the lowmem area is > reserved first at the top of the memory, the kernel image takes most of > it and kexec fails with > > kexec_file(Image): Could not find any suitable kernel location! > > Sort the bootmem areas by address and walk them in ascending order, or in > descending order for top-down searches, like kexec_walk_resources() does. > > Fixes: 3bdecc3c93f9 ("kexec: add KHO support to kexec file loads") > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org> Reviewed-by: Pratyush Yadav <pratyush@kernel.org> [...] -- Regards, Pratyush Yadav ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/3] kho: walk bootmem areas in address order 2026-11-04 16:50 ` [PATCH v2 1/3] kho: walk bootmem areas in address order Mike Rapoport (Microsoft) ` (2 preceding siblings ...) 2026-11-10 16:52 ` Pratyush Yadav @ 2026-11-12 6:32 ` Mukesh Pilaniya 2026-11-12 8:49 ` Mike Rapoport 3 siblings, 1 reply; 18+ messages in thread From: Mukesh Pilaniya @ 2026-11-12 6:32 UTC (permalink / raw) To: Mike Rapoport (Microsoft), Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm Hi Mike, On 04/11/26 10:20 pm, Mike Rapoport (Microsoft) wrote: > kexec_add_buffer() users may depend on the order in which memory holes are > searched. For instance, arm64 places the kernel bottom-up and then > requires the DTB to be above the kernel. > > kho_walk_bootmem() walks the bootmem areas in the order they were > reserved, so if the kernel lands in a small area at the top of the memory > there is no room left for the DTB and kexec fails. For example, on an > arm64 VM with 2G of RAM and kho_bootmem=8M,64M,64M, the lowmem area is > reserved first at the top of the memory, the kernel image takes most of > it and kexec fails with > > kexec_file(Image): Could not find any suitable kernel location! > > Sort the bootmem areas by address and walk them in ascending order, or in > descending order for top-down searches, like kexec_walk_resources() does. > > Fixes: 3bdecc3c93f9 ("kexec: add KHO support to kexec file loads") > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org> > --- > kernel/liveupdate/kexec_handover.c | 57 ++++++++++++++++++++++++++++++-------- > 1 file changed, 46 insertions(+), 11 deletions(-) > > diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c > index 6f1f55fe31819..2ac5d94f33fd4 100644 > --- a/kernel/liveupdate/kexec_handover.c > +++ b/kernel/liveupdate/kexec_handover.c > @@ -26,6 +26,7 @@ > #include <linux/list.h> > #include <linux/memblock.h> > #include <linux/page-isolation.h> > +#include <linux/sort.h> > #include <linux/unaligned.h> > #include <linux/vmalloc.h> > > @@ -820,6 +821,14 @@ bool kho_bootmem_overlap(phys_addr_t phys, size_t size) > return false; > } > > +static int __init kho_bootmem_cmp(const void *_a, const void *_b) > +{ > + const struct kho_bootmem *a = _a; > + const struct kho_bootmem *b = _b; > + > + return cmp_int(a->addr, b->addr); > +} > + > /** > * kho_reserve_bootmem - Reserve a contiguous chunk of memory for kexec > * > @@ -904,6 +913,9 @@ static void __init kho_reserve_bootmem(void) > */ > kho_bootmem_cnt = i; > > + sort(kho_bootmem, kho_bootmem_cnt, sizeof(*kho_bootmem), > + kho_bootmem_cmp, NULL); This only covers the case where this kernel allocated the areas itself. On a KHO boot the array comes from the previous kernel. A kernel with this series that is handed over from one without it therefore keeps walking the areas in reservation order for every following kexec_file_load, and the arm64 failure you describe comes back until the next cold boot and vise versa because the ABI string is still "kho-v4". So, sorting once in kho_memory_init_early after kho_bootmem is mapped would make the invariant independent of the producer. When the previous kernel does have the sort this is a no-op, but the consumer cannot tell which kernel recorded the array, because the ABI string is the same. > + > return; > > err_free_bootmem_areas: > @@ -2081,20 +2093,40 @@ int kho_fill_kimage(struct kimage *image) > return 0; > } > > -static int kho_walk_bootmem(struct kexec_buf *kbuf, > - int (*func)(struct resource *, void *)) > +static int kho_bootmem_walk_one(struct kexec_buf *kbuf, > + const struct kho_bootmem *area, > + int (*func)(struct resource *, void *)) > +{ > + struct resource res = { > + .start = area->addr, > + .end = area->addr + area->size - 1, > + }; > + > + /* Try to fit the kbuf into our KHO bootmem region */ > + return func(&res, kbuf); > +} > + > +static int kho_bootmem_walk_top_down(struct kexec_buf *kbuf, > + int (*func)(struct resource *, void *)) > { > int ret = 0; > - int i; > > - for (i = 0; i < kho_bootmem_cnt; i++) { > - struct resource res = { > - .start = kho_bootmem[i].addr, > - .end = kho_bootmem[i].addr + kho_bootmem[i].size - 1, > - }; > + for (int i = kho_bootmem_cnt - 1; i >= 0; i--) { kho_bootmem_cnt is unsigned, but the reverse loops in kho_reserve_bootmem() and kho_bootmem_walk_top_down() start an int counter at kho_bootmem_cnt - 1, which for a zero count is UINT_MAX converted to int. That conversion is implementation-defined; with the current compilers it yields -1 and the loop body is skipped. How about using this one. for (unsigned int i = kho_bootmem_cnt; i-- > 0;) Reviewed-by: Mukesh Pilaniya <mpilaniy@redhat.com> > + ret = kho_bootmem_walk_one(kbuf, &kho_bootmem[i], func); > + if (ret) > + break; > + } > + > + return ret; > +} > > - /* Try to fit the kimage into our KHO bootmem region */ > - ret = func(&res, kbuf); > +static int kho_bootmem_walk_bottom_up(struct kexec_buf *kbuf, > + int (*func)(struct resource *, void *)) > +{ > + int ret = 0; > + > + for (int i = 0; i < kho_bootmem_cnt; i++) { > + ret = kho_bootmem_walk_one(kbuf, &kho_bootmem[i], func); > if (ret) > break; > } > @@ -2110,7 +2142,10 @@ int kho_locate_mem_hole(struct kexec_buf *kbuf, > if (!kho_enable || kbuf->image->type == KEXEC_TYPE_CRASH) > return 1; > > - ret = kho_walk_bootmem(kbuf, func); > + if (kbuf->top_down) > + ret = kho_bootmem_walk_top_down(kbuf, func); > + else > + ret = kho_bootmem_walk_bottom_up(kbuf, func); > > return ret == 1 ? 0 : -EADDRNOTAVAIL; > } > -- Regards, Mukesh Pilaniya ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/3] kho: walk bootmem areas in address order 2026-11-12 6:32 ` Mukesh Pilaniya @ 2026-11-12 8:49 ` Mike Rapoport 0 siblings, 0 replies; 18+ messages in thread From: Mike Rapoport @ 2026-11-12 8:49 UTC (permalink / raw) To: Mukesh Pilaniya Cc: Pasha Tatashin, Pratyush Yadav, Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm On Thu, Nov 12, 2026 at 12:02:05PM +0530, Mukesh Pilaniya wrote: > Hi Mike, > > On 04/11/26 10:20 pm, Mike Rapoport (Microsoft) wrote: > > kexec_add_buffer() users may depend on the order in which memory holes are > > searched. For instance, arm64 places the kernel bottom-up and then > > requires the DTB to be above the kernel. > > > > kho_walk_bootmem() walks the bootmem areas in the order they were > > reserved, so if the kernel lands in a small area at the top of the memory > > there is no room left for the DTB and kexec fails. For example, on an > > arm64 VM with 2G of RAM and kho_bootmem=8M,64M,64M, the lowmem area is > > reserved first at the top of the memory, the kernel image takes most of > > it and kexec fails with > > > > kexec_file(Image): Could not find any suitable kernel location! > > > > Sort the bootmem areas by address and walk them in ascending order, or in > > descending order for top-down searches, like kexec_walk_resources() does. > > > > Fixes: 3bdecc3c93f9 ("kexec: add KHO support to kexec file loads") > > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org> > > --- > > kernel/liveupdate/kexec_handover.c | 57 ++++++++++++++++++++++++++++++-------- > > 1 file changed, 46 insertions(+), 11 deletions(-) > > > > diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c > > index 6f1f55fe31819..2ac5d94f33fd4 100644 > > --- a/kernel/liveupdate/kexec_handover.c > > +++ b/kernel/liveupdate/kexec_handover.c > > @@ -26,6 +26,7 @@ > > #include <linux/list.h> > > #include <linux/memblock.h> > > #include <linux/page-isolation.h> > > +#include <linux/sort.h> > > #include <linux/unaligned.h> > > #include <linux/vmalloc.h> > > > > @@ -820,6 +821,14 @@ bool kho_bootmem_overlap(phys_addr_t phys, size_t size) > > return false; > > } > > > > +static int __init kho_bootmem_cmp(const void *_a, const void *_b) > > +{ > > + const struct kho_bootmem *a = _a; > > + const struct kho_bootmem *b = _b; > > + > > + return cmp_int(a->addr, b->addr); > > +} > > + > > /** > > * kho_reserve_bootmem - Reserve a contiguous chunk of memory for kexec > > * > > @@ -904,6 +913,9 @@ static void __init kho_reserve_bootmem(void) > > */ > > kho_bootmem_cnt = i; > > > > + sort(kho_bootmem, kho_bootmem_cnt, sizeof(*kho_bootmem), > > + kho_bootmem_cmp, NULL); > This only covers the case where this kernel allocated the areas itself. > On a KHO boot the array comes from the previous kernel. A kernel with > this series that is handed over from one without it therefore keeps > walking the areas in reservation order for every following > kexec_file_load, and the arm64 failure you describe comes back until the > next cold boot and vise versa because the ABI string is still > "kho-v4". If we were able to kexec from a kernel with no reservation ordering, the issue is not there, isn't it? And after a cycle of KHO boots to newer kernels we anyway can get to the point when bootmem is not large enough. > > +static int kho_bootmem_walk_top_down(struct kexec_buf *kbuf, > > + int (*func)(struct resource *, void *)) > > { > > int ret = 0; > > - int i; > > > > - for (i = 0; i < kho_bootmem_cnt; i++) { > > - struct resource res = { > > - .start = kho_bootmem[i].addr, > > - .end = kho_bootmem[i].addr + kho_bootmem[i].size - 1, > > - }; > > + for (int i = kho_bootmem_cnt - 1; i >= 0; i--) { > > kho_bootmem_cnt is unsigned, but the reverse loops in > kho_reserve_bootmem() and kho_bootmem_walk_top_down() start an int > counter at kho_bootmem_cnt - 1, which for a zero count is UINT_MAX > converted to int. That conversion is implementation-defined; with the > current compilers it yields -1 and the loop body is skipped. We never get here with kho_bootmem_cnt == 0. > How about using this one. > for (unsigned int i = kho_bootmem_cnt; i-- > 0;) > > Reviewed-by: Mukesh Pilaniya <mpilaniy@redhat.com> Thanks! > -- > Regards, > Mukesh Pilaniya > -- Sincerely yours, Mike. ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 2/3] kho: skip zero-sized lowmem and global bootmem areas 2026-11-04 16:50 [PATCH v2 0/3] kho: fix bootmem sizing Mike Rapoport (Microsoft) 2026-11-04 16:50 ` [PATCH v2 1/3] kho: walk bootmem areas in address order Mike Rapoport (Microsoft) @ 2026-11-04 16:50 ` Mike Rapoport (Microsoft) 2026-11-04 18:57 ` Pasha Tatashin ` (3 more replies) 2026-11-04 16:50 ` [PATCH v2 3/3] kho: fix bootmem sizing Mike Rapoport (Microsoft) 2 siblings, 4 replies; 18+ messages in thread From: Mike Rapoport (Microsoft) @ 2026-11-04 16:50 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm The lowmem and the global bootmem areas can have zero size, for example when none or all of the memory is below ARCH_LOW_ADDRESS_LIMIT, or when either of those areas is explicitly set to zero with kho_bootmem=. For a zero-sized allocation memblock returns an address without reserving anything, and that empty area is recorded in kho_bootmem. If there is no memory below ARCH_LOW_ADDRESS_LIMIT, allocation of the empty lowmem area fails and KHO gets disabled. Extract a helper that checks for zero size and allocates memory from memblock, and use it to skip empty areas the same way as empty per-node areas are skipped. Fixes: 3dc92c311498 ("kexec: add Kexec HandOver (KHO) generation helpers") Reported-by: Chen Pei <cp0613@linux.alibaba.com> Closes: https://lore.kernel.org/all/20261026131851.9942-1-cp0613@linux.alibaba.com Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org> --- kernel/liveupdate/kexec_handover.c | 66 +++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c index 2ac5d94f33fd4..5b1797d1289c8 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -829,6 +829,26 @@ static int __init kho_bootmem_cmp(const void *_a, const void *_b) return cmp_int(a->addr, b->addr); } +static int __init kho_reserve_bootmem_area(phys_addr_t size, phys_addr_t end, + int nid) +{ + phys_addr_t addr; + + if (!size) + return 0; + + addr = memblock_alloc_range_nid(size, BOOTMEM_ALIGNMENT_BYTES, 0, end, + nid, true); + if (!addr) + return -ENOMEM; + + kho_bootmem[kho_bootmem_cnt].addr = addr; + kho_bootmem[kho_bootmem_cnt].size = size; + kho_bootmem_cnt++; + + return 0; +} + /** * kho_reserve_bootmem - Reserve a contiguous chunk of memory for kexec * @@ -840,8 +860,8 @@ static int __init kho_bootmem_cmp(const void *_a, const void *_b) */ static void __init kho_reserve_bootmem(void) { - int nid, i = 0, max_nr_bootmem; - phys_addr_t addr, size; + int nid, max_nr_bootmem; + phys_addr_t size; if (!kho_enable) return; @@ -861,66 +881,40 @@ static void __init kho_reserve_bootmem(void) * reserve bootmem area in low memory for lowmem allocations in the * next kernel */ - size = bootmem_size_lowmem; - addr = memblock_phys_alloc_range(size, BOOTMEM_ALIGNMENT_BYTES, 0, - ARCH_LOW_ADDRESS_LIMIT); - if (!addr) { + if (kho_reserve_bootmem_area(bootmem_size_lowmem, ARCH_LOW_ADDRESS_LIMIT, + NUMA_NO_NODE)) { pr_err("Failed to reserve lowmem bootmem\n"); goto err_free_bootmem_desc; } - 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) { + if (kho_reserve_bootmem_area(bootmem_size_global, + MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE)) { pr_err("Failed to reserve global bootmem\n"); goto err_free_bootmem_areas; } - kho_bootmem[i].addr = addr; - kho_bootmem[i].size = size; - i++; - /* * Loop over nodes that have both memory and are online. Skip * memoryless nodes, as we can not allocate bootmem areas there. */ 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); - if (!addr) { + if (kho_reserve_bootmem_area(bootmem_size_node(nid), + MEMBLOCK_ALLOC_ACCESSIBLE, nid)) { pr_err("Failed to reserve nid %d bootmem\n", nid); goto err_free_bootmem_areas; } - - kho_bootmem[i].addr = addr; - kho_bootmem[i].size = size; - i++; } - /* - * Nodes that needed no bootmem were skipped, so fewer areas than - * initially estimated may have been reserved. - */ - kho_bootmem_cnt = i; - sort(kho_bootmem, kho_bootmem_cnt, sizeof(*kho_bootmem), kho_bootmem_cmp, NULL); return; err_free_bootmem_areas: - for (i--; i >= 0; i--) + for (int i = kho_bootmem_cnt - 1; i >= 0; i--) memblock_phys_free(kho_bootmem[i].addr, kho_bootmem[i].size); + kho_bootmem_cnt = 0; err_free_bootmem_desc: memblock_free(kho_bootmem, max_nr_bootmem * sizeof(*kho_bootmem)); err_disable_kho: -- 2.53.0 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v2 2/3] kho: skip zero-sized lowmem and global bootmem areas 2026-11-04 16:50 ` [PATCH v2 2/3] kho: skip zero-sized lowmem and global bootmem areas Mike Rapoport (Microsoft) @ 2026-11-04 18:57 ` Pasha Tatashin 2026-11-04 22:17 ` Jose A. Perez de Azpillaga ` (2 subsequent siblings) 3 siblings, 0 replies; 18+ messages in thread From: Pasha Tatashin @ 2026-11-04 18:57 UTC (permalink / raw) To: Mike Rapoport (Microsoft) Cc: Pasha Tatashin, Pratyush Yadav, Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm On Wed, 04 Nov 2026 18:50:10 +0200, Mike Rapoport (Microsoft) <rppt@kernel.org> wrote: > The lowmem and the global bootmem areas can have zero size, for example > when none or all of the memory is below ARCH_LOW_ADDRESS_LIMIT, or when > either of those areas is explicitly set to zero with kho_bootmem=. > > For a zero-sized allocation memblock returns an address without reserving > anything, and that empty area is recorded in kho_bootmem. If there is no > memory below ARCH_LOW_ADDRESS_LIMIT, allocation of the empty lowmem area > fails and KHO gets disabled. > > [...] Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com> -- Pasha ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 2/3] kho: skip zero-sized lowmem and global bootmem areas 2026-11-04 16:50 ` [PATCH v2 2/3] kho: skip zero-sized lowmem and global bootmem areas Mike Rapoport (Microsoft) 2026-11-04 18:57 ` Pasha Tatashin @ 2026-11-04 22:17 ` Jose A. Perez de Azpillaga 2026-11-10 16:55 ` Pratyush Yadav 2026-11-12 6:48 ` Mukesh Pilaniya 3 siblings, 0 replies; 18+ messages in thread From: Jose A. Perez de Azpillaga @ 2026-11-04 22:17 UTC (permalink / raw) To: Mike Rapoport (Microsoft), Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm On 11/4/26 5:50 PM, Mike Rapoport (Microsoft) wrote: > The lowmem and the global bootmem areas can have zero size, for example > when none or all of the memory is below ARCH_LOW_ADDRESS_LIMIT, or when > either of those areas is explicitly set to zero with kho_bootmem=. > > For a zero-sized allocation memblock returns an address without reserving > anything, and that empty area is recorded in kho_bootmem. If there is no > memory below ARCH_LOW_ADDRESS_LIMIT, allocation of the empty lowmem area > fails and KHO gets disabled. > > Extract a helper that checks for zero size and allocates memory from > memblock, and use it to skip empty areas the same way as empty per-node > areas are skipped. > > Fixes: 3dc92c311498 ("kexec: add Kexec HandOver (KHO) generation helpers") > Reported-by: Chen Pei <cp0613@linux.alibaba.com> > Closes: https://lore.kernel.org/all/20261026131851.9942-1-cp0613@linux.alibaba.com > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org> Reviewed-by: Jose A. Perez de Azpillaga <azpijr@gmail.com> -- cheers, jose a. p-a ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 2/3] kho: skip zero-sized lowmem and global bootmem areas 2026-11-04 16:50 ` [PATCH v2 2/3] kho: skip zero-sized lowmem and global bootmem areas Mike Rapoport (Microsoft) 2026-11-04 18:57 ` Pasha Tatashin 2026-11-04 22:17 ` Jose A. Perez de Azpillaga @ 2026-11-10 16:55 ` Pratyush Yadav 2026-11-12 6:48 ` Mukesh Pilaniya 3 siblings, 0 replies; 18+ messages in thread From: Pratyush Yadav @ 2026-11-10 16:55 UTC (permalink / raw) To: Mike Rapoport (Microsoft) Cc: Pasha Tatashin, Pratyush Yadav, Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm On Wed, Nov 04 2026, Mike Rapoport (Microsoft) wrote: > The lowmem and the global bootmem areas can have zero size, for example > when none or all of the memory is below ARCH_LOW_ADDRESS_LIMIT, or when > either of those areas is explicitly set to zero with kho_bootmem=. > > For a zero-sized allocation memblock returns an address without reserving > anything, and that empty area is recorded in kho_bootmem. If there is no > memory below ARCH_LOW_ADDRESS_LIMIT, allocation of the empty lowmem area > fails and KHO gets disabled. > > Extract a helper that checks for zero size and allocates memory from > memblock, and use it to skip empty areas the same way as empty per-node > areas are skipped. > > Fixes: 3dc92c311498 ("kexec: add Kexec HandOver (KHO) generation helpers") > Reported-by: Chen Pei <cp0613@linux.alibaba.com> > Closes: https://lore.kernel.org/all/20261026131851.9942-1-cp0613@linux.alibaba.com > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org> Reviewed-by: Pratyush Yadav <pratyush@kernel.org> [...] -- Regards, Pratyush Yadav ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 2/3] kho: skip zero-sized lowmem and global bootmem areas 2026-11-04 16:50 ` [PATCH v2 2/3] kho: skip zero-sized lowmem and global bootmem areas Mike Rapoport (Microsoft) ` (2 preceding siblings ...) 2026-11-10 16:55 ` Pratyush Yadav @ 2026-11-12 6:48 ` Mukesh Pilaniya 3 siblings, 0 replies; 18+ messages in thread From: Mukesh Pilaniya @ 2026-11-12 6:48 UTC (permalink / raw) To: Mike Rapoport (Microsoft), Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm Hi Mike, On 04/11/26 10:20 pm, Mike Rapoport (Microsoft) wrote: > The lowmem and the global bootmem areas can have zero size, for example > when none or all of the memory is below ARCH_LOW_ADDRESS_LIMIT, or when > either of those areas is explicitly set to zero with kho_bootmem=. > > For a zero-sized allocation memblock returns an address without reserving > anything, and that empty area is recorded in kho_bootmem. If there is no > memory below ARCH_LOW_ADDRESS_LIMIT, allocation of the empty lowmem area > fails and KHO gets disabled. > > Extract a helper that checks for zero size and allocates memory from > memblock, and use it to skip empty areas the same way as empty per-node > areas are skipped. > > Fixes: 3dc92c311498 ("kexec: add Kexec HandOver (KHO) generation helpers") > Reported-by: Chen Pei <cp0613@linux.alibaba.com> > Closes: https://lore.kernel.org/all/20261026131851.9942-1-cp0613@linux.alibaba.com > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org> > --- > kernel/liveupdate/kexec_handover.c | 66 +++++++++++++++++--------------------- > 1 file changed, 30 insertions(+), 36 deletions(-) > > diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c > index 2ac5d94f33fd4..5b1797d1289c8 100644 > --- a/kernel/liveupdate/kexec_handover.c > +++ b/kernel/liveupdate/kexec_handover.c > @@ -829,6 +829,26 @@ static int __init kho_bootmem_cmp(const void *_a, const void *_b) > return cmp_int(a->addr, b->addr); > } > > +static int __init kho_reserve_bootmem_area(phys_addr_t size, phys_addr_t end, > + int nid) > +{ > + phys_addr_t addr; > + > + if (!size) > + return 0; > + > + addr = memblock_alloc_range_nid(size, BOOTMEM_ALIGNMENT_BYTES, 0, end, > + nid, true); The low memory and global areas are reserved with NUMA_NO_NODE, but kho_reserve_bootmem_area passes exact_nid = true for them as well. memblock only uses the flag for a valid node So Pass numa_valid_node(nid) instant of true. Reviewed-by: Mukesh Pilaniya <mpilaniy@redhat.com> > + if (!addr) > + return -ENOMEM; > + > + kho_bootmem[kho_bootmem_cnt].addr = addr; > + kho_bootmem[kho_bootmem_cnt].size = size; > + kho_bootmem_cnt++; > + > + return 0; > +} > + > /** > * kho_reserve_bootmem - Reserve a contiguous chunk of memory for kexec > * > @@ -840,8 +860,8 @@ static int __init kho_bootmem_cmp(const void *_a, const void *_b) > */ > static void __init kho_reserve_bootmem(void) > { > - int nid, i = 0, max_nr_bootmem; > - phys_addr_t addr, size; > + int nid, max_nr_bootmem; > + phys_addr_t size; > > if (!kho_enable) > return; > @@ -861,66 +881,40 @@ static void __init kho_reserve_bootmem(void) > * reserve bootmem area in low memory for lowmem allocations in the > * next kernel > */ > - size = bootmem_size_lowmem; > - addr = memblock_phys_alloc_range(size, BOOTMEM_ALIGNMENT_BYTES, 0, > - ARCH_LOW_ADDRESS_LIMIT); > - if (!addr) { > + if (kho_reserve_bootmem_area(bootmem_size_lowmem, ARCH_LOW_ADDRESS_LIMIT, > + NUMA_NO_NODE)) { > pr_err("Failed to reserve lowmem bootmem\n"); > goto err_free_bootmem_desc; > } > > - 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) { > + if (kho_reserve_bootmem_area(bootmem_size_global, > + MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE)) { > pr_err("Failed to reserve global bootmem\n"); > goto err_free_bootmem_areas; > } > > - kho_bootmem[i].addr = addr; > - kho_bootmem[i].size = size; > - i++; > - > /* > * Loop over nodes that have both memory and are online. Skip > * memoryless nodes, as we can not allocate bootmem areas there. > */ > 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); > - if (!addr) { > + if (kho_reserve_bootmem_area(bootmem_size_node(nid), > + MEMBLOCK_ALLOC_ACCESSIBLE, nid)) { > pr_err("Failed to reserve nid %d bootmem\n", nid); > goto err_free_bootmem_areas; > } > - > - kho_bootmem[i].addr = addr; > - kho_bootmem[i].size = size; > - i++; > } > > - /* > - * Nodes that needed no bootmem were skipped, so fewer areas than > - * initially estimated may have been reserved. > - */ > - kho_bootmem_cnt = i; > - > sort(kho_bootmem, kho_bootmem_cnt, sizeof(*kho_bootmem), > kho_bootmem_cmp, NULL); > > return; > > err_free_bootmem_areas: > - for (i--; i >= 0; i--) > + for (int i = kho_bootmem_cnt - 1; i >= 0; i--) Check the First patch comment on this. > memblock_phys_free(kho_bootmem[i].addr, kho_bootmem[i].size); > + kho_bootmem_cnt = 0; > err_free_bootmem_desc: > memblock_free(kho_bootmem, max_nr_bootmem * sizeof(*kho_bootmem)); > err_disable_kho: > -- Regards, Mukesh Pilaniya ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 3/3] kho: fix bootmem sizing 2026-11-04 16:50 [PATCH v2 0/3] kho: fix bootmem sizing Mike Rapoport (Microsoft) 2026-11-04 16:50 ` [PATCH v2 1/3] kho: walk bootmem areas in address order Mike Rapoport (Microsoft) 2026-11-04 16:50 ` [PATCH v2 2/3] kho: skip zero-sized lowmem and global bootmem areas Mike Rapoport (Microsoft) @ 2026-11-04 16:50 ` Mike Rapoport (Microsoft) 2026-11-04 18:57 ` Pasha Tatashin ` (3 more replies) 2 siblings, 4 replies; 18+ messages in thread From: Mike Rapoport (Microsoft) @ 2026-11-04 16:50 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm 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. If ARCH_LOW_ADDRESS_LIMIT covers all memory, as may happen on arm64, any area can serve lowmem allocations, so don't reserve the lowmem area. 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 | 93 ++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 39 deletions(-) diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c index 5b1797d1289c8..c4b697a612f67 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -685,6 +685,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) { @@ -754,29 +755,58 @@ 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. + * + * The reserved memory on a node and the total reserved memory include + * lowmem, so it is subtracted from both. + * + * If ARCH_LOW_ADDRESS_LIMIT covers all memory, any area can serve lowmem + * allocations and there is no lowmem area. + * + * 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 low_limit = ARCH_LOW_ADDRESS_LIMIT; + phys_addr_t lowmem, global, size; + + if (low_limit >= memblock_end_of_DRAM() - 1) + low_limit = 0; + + lowmem = reserved_mem_size(low_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(low_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; } /* @@ -785,24 +815,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) @@ -899,7 +914,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(bootmem_size_node(nid), + if (kho_reserve_bootmem_area(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 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v2 3/3] kho: fix bootmem sizing 2026-11-04 16:50 ` [PATCH v2 3/3] kho: fix bootmem sizing Mike Rapoport (Microsoft) @ 2026-11-04 18:57 ` Pasha Tatashin 2026-11-05 9:26 ` Mike Rapoport 2026-11-04 22:17 ` Jose A. Perez de Azpillaga ` (2 subsequent siblings) 3 siblings, 1 reply; 18+ messages in thread From: Pasha Tatashin @ 2026-11-04 18:57 UTC (permalink / raw) To: Mike Rapoport (Microsoft) Cc: Pasha Tatashin, Pratyush Yadav, Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm > 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. > > If ARCH_LOW_ADDRESS_LIMIT covers all memory, as may happen on arm64, any > area can serve lowmem allocations, so don't reserve the lowmem area. > > 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> > > diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c > index 5b1797d1289c..c4b697a612f6 100644 > --- a/kernel/liveupdate/kexec_handover.c > +++ b/kernel/liveupdate/kexec_handover.c > @@ -685,6 +685,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) > { > @@ -754,29 +755,58 @@ 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. > + * > + * The reserved memory on a node and the total reserved memory include > + * lowmem, so it is subtracted from both. > + * > + * If ARCH_LOW_ADDRESS_LIMIT covers all memory, any area can serve lowmem > + * allocations and there is no lowmem area. > + * > + * 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 low_limit = ARCH_LOW_ADDRESS_LIMIT; > + phys_addr_t lowmem, global, size; > + > + if (low_limit >= memblock_end_of_DRAM() - 1) > + low_limit = 0; > + > + lowmem = reserved_mem_size(low_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(low_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; > } > > /* > @@ -785,24 +815,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); Nit, but I prefer to avoid multi-line indented statements without braces. Just put a braces around the above. Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com> -- Pasha ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 3/3] kho: fix bootmem sizing 2026-11-04 18:57 ` Pasha Tatashin @ 2026-11-05 9:26 ` Mike Rapoport 0 siblings, 0 replies; 18+ messages in thread From: Mike Rapoport @ 2026-11-05 9:26 UTC (permalink / raw) To: Pasha Tatashin Cc: Pratyush Yadav, Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm On Wed, Nov 04, 2026 at 01:57:03PM -0500, Pasha Tatashin wrote: > > - > > - 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); > > Nit, but I prefer to avoid multi-line indented statements without > braces. Just put a braces around the above. Yep, I'll fix it up while applying. > Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com> > > -- > Pasha > -- Sincerely yours, Mike. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 3/3] kho: fix bootmem sizing 2026-11-04 16:50 ` [PATCH v2 3/3] kho: fix bootmem sizing Mike Rapoport (Microsoft) 2026-11-04 18:57 ` Pasha Tatashin @ 2026-11-04 22:17 ` Jose A. Perez de Azpillaga 2026-11-10 16:54 ` Pratyush Yadav 2026-11-12 7:21 ` Mukesh Pilaniya 3 siblings, 0 replies; 18+ messages in thread From: Jose A. Perez de Azpillaga @ 2026-11-04 22:17 UTC (permalink / raw) To: Mike Rapoport (Microsoft), Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm On 11/4/26 5:50 PM, Mike Rapoport (Microsoft) wrote: > 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. > > If ARCH_LOW_ADDRESS_LIMIT covers all memory, as may happen on arm64, any > area can serve lowmem allocations, so don't reserve the lowmem area. > > 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> Reviewed-by: Jose A. Perez de Azpillaga <azpijr@gmail.com> -- cheers, jose a. p-a ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 3/3] kho: fix bootmem sizing 2026-11-04 16:50 ` [PATCH v2 3/3] kho: fix bootmem sizing Mike Rapoport (Microsoft) 2026-11-04 18:57 ` Pasha Tatashin 2026-11-04 22:17 ` Jose A. Perez de Azpillaga @ 2026-11-10 16:54 ` Pratyush Yadav 2026-11-12 7:21 ` Mukesh Pilaniya 3 siblings, 0 replies; 18+ messages in thread From: Pratyush Yadav @ 2026-11-10 16:54 UTC (permalink / raw) To: Mike Rapoport (Microsoft) Cc: Pasha Tatashin, Pratyush Yadav, Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm On Wed, Nov 04 2026, Mike Rapoport (Microsoft) wrote: > 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. > > If ARCH_LOW_ADDRESS_LIMIT covers all memory, as may happen on arm64, any > area can serve lowmem allocations, so don't reserve the lowmem area. > > 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> Reviewed-by: Pratyush Yadav <pratyush@kernel.org> [...] -- Regards, Pratyush Yadav ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 3/3] kho: fix bootmem sizing 2026-11-04 16:50 ` [PATCH v2 3/3] kho: fix bootmem sizing Mike Rapoport (Microsoft) ` (2 preceding siblings ...) 2026-11-10 16:54 ` Pratyush Yadav @ 2026-11-12 7:21 ` Mukesh Pilaniya 3 siblings, 0 replies; 18+ messages in thread From: Mukesh Pilaniya @ 2026-11-12 7:21 UTC (permalink / raw) To: Mike Rapoport (Microsoft), Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Chen Pei, George Guo, Kexin Liu, Sourabh Jain, kexec, linux-kernel, linux-mm Hi Mike, On 04/11/26 10:20 pm, Mike Rapoport (Microsoft) wrote: > 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. > > If ARCH_LOW_ADDRESS_LIMIT covers all memory, as may happen on arm64, any > area can serve lowmem allocations, so don't reserve the lowmem area. The documentation still describes the old layout says __there is always a boot memory region per node plus one for node-less allocations__, which stops being true as soon as the global or the lowmem area is empty, and the lowmem area is not mentioned at all. So please update the documentation as well. Reviewed-by: Mukesh Pilaniya <mpilaniy@redhat.com> > > 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 | 93 ++++++++++++++++++++++---------------- > 1 file changed, 54 insertions(+), 39 deletions(-) > > diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c > index 5b1797d1289c8..c4b697a612f67 100644 > --- a/kernel/liveupdate/kexec_handover.c > +++ b/kernel/liveupdate/kexec_handover.c > @@ -685,6 +685,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) > { > @@ -754,29 +755,58 @@ 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. > + * > + * The reserved memory on a node and the total reserved memory include > + * lowmem, so it is subtracted from both. > + * > + * If ARCH_LOW_ADDRESS_LIMIT covers all memory, any area can serve lowmem > + * allocations and there is no lowmem area. > + * > + * 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 low_limit = ARCH_LOW_ADDRESS_LIMIT; > + phys_addr_t lowmem, global, size; > + > + if (low_limit >= memblock_end_of_DRAM() - 1) > + low_limit = 0; > + > + lowmem = reserved_mem_size(low_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(low_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; > } > > /* > @@ -785,24 +815,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) > @@ -899,7 +914,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(bootmem_size_node(nid), > + if (kho_reserve_bootmem_area(bootmem_size_node[nid], > MEMBLOCK_ALLOC_ACCESSIBLE, nid)) { > pr_err("Failed to reserve nid %d bootmem\n", nid); > goto err_free_bootmem_areas; > -- Regards, Mukesh Pilaniya ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-11-12 8:49 UTC | newest] Thread overview: 18+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-11-04 16:50 [PATCH v2 0/3] kho: fix bootmem sizing Mike Rapoport (Microsoft) 2026-11-04 16:50 ` [PATCH v2 1/3] kho: walk bootmem areas in address order Mike Rapoport (Microsoft) 2026-11-04 18:57 ` Pasha Tatashin 2026-11-04 22:14 ` Jose A. Perez de Azpillaga 2026-11-10 16:52 ` Pratyush Yadav 2026-11-12 6:32 ` Mukesh Pilaniya 2026-11-12 8:49 ` Mike Rapoport 2026-11-04 16:50 ` [PATCH v2 2/3] kho: skip zero-sized lowmem and global bootmem areas Mike Rapoport (Microsoft) 2026-11-04 18:57 ` Pasha Tatashin 2026-11-04 22:17 ` Jose A. Perez de Azpillaga 2026-11-10 16:55 ` Pratyush Yadav 2026-11-12 6:48 ` Mukesh Pilaniya 2026-11-04 16:50 ` [PATCH v2 3/3] kho: fix bootmem sizing Mike Rapoport (Microsoft) 2026-11-04 18:57 ` Pasha Tatashin 2026-11-05 9:26 ` Mike Rapoport 2026-11-04 22:17 ` Jose A. Perez de Azpillaga 2026-11-10 16:54 ` Pratyush Yadav 2026-11-12 7:21 ` Mukesh Pilaniya
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox