From: Paul Sherman <shermanpauldylan@gmail.com>
To: linux-mm@kvack.org
Cc: tj@kernel.org, vbabka@suse.cz, dennis@kernel.org,
akpm@linux-foundation.org, linux-kernel@vger.kernel.org,
Paul Sherman <shermanpauldylan@gmail.com>
Subject: [PATCH] mm/percpu: allow embed allocator when total size fits in vmalloc
Date: Fri, 17 Jul 2026 16:16:16 -0700 [thread overview]
Message-ID: <20260717231616.9126-1-shermanpauldylan@gmail.com> (raw)
On large NUMA systems (e.g. 4-node 128GB), the physical span between
NUMA nodes may exceed 75% of vmalloc space even though the total percpu
allocation is tiny (e.g. ~6MB for 64 CPUs).
The 75% check was designed for pcpu_get_vm_areas() used by dynamic
percpu chunks, where vmalloc congruency is required. The embed
allocator uses the linear map directly for the first chunk -- physical
addresses are accessible as virtual addresses without vmalloc mapping.
The relevant constraint is total percpu size, not physical span.
Replace the unconditional fallback with a total-size check: if the
aggregate percpu allocation fits within 75% of vmalloc space, proceed
with embed regardless of physical NUMA span. Systems where total percpu
size genuinely exceeds the vmalloc bound retain the page allocator
fallback.
Tested on Sophgo SG2042 (64-hart, 4-NUMA, 128GB DDR4, RISC-V Sv39):
percpu: embed: span 0x17def7a000 > vmalloc 75% but total 0x5c0000
fits -- linear map used
percpu: Embedded 23 pages/cpu s54168 r8192 d31848 u94208
Link: https://lkml.iu.edu/hypermail/linux/kernel/1707.3/00337.html
Cc: Tejun Heo <tj@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Dennis Zhou <dennis@kernel.org>
Signed-off-by: Paul Sherman <shermanpauldylan@gmail.com>
---
This fix is inert on systems where the original check never fired;
it only activates when physical span exceeds 75% of vmalloc but total
percpu size does not.
Architecture analysis:
Architecture | vmalloc | phys span | total percpu | result
---------------|--------------|--------------|--------------|--------
RISC-V Sv39 | ~88 GB | ~102 GB | ~6 MB | fixed
RISC-V Sv48 | ~88 TB | ~102 GB | ~6 MB | unaffected
RISC-V Sv57 | ~44 PB | ~102 GB | ~6 MB | unaffected
ARM64 large | ~248 TB | varies | tiny | unaffected
32-bit NUMA | ~128 MB | varies | may exceed | correct fallback
Tejun Heo noted in 2017 [Link] that the only constraint is vmalloc
size relative to NUMA node distances, and that making vmalloc bigger
would be the best fix. On RISC-V Sv39 with 88GB vmalloc and 102GB
physical NUMA span that is not an option -- but the embed allocator
does not need congruent vmalloc mapping for the first chunk anyway.
mm/percpu.c | 29 ++++++++++++++++++++++++-----
1 file changed, 24 insertions(+), 5 deletions(-)
diff --git a/mm/percpu.c b/mm/percpu.c
index b0676b8054ed..72695778872c 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -3069,13 +3069,32 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size,
/* warn if maximum distance is further than 75% of vmalloc space */
if (max_distance > VMALLOC_TOTAL * 3 / 4) {
- pr_warn("max_distance=0x%lx too large for vmalloc space 0x%lx\n",
+ pr_warn("percpu: embed: max_distance=0x%lx too large for vmalloc space 0x%lx\n",
max_distance, VMALLOC_TOTAL);
#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK
- /* and fail if we have fallback */
- rc = -EINVAL;
- goto out_free_areas;
-#endif
+ /*
+ * The embed allocator uses the linear map directly for the
+ * first chunk -- physical addresses are accessible as virtual
+ * addresses without vmalloc mapping. The 75% check was designed
+ * for pcpu_get_vm_areas() (dynamic chunks) where vmalloc
+ * congruency is required. On large NUMA systems, physical span
+ * between nodes may exceed vmalloc bounds even though total
+ * percpu size is tiny. Check total size, not physical span.
+ */
+ {
+ unsigned long total_size = 0;
+ for (group = 0; group < ai->nr_groups; group++)
+ total_size += (unsigned long)ai->unit_size *
+ ai->groups[group].nr_units;
+ if (total_size > VMALLOC_TOTAL * 3 / 4) {
+ rc = -EINVAL;
+ goto out_free_areas;
+ }
+ pr_info("percpu: embed: span 0x%lx > vmalloc 75%%"
+ " but total 0x%lx fits -- linear map used\n",
+ max_distance, total_size);
+ }
+#endif /* CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK */
}
/*
--
2.53.0
next reply other threads:[~2026-07-17 23:16 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-17 23:16 Paul Sherman [this message]
2026-07-18 0:23 ` [PATCH] mm/percpu: allow embed allocator when total size fits in vmalloc Andrew Morton
2026-07-18 17:49 ` Paul Sherman
2026-07-19 5:59 ` Paul Sherman
2026-07-20 14:02 ` Dennis Zhou
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=20260717231616.9126-1-shermanpauldylan@gmail.com \
--to=shermanpauldylan@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=dennis@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=tj@kernel.org \
--cc=vbabka@suse.cz \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.