* [PATCH v1] mm/hugetlb_cma: support percentage-based hugetlb_cma reservation
@ 2026-06-25 21:59 Sourav Panda
2026-06-26 12:18 ` kernel test robot
0 siblings, 1 reply; 2+ messages in thread
From: Sourav Panda @ 2026-06-25 21:59 UTC (permalink / raw)
To: muchun.song, osalvador, akpm
Cc: david, surenb, fvdl, gthelen, souravpanda, linux-mm, linux-kernel
Currently, hugetlb_cma reservation only supports absolute sizes (e.g.,
hugetlb_cma=2G or hugetlb_cma=0:1G,1:1G). This can be restrictive in
heterogeneous environments or when deploying common kernel command lines
across machines with different memory capacities.
Add support for percentage-based hugetlb_cma reservation (e.g.,
hugetlb_cma=20% or hugetlb_cma=0:20%,1:10%).
The percentage is calculated against the total memory (for global
settings) or against the node-specific memory (for node-specific
settings) using memblock APIs during early boot.
Signed-off-by: Sourav Panda <souravpanda@google.com>
---
.../admin-guide/kernel-parameters.txt | 7 +-
mm/hugetlb_cma.c | 81 ++++++++++++++++++-
2 files changed, 82 insertions(+), 6 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 5a05b48d1684..846940ce2858 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2064,8 +2064,11 @@ Kernel parameters
hugetlb_cma= [HW,CMA,EARLY] The size of a CMA area used for allocation
of gigantic hugepages. Or using node format, the size
of a CMA area per node can be specified.
- Format: nn[KMGTPE] or (node format)
- <node>:nn[KMGTPE][,<node>:nn[KMGTPE]]
+ The size can be an absolute value (e.g., 2G) or a
+ percentage of the total memory or node memory (e.g., 20%).
+ Format: nn[KMGTPE] or nn% or (node format)
+ <node>:nn[KMGTPE][,<node>:nn[KMGTPE]] or
+ <node>:nn%[,<node>:nn%]
Reserve a CMA area of given size and allocate gigantic
hugepages using the CMA allocator. If enabled, the
diff --git a/mm/hugetlb_cma.c b/mm/hugetlb_cma.c
index 7693ccefd0c6..b4f8bbe4c62d 100644
--- a/mm/hugetlb_cma.c
+++ b/mm/hugetlb_cma.c
@@ -9,6 +9,8 @@
#include <asm/setup.h>
#include <linux/hugetlb.h>
+#include <linux/memblock.h>
+#include <linux/math.h>
#include "internal.h"
#include "hugetlb_cma.h"
@@ -18,6 +20,28 @@ static unsigned long hugetlb_cma_size_in_node[MAX_NUMNODES] __initdata;
static bool hugetlb_cma_only __ro_after_init;
static unsigned long hugetlb_cma_size __ro_after_init;
+static unsigned int hugetlb_cma_percent __initdata;
+static unsigned int hugetlb_cma_percent_in_node[MAX_NUMNODES] __initdata;
+
+#ifdef CONFIG_NUMA
+static unsigned long __init memblock_node_memory_size(int nid)
+{
+ struct memblock_region *reg;
+ unsigned long size = 0;
+
+ for_each_mem_region(reg) {
+ if (reg->nid == nid)
+ size += reg->size;
+ }
+ return size;
+}
+#else
+static unsigned long __init memblock_node_memory_size(int nid)
+{
+ return memblock_phys_mem_size();
+}
+#endif
+
void hugetlb_cma_free_frozen_folio(struct folio *folio)
{
WARN_ON_ONCE(!cma_release_frozen(hugetlb_cma[folio_nid(folio)],
@@ -100,14 +124,27 @@ static int __init cmdline_parse_hugetlb_cma(char *p)
break;
if (s[count] == ':') {
+ char *next;
+
if (tmp >= MAX_NUMNODES)
break;
nid = array_index_nospec(tmp, MAX_NUMNODES);
s += count + 1;
- tmp = memparse(s, &s);
- hugetlb_cma_size_in_node[nid] = tmp;
- hugetlb_cma_size += tmp;
+ tmp = memparse(s, &next);
+ if (*next == '%') {
+ if (tmp > 100) {
+ pr_warn("hugetlb_cma: invalid percentage %lu for node %d\n",
+ tmp, nid);
+ break;
+ }
+ hugetlb_cma_percent_in_node[nid] = tmp;
+ s = next + 1;
+ } else {
+ hugetlb_cma_size_in_node[nid] = tmp;
+ hugetlb_cma_size += tmp;
+ s = next;
+ }
/*
* Skip the separator if have one, otherwise
@@ -118,7 +155,17 @@ static int __init cmdline_parse_hugetlb_cma(char *p)
else
break;
} else {
- hugetlb_cma_size = memparse(p, &p);
+ char *next;
+
+ tmp = memparse(p, &next);
+ if (*next == '%') {
+ if (tmp > 100)
+ pr_warn("hugetlb_cma: invalid percentage %lu\n", tmp);
+ else
+ hugetlb_cma_percent = tmp;
+ } else {
+ hugetlb_cma_size = tmp;
+ }
break;
}
}
@@ -144,8 +191,34 @@ void __init hugetlb_cma_reserve(void)
{
unsigned long size, reserved, per_node, order;
bool node_specific_cma_alloc = false;
+ bool has_node_specific_param = false;
int nid;
+ for (nid = 0; nid < MAX_NUMNODES; nid++) {
+ if (hugetlb_cma_size_in_node[nid] || hugetlb_cma_percent_in_node[nid]) {
+ has_node_specific_param = true;
+ break;
+ }
+ }
+
+ if (has_node_specific_param) {
+ for (nid = 0; nid < MAX_NUMNODES; nid++) {
+ if (hugetlb_cma_percent_in_node[nid]) {
+ unsigned long node_gfp_mem = memblock_node_memory_size(nid);
+ unsigned long s;
+
+ s = mult_frac(node_gfp_mem,
+ hugetlb_cma_percent_in_node[nid],
+ 100);
+
+ hugetlb_cma_size_in_node[nid] = s;
+ hugetlb_cma_size += s;
+ }
+ }
+ } else if (hugetlb_cma_percent) {
+ hugetlb_cma_size = mult_frac(memblock_phys_mem_size(), hugetlb_cma_percent, 100);
+ }
+
if (!hugetlb_cma_size)
return;
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH v1] mm/hugetlb_cma: support percentage-based hugetlb_cma reservation
2026-06-25 21:59 [PATCH v1] mm/hugetlb_cma: support percentage-based hugetlb_cma reservation Sourav Panda
@ 2026-06-26 12:18 ` kernel test robot
0 siblings, 0 replies; 2+ messages in thread
From: kernel test robot @ 2026-06-26 12:18 UTC (permalink / raw)
To: Sourav Panda, muchun.song, osalvador, akpm
Cc: oe-kbuild-all, david, surenb, fvdl, gthelen, souravpanda,
linux-mm, linux-kernel
Hi Sourav,
kernel test robot noticed the following build errors:
[auto build test ERROR on v7.1]
[also build test ERROR on linus/master]
[cannot apply to akpm-mm/mm-everything]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Sourav-Panda/mm-hugetlb_cma-support-percentage-based-hugetlb_cma-reservation/20260626-060014
base: v7.1
patch link: https://lore.kernel.org/r/20260625215900.2151690-1-souravpanda%40google.com
patch subject: [PATCH v1] mm/hugetlb_cma: support percentage-based hugetlb_cma reservation
config: i386-randconfig-062-20260626 (https://download.01.org/0day-ci/archive/20260626/202606262023.IKUrn01I-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
sparse: v0.6.5-rc1
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260626/202606262023.IKUrn01I-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202606262023.IKUrn01I-lkp@intel.com/
All errors (new ones prefixed by >>):
ld: mm/hugetlb_cma.o: in function `hugetlb_cma_reserve':
>> mm/hugetlb_cma.c:219:(.init.text+0x21b): undefined reference to `__udivmoddi4'
>> ld: mm/hugetlb_cma.c:219:(.init.text+0x22f): undefined reference to `__udivdi3'
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for MFD_STMFX
Depends on [n]: HAS_IOMEM [=y] && I2C [=y] && OF [=n]
Selected by [y]:
- PINCTRL_STMFX [=y] && PINCTRL [=y] && I2C [=y] && HAS_IOMEM [=y]
vim +219 mm/hugetlb_cma.c
189
190 void __init hugetlb_cma_reserve(void)
191 {
192 unsigned long size, reserved, per_node, order;
193 bool node_specific_cma_alloc = false;
194 bool has_node_specific_param = false;
195 int nid;
196
197 for (nid = 0; nid < MAX_NUMNODES; nid++) {
198 if (hugetlb_cma_size_in_node[nid] || hugetlb_cma_percent_in_node[nid]) {
199 has_node_specific_param = true;
200 break;
201 }
202 }
203
204 if (has_node_specific_param) {
205 for (nid = 0; nid < MAX_NUMNODES; nid++) {
206 if (hugetlb_cma_percent_in_node[nid]) {
207 unsigned long node_gfp_mem = memblock_node_memory_size(nid);
208 unsigned long s;
209
210 s = mult_frac(node_gfp_mem,
211 hugetlb_cma_percent_in_node[nid],
212 100);
213
214 hugetlb_cma_size_in_node[nid] = s;
215 hugetlb_cma_size += s;
216 }
217 }
218 } else if (hugetlb_cma_percent) {
> 219 hugetlb_cma_size = mult_frac(memblock_phys_mem_size(), hugetlb_cma_percent, 100);
220 }
221
222 if (!hugetlb_cma_size)
223 return;
224
225 order = arch_hugetlb_cma_order();
226 if (!order) {
227 pr_warn("hugetlb_cma: the option isn't supported by current arch\n");
228 return;
229 }
230
231 /*
232 * HugeTLB CMA reservation is required for gigantic
233 * huge pages which could not be allocated via the
234 * page allocator. Just warn if there is any change
235 * breaking this assumption.
236 */
237 VM_WARN_ON(order <= MAX_PAGE_ORDER);
238
239 hugetlb_bootmem_set_nodes();
240
241 for (nid = 0; nid < MAX_NUMNODES; nid++) {
242 if (hugetlb_cma_size_in_node[nid] == 0)
243 continue;
244
245 if (!node_isset(nid, hugetlb_bootmem_nodes)) {
246 pr_warn("hugetlb_cma: invalid node %d specified\n", nid);
247 hugetlb_cma_size -= hugetlb_cma_size_in_node[nid];
248 hugetlb_cma_size_in_node[nid] = 0;
249 continue;
250 }
251
252 if (hugetlb_cma_size_in_node[nid] < (PAGE_SIZE << order)) {
253 pr_warn("hugetlb_cma: cma area of node %d should be at least %lu MiB\n",
254 nid, (PAGE_SIZE << order) / SZ_1M);
255 hugetlb_cma_size -= hugetlb_cma_size_in_node[nid];
256 hugetlb_cma_size_in_node[nid] = 0;
257 } else {
258 node_specific_cma_alloc = true;
259 }
260 }
261
262 /* Validate the CMA size again in case some invalid nodes specified. */
263 if (!hugetlb_cma_size)
264 return;
265
266 if (hugetlb_cma_size < (PAGE_SIZE << order)) {
267 pr_warn("hugetlb_cma: cma area should be at least %lu MiB\n",
268 (PAGE_SIZE << order) / SZ_1M);
269 hugetlb_cma_size = 0;
270 return;
271 }
272
273 if (!node_specific_cma_alloc) {
274 /*
275 * If 3 GB area is requested on a machine with 4 numa nodes,
276 * let's allocate 1 GB on first three nodes and ignore the last one.
277 */
278 per_node = DIV_ROUND_UP(hugetlb_cma_size,
279 nodes_weight(hugetlb_bootmem_nodes));
280 per_node = round_up(per_node, PAGE_SIZE << order);
281 pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n",
282 hugetlb_cma_size / SZ_1M, per_node / SZ_1M);
283 }
284
285 reserved = 0;
286 for_each_node_mask(nid, hugetlb_bootmem_nodes) {
287 int res;
288 char name[CMA_MAX_NAME];
289
290 if (node_specific_cma_alloc) {
291 if (hugetlb_cma_size_in_node[nid] == 0)
292 continue;
293
294 size = hugetlb_cma_size_in_node[nid];
295 } else {
296 size = min(per_node, hugetlb_cma_size - reserved);
297 }
298
299 size = round_up(size, PAGE_SIZE << order);
300
301 snprintf(name, sizeof(name), "hugetlb%d", nid);
302 /*
303 * Note that 'order per bit' is based on smallest size that
304 * may be returned to CMA allocator in the case of
305 * huge page demotion.
306 */
307 res = cma_declare_contiguous_multi(size, PAGE_SIZE << order,
308 HUGETLB_PAGE_ORDER, name,
309 &hugetlb_cma[nid], nid);
310 if (res) {
311 pr_warn("hugetlb_cma: reservation failed: err %d, node %d",
312 res, nid);
313 continue;
314 }
315
316 reserved += size;
317 pr_info("hugetlb_cma: reserved %lu MiB on node %d\n",
318 size / SZ_1M, nid);
319
320 if (reserved >= hugetlb_cma_size)
321 break;
322 }
323
324 if (!reserved)
325 /*
326 * hugetlb_cma_size is used to determine if allocations from
327 * cma are possible. Set to zero if no cma regions are set up.
328 */
329 hugetlb_cma_size = 0;
330 }
331
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-06-26 12:19 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-25 21:59 [PATCH v1] mm/hugetlb_cma: support percentage-based hugetlb_cma reservation Sourav Panda
2026-06-26 12:18 ` kernel test robot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox