mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 20:53:03 +02:00
mm/hugetlb_cma: support percentage-based hugetlb_cma reservation
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. Link: https://lore.kernel.org/20260807040003.2156630-1-souravpanda@google.com Signed-off-by: Sourav Panda <souravpanda@google.com> Acked-by: Usama Arif <usama.arif@linux.dev> Cc: David Hildenbrand <david@kernel.org> Cc: David Rientjes <rientjes@google.com> Cc: Frank van der Linden <fvdl@google.com> Cc: Greg Thelen <gthelen@google.com> Cc: Muchun Song <muchun.song@linux.dev> Cc: Oscar Salvador <osalvador@suse.de> Cc: Suren Baghdasaryan <surenb@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
28b13c3c4c
commit
34e0849142
|
|
@ -2064,8 +2064,14 @@ 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%).
|
||||
Percentage-derived sizes are rounded down to a multiple of
|
||||
the architecture's gigantic hugepage size and may become
|
||||
zero.
|
||||
Format: nn[KMGTPE] or nn% or (node format)
|
||||
<node>:nn[KMGTPE][,<node>:nn[KMGTPE]] or
|
||||
<node>:nn%[,<node>:nn%]
|
||||
|
||||
The size must be a multiple of the gigantic page size.
|
||||
When using node format, this applies to each per-node size.
|
||||
|
|
|
|||
142
mm/hugetlb_cma.c
142
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)],
|
||||
|
|
@ -90,14 +115,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
|
||||
|
|
@ -108,7 +150,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;
|
||||
}
|
||||
}
|
||||
|
|
@ -134,8 +197,36 @@ void __init hugetlb_cma_reserve(void)
|
|||
{
|
||||
unsigned long size, reserved, per_node, order, gigantic_page_size;
|
||||
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;
|
||||
|
||||
|
|
@ -154,6 +245,32 @@ void __init hugetlb_cma_reserve(void)
|
|||
VM_WARN_ON(order <= MAX_PAGE_ORDER);
|
||||
gigantic_page_size = PAGE_SIZE << 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++) {
|
||||
|
|
@ -194,8 +311,13 @@ 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, gigantic_page_size);
|
||||
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;
|
||||
|
|
@ -230,8 +352,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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user