From 3a3fc1dfd6a958615ebaab8fb251e89fc2b3f2f2 Mon Sep 17 00:00:00 2001 From: Sang-Heon Jeon Date: Fri, 17 Apr 2026 22:58:05 +0900 Subject: [PATCH 1/3] mm/fake-numa: fix under-allocation detection in uniform split When splitting NUMA node uniformly, split_nodes_size_interleave_uniform() returns the next absolute node ID, not the number of nodes created. The existing under-allocation detection logic compares next absolute node ID (ret) and request count (n), which only works when nid starts at 0. For example, on a system with 2 physical NUMA nodes (node 0: 2GB, node 1: 128MB) and numa=fake=8U, 8 fake nodes are successfully created from node 0 and split_nodes_size_interleave_uniform() returns 8. For node 1, fake node nid starts at 8, but only 4 fake nodes are created due to current FAKE_NODE_MIN_SIZE being 32MB, and split_nodes_size_interleave_uniform() returns 12. By existing under-allocation detection logic, "ret < n" (12 < 8) is false, so the under-allocation will not be detected. Fix under-allocation detection logic to compare the number of actually created nodes (ret - nid) against the request count (n). Also skip under-allocation detection logic for memoryless physical nodes where no fake nodes are created. Also, fix the outdated comment describing split_nodes_size_interleave_uniform() to match the actual return value. Signed-off-by: Sang-Heon Jeon Reported-by: Donghyeon Lee Reported-by: Munhui Chae Fixes: cc9aec03e58f ("x86/numa_emulation: Introduce uniform split capability") # 4.19 Link: https://patch.msgid.link/20260417135805.1758378-1-ekffu200098@gmail.com Signed-off-by: Mike Rapoport (Microsoft) --- mm/numa_emulation.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/mm/numa_emulation.c b/mm/numa_emulation.c index 703c8fa05048..55f26b22bb0b 100644 --- a/mm/numa_emulation.c +++ b/mm/numa_emulation.c @@ -214,7 +214,7 @@ static u64 uniform_size(u64 max_addr, u64 base, u64 hole, int nr_nodes) * Sets up fake nodes of `size' interleaved over physical nodes ranging from * `addr' to `max_addr'. * - * Returns zero on success or negative on error. + * Returns node ID of the next node on success or negative error code. */ static int __init split_nodes_size_interleave_uniform(struct numa_meminfo *ei, struct numa_meminfo *pi, @@ -398,7 +398,7 @@ void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt) */ if (strchr(emu_cmdline, 'U')) { unsigned long n; - int nid = 0; + int nid = 0, nr_created; n = simple_strtoul(emu_cmdline, &emu_cmdline, 0); ret = -1; @@ -416,9 +416,18 @@ void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt) n, &pi.blk[0], nid); if (ret < 0) break; - if (ret < n) { + + /* + * If no memory was found for this physical node, + * skip the under-allocation check. + */ + if (ret == nid) + continue; + + nr_created = ret - nid; + if (nr_created < n) { pr_info("%s: phys: %d only got %d of %ld nodes, failing\n", - __func__, i, ret, n); + __func__, i, nr_created, n); ret = -1; break; } From 9588076fb21992a5d14efeb99134ebf034c7b84f Mon Sep 17 00:00:00 2001 From: Priyanshu Kumar Date: Wed, 15 Apr 2026 12:27:31 +0000 Subject: [PATCH 2/3] tools/testing/memblock: fix stale NUMA reservation tests memblock allocations now reserve memory with MEMBLOCK_RSRV_KERN and, on NUMA configurations, record the requested node on the reserved region. Several memblock simulator NUMA tests still expected merges that only worked before those reservation semantics changed, so the suite aborted even though the allocator behavior was correct. Update the NUMA merge expectations in the memblock_alloc_try_nid() and memblock_alloc_exact_nid_raw() tests to match the current reserved region metadata rules. For cases that should still merge, create the pre-existing reservation with matching nid and MEMBLOCK_RSRV_KERN metadata. Also strengthen the memblock_alloc_node() coverage by checking the newly created reserved region directly instead of re-reading the source memory node descriptor. Finally, drop the stale README/TODO notes that still claimed memblock_alloc_node() could not be tested. The memblock simulator passes again with NUMA enabled after these updates. Signed-off-by: Priyanshu Kumar Link: https://patch.msgid.link/20260415122731.1768912-1-priyanshukumarpu@gmail.com [rppt: dropped unrelated changes] Signed-off-by: Mike Rapoport (Microsoft) --- tools/testing/memblock/README | 5 +---- tools/testing/memblock/TODO | 4 ++-- tools/testing/memblock/tests/alloc_exact_nid_api.c | 6 +++--- tools/testing/memblock/tests/alloc_nid_api.c | 6 +++--- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/tools/testing/memblock/README b/tools/testing/memblock/README index 7ca437d81806..b435f48d8a70 100644 --- a/tools/testing/memblock/README +++ b/tools/testing/memblock/README @@ -104,10 +104,7 @@ called at the beginning of each test. Known issues ============ -1. Requesting a specific NUMA node via memblock_alloc_node() does not work as - intended. Once the fix is in place, tests for this function can be added. - -2. Tests for memblock_alloc_low() can't be easily implemented. The function uses +1. Tests for memblock_alloc_low() can't be easily implemented. The function uses ARCH_LOW_ADDRESS_LIMIT marco, which can't be changed to point at the low memory of the memory_block. diff --git a/tools/testing/memblock/TODO b/tools/testing/memblock/TODO index e306c90c535f..c13ad0dae776 100644 --- a/tools/testing/memblock/TODO +++ b/tools/testing/memblock/TODO @@ -1,5 +1,5 @@ TODO ===== -1. Add tests for memblock_alloc_node() to check if the correct NUMA node is set - for the new region +1. Add tests for memblock_alloc_low() once the simulator can model + ARCH_LOW_ADDRESS_LIMIT against the low memory in memory_block diff --git a/tools/testing/memblock/tests/alloc_exact_nid_api.c b/tools/testing/memblock/tests/alloc_exact_nid_api.c index 6e14447da6e1..0c46c73b5e04 100644 --- a/tools/testing/memblock/tests/alloc_exact_nid_api.c +++ b/tools/testing/memblock/tests/alloc_exact_nid_api.c @@ -368,7 +368,7 @@ static int alloc_exact_nid_bottom_up_numa_part_reserved_check(void) max_addr = memblock_end_of_DRAM(); total_size = size + r1.size; - memblock_reserve(r1.base, r1.size); + __memblock_reserve(r1.base, r1.size, nid_req, MEMBLOCK_RSRV_KERN); allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES, min_addr, max_addr, nid_req); @@ -861,8 +861,8 @@ static int alloc_exact_nid_numa_reserved_full_merge_generic_check(void) min_addr = r2.base + r2.size; max_addr = r1.base; - memblock_reserve(r1.base, r1.size); - memblock_reserve(r2.base, r2.size); + __memblock_reserve(r1.base, r1.size, nid_req, MEMBLOCK_RSRV_KERN); + __memblock_reserve(r2.base, r2.size, nid_req, MEMBLOCK_RSRV_KERN); allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES, min_addr, max_addr, diff --git a/tools/testing/memblock/tests/alloc_nid_api.c b/tools/testing/memblock/tests/alloc_nid_api.c index 562e4701b0e0..c04923532159 100644 --- a/tools/testing/memblock/tests/alloc_nid_api.c +++ b/tools/testing/memblock/tests/alloc_nid_api.c @@ -1965,7 +1965,7 @@ static int alloc_nid_bottom_up_numa_part_reserved_check(void) max_addr = memblock_end_of_DRAM(); total_size = size + r1.size; - memblock_reserve(r1.base, r1.size); + __memblock_reserve(r1.base, r1.size, nid_req, MEMBLOCK_RSRV_KERN); allocated_ptr = run_memblock_alloc_nid(size, SMP_CACHE_BYTES, min_addr, max_addr, nid_req); @@ -2412,8 +2412,8 @@ static int alloc_nid_numa_reserved_full_merge_generic_check(void) min_addr = r2.base + r2.size; max_addr = r1.base; - memblock_reserve(r1.base, r1.size); - memblock_reserve(r2.base, r2.size); + __memblock_reserve(r1.base, r1.size, nid_req, MEMBLOCK_RSRV_KERN); + __memblock_reserve(r2.base, r2.size, nid_req, MEMBLOCK_RSRV_KERN); allocated_ptr = run_memblock_alloc_nid(size, SMP_CACHE_BYTES, min_addr, max_addr, nid_req); From 00e06cb773fd81d4f2806a6ee69d1aef8f6dd5ca Mon Sep 17 00:00:00 2001 From: Giorgi Tchankvetadze Date: Tue, 2 Jun 2026 15:32:45 +0400 Subject: [PATCH 3/3] mm: mm_init: use div64_ul() instead of do_div() Fixes Coccinelle/coccicheck warning reported by do_div.cocci. Compared to do_div(), div64_ul() does not implicitly cast the divisor and does not unnecessarily calculate the remainder. There are no functional changes. The benefit is purely a semantic cleanup that better communicates the intent of the division and resolves the static analysis warning. Signed-off-by: Giorgi Tchankvetadze Link: https://patch.msgid.link/20260602-mm-div64-cleanup-v1-1-bf5d67d89d93@gmail.com Signed-off-by: Mike Rapoport (Microsoft) --- mm/mm_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/mm_init.c b/mm/mm_init.c index f9f8e1af921c..4e0909a721d2 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -2412,7 +2412,7 @@ void *__init alloc_large_system_hash(const char *tablename, /* limit allocation size to 1/16 total memory by default */ if (max == 0) { max = ((unsigned long long)nr_all_pages << PAGE_SHIFT) >> 4; - do_div(max, bucketsize); + max = div64_ul(max, bucketsize); } max = min(max, 0x80000000ULL);