Re: [PATCH v4] mm/hugetlb_cma: support percentage-based hugetlb_cma reservation

Sourav Panda <[email protected]>
Newsgroups gmane.linux.kernel,gmane.linux.kernel.mm
Message-ID <CANruzcQeg8Fcwi7_2QoKXERwX=q-7xdAaforPm9YKQUBssgWHA@mail.gmail.com>
On Thu, Aug 6, 2026 at 5:15 AM Usama Arif <[email protected]> wrote:
>
>
>
> On 06/08/2026 09:56, Sourav Panda wrote:
> > 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 <[email protected]>
> > ---
> > Link: https://lore.kernel.org/linux-mm/[email protected]/ [v3]
> > Link: https://lore.kernel.org/linux-mm/[email protected]/ [v2]
> > Link: https://lore.kernel.org/linux-mm/[email protected]/ [v1]
> >
> > v4:
> > - Clear global hugetlb_cma_percent and hugetlb_cma_size when node-specific parameters are parsed so the last command line configuration wins (Usama Arif).
> > - Warn when ALIGN_DOWN rounds down a non-zero percentage-derived reservation size to 0 MiB (Usama Arif).
> >
> > v3:
> > - Enhance pr_info logs to explicitly show percentage-derived sizes per Andrew Morton"s suggestions.
> > - Explicitly align percentage-derived sizes down to the gigantic page size to prevent allocation failures (Usama Arif).
> >
> >  .../admin-guide/kernel-parameters.txt         |   7 +-
> >  mm/hugetlb_cma.c                              | 141 +++++++++++++++++-
> >  2 files changed, 138 insertions(+), 10 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%).
>
> I think it would be good to add something like below in the doc as well:
>
> Percentage-derived sizes are rounded down to a multiple of the
> architecture's gigantic hugepage size and may become zero.
>
>
> And thanks for the patch! This is very useful to have in a heterogeneous fleet.
>
> Acked-by: Usama Arif <[email protected]>

Thanks for the reviews Usama :)

I will send v5 today with the documentation change.

>
>
> > +                     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..2ca014a0a3b8 100644
> > --- a/mm/hugetlb_cma.c
> > +++ b/mm/hugetlb_cma.c
> > @@ -9,6 +9,9 @@
> >  #include <asm/setup.h>
> >
> >  #include <linux/hugetlb.h>
> > +#include <linux/memblock.h>
> > +#include <linux/math.h>
> > +#include <linux/math64.h>
> >  #include "internal.h"
> >  #include "hugetlb_cma.h"
> >
> > @@ -18,6 +21,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 phys_addr_t __init memblock_node_memory_size(int nid)
> > +{
> > +     struct memblock_region *reg;
> > +     phys_addr_t size = 0;
> > +
> > +     for_each_mem_region(reg) {
> > +             if (reg->nid == nid)
> > +                     size += reg->size;
> > +     }
> > +     return size;
> > +}
> > +#else
> > +static phys_addr_t __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 +125,31 @@ 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);
> >
> > +                     hugetlb_cma_size = 0;
> > +                     hugetlb_cma_percent = 0;
> > +
> >                       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;
> > +                             hugetlb_cma_size_in_node[nid] = 0;
> > +                             s = next + 1;
> > +                     } else {
> > +                             hugetlb_cma_size_in_node[nid] = tmp;
> > +                             hugetlb_cma_percent_in_node[nid] = 0;
> > +                             s = next;
> > +                     }
> >
> >                       /*
> >                        * Skip the separator if have one, otherwise
> > @@ -118,7 +160,28 @@ 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;
> > +                                     hugetlb_cma_size = 0;
> > +                                     for (nid = 0; nid < MAX_NUMNODES; nid++) {
> > +                                             hugetlb_cma_size_in_node[nid] = 0;
> > +                                             hugetlb_cma_percent_in_node[nid] = 0;
> > +                                     }
> > +                             }
> > +                     } else {
> > +                             hugetlb_cma_size = tmp;
> > +                             hugetlb_cma_percent = 0;
> > +                             for (nid = 0; nid < MAX_NUMNODES; nid++) {
> > +                                     hugetlb_cma_size_in_node[nid] = 0;
> > +                                     hugetlb_cma_percent_in_node[nid] = 0;
> > +                             }
> > +                     }
> >                       break;
> >               }
> >       }
> > @@ -144,8 +207,36 @@ 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) {
> > +             hugetlb_cma_size = 0;
> > +             for (nid = 0; nid < MAX_NUMNODES; nid++) {
> > +                     if (hugetlb_cma_percent_in_node[nid]) {
> > +                             phys_addr_t node_gfp_mem = memblock_node_memory_size(nid);
> > +                             u64 s;
> > +
> > +                             s = mul_u64_u32_div((u64)node_gfp_mem,
> > +                                                 hugetlb_cma_percent_in_node[nid],
> > +                                                 100);
> > +
> > +                             hugetlb_cma_size_in_node[nid] = s;
> > +                     }
> > +                     hugetlb_cma_size += hugetlb_cma_size_in_node[nid];
> > +             }
> > +     } else if (hugetlb_cma_percent) {
> > +             hugetlb_cma_size = mul_u64_u32_div((u64)memblock_phys_mem_size(),
> > +                                                hugetlb_cma_percent, 100);
> > +     }
> > +
> >       if (!hugetlb_cma_size)
> >               return;
> >
> > @@ -163,6 +254,32 @@ void __init hugetlb_cma_reserve(void)
> >        */
> >       VM_WARN_ON(order <= MAX_PAGE_ORDER);
> >
> > +     if (hugetlb_cma_percent) {
> > +             unsigned long orig_size = hugetlb_cma_size;
> > +
> > +             hugetlb_cma_size = ALIGN_DOWN(hugetlb_cma_size, PAGE_SIZE << order);
> > +             if (orig_size && !hugetlb_cma_size)
> > +                     pr_warn("hugetlb_cma: reservation size rounded down to 0 from %lu MiB (%u%%)\n",
> > +                             orig_size / SZ_1M, hugetlb_cma_percent);
> > +     } else if (has_node_specific_param) {
> > +             hugetlb_cma_size = 0;
> > +             for (nid = 0; nid < MAX_NUMNODES; nid++) {
> > +                     if (hugetlb_cma_percent_in_node[nid]) {
> > +                             unsigned long orig_size = hugetlb_cma_size_in_node[nid];
> > +
> > +                             hugetlb_cma_size_in_node[nid] =
> > +                                     ALIGN_DOWN(hugetlb_cma_size_in_node[nid],
> > +                                                PAGE_SIZE << order);
> > +                             if (orig_size && !hugetlb_cma_size_in_node[nid])
> > +                                     pr_warn("hugetlb_cma: reservation size rounded down to 0 from %lu MiB (%u%%) on node %d\n",
> > +                                             orig_size / SZ_1M,
> > +                                             hugetlb_cma_percent_in_node[nid],
> > +                                             nid);
> > +                     }
> > +                     hugetlb_cma_size += hugetlb_cma_size_in_node[nid];
> > +             }
> > +     }
> > +
> >       hugetlb_bootmem_set_nodes();
> >
> >       for (nid = 0; nid < MAX_NUMNODES; nid++) {
> > @@ -205,8 +322,12 @@ void __init hugetlb_cma_reserve(void)
> >               per_node = DIV_ROUND_UP(hugetlb_cma_size,
> >                                       nodes_weight(hugetlb_bootmem_nodes));
> >               per_node = round_up(per_node, PAGE_SIZE << order);
> > -             pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n",
> > -                     hugetlb_cma_size / SZ_1M, per_node / SZ_1M);
> > +             if (hugetlb_cma_percent)
> > +                     pr_info("hugetlb_cma: reserve %lu MiB (%u%%), up to %lu MiB per node\n",
> > +                             hugetlb_cma_size / SZ_1M, hugetlb_cma_percent, per_node / SZ_1M);
> > +             else
> > +                     pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n",
> > +                             hugetlb_cma_size / SZ_1M, per_node / SZ_1M);
> >       }
> >
> >       reserved = 0;
> > @@ -241,8 +362,12 @@ void __init hugetlb_cma_reserve(void)
> >               }
> >
> >               reserved += size;
> > -             pr_info("hugetlb_cma: reserved %lu MiB on node %d\n",
> > -                     size / SZ_1M, nid);
> > +             if (hugetlb_cma_percent_in_node[nid])
> > +                     pr_info("hugetlb_cma: reserved %lu MiB (%u%%) on node %d\n",
> > +                             size / SZ_1M, hugetlb_cma_percent_in_node[nid], nid);
> > +             else
> > +                     pr_info("hugetlb_cma: reserved %lu MiB on node %d\n",
> > +                             size / SZ_1M, nid);
> >
> >               if (reserved >= hugetlb_cma_size)
> >                       break;
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.