[PATCH 03/11] cgroup: add memory_cma_accounting mount option

From: Eric Chanudet

Date: Fri Aug 21 2026 - 14:59:43 EST


Add a cgroup v2 mount option that will be used later in this series to
enable CMA memory accounting under memcg.

The option is made opt-in as it will charge allocations to the cgroup's
overall memory usage, which changes existing expectations.

Signed-off-by: Eric Chanudet <echanude@xxxxxxxxxx>
---
Documentation/admin-guide/cgroup-v2.rst | 20 ++++++++++++++++++++
include/linux/cgroup-defs.h | 5 +++++
kernel/cgroup/cgroup.c | 15 ++++++++++++++-
3 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
index aed195a71cbf..3dfc13f31a0c 100644
--- a/Documentation/admin-guide/cgroup-v2.rst
+++ b/Documentation/admin-guide/cgroup-v2.rst
@@ -246,6 +246,26 @@ cgroup v2 currently supports the following mount options.
will not be tracked by the memory controller (even if cgroup
v2 is remounted later on).

+ memory_cma_accounting
+ Count CMA memory usage towards the cgroup's overall memory usage for
+ the memory controller, and expose per-CMA-area usage counters. This
+ behavior is opt-in, so as to not cause regression on existing setups.
+
+ A few caveats to keep in mind:
+
+ * CMA areas are reserved at boot time, memory is only charged to a
+ cgroup when a CMA allocation is performed on its behalf.
+ * CMA pages allocated while this option is not enabled will not be
+ tracked by the memory controller, even if cgroup v2 is remounted
+ later on with this option. Charges happen at allocation.
+ * CMA allocations are charged both to the cgroup's memory counter
+ (limited by memory.max) and the per-area CMA counter (limited by
+ memory.cma.<area>.max). Hitting either limit can cause an allocation
+ to fail. If CMA usage pushes the cgroup over memory.high or
+ memory.max, the memory controller will attempt to reclaim other
+ memory only. CMA memory charged to the cgroup is not reclaimable.
+ Limits should be sized to accommodate the expected CMA pressure.
+
pids_localevents
The option restores v1-like behavior of pids.events:max, that is only
local (inside cgroup proper) fork failures are counted. Without this
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index de2cd6238c2a..15f3f7110c5b 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -129,6 +129,11 @@ enum {
* Enable legacy local pids.events.
*/
CGRP_ROOT_PIDS_LOCAL_EVENTS = (1 << 20),
+
+ /*
+ * Enable cma accounting for the memory controller.
+ */
+ CGRP_ROOT_MEMORY_CMA_ACCOUNTING = (1 << 21),
};

/* cftype->flags */
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index b5b461d4418b..12184f85ad10 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -1985,6 +1985,7 @@ enum cgroup2_param {
Opt_memory_recursiveprot,
Opt_memory_hugetlb_accounting,
Opt_pids_localevents,
+ Opt_memory_cma_accounting,
nr__cgroup2_params
};

@@ -1995,6 +1996,7 @@ static const struct fs_parameter_spec cgroup2_fs_parameters[] = {
fsparam_flag("memory_recursiveprot", Opt_memory_recursiveprot),
fsparam_flag("memory_hugetlb_accounting", Opt_memory_hugetlb_accounting),
fsparam_flag("pids_localevents", Opt_pids_localevents),
+ fsparam_flag("memory_cma_accounting", Opt_memory_cma_accounting),
{}
};

@@ -2027,6 +2029,9 @@ static int cgroup2_parse_param(struct fs_context *fc, struct fs_parameter *param
case Opt_pids_localevents:
ctx->flags |= CGRP_ROOT_PIDS_LOCAL_EVENTS;
return 0;
+ case Opt_memory_cma_accounting:
+ ctx->flags |= CGRP_ROOT_MEMORY_CMA_ACCOUNTING;
+ return 0;
}
return -EINVAL;
}
@@ -2068,6 +2073,11 @@ static void apply_cgroup_root_flags(unsigned int root_flags)
cgrp_dfl_root.flags |= CGRP_ROOT_PIDS_LOCAL_EVENTS;
else
cgrp_dfl_root.flags &= ~CGRP_ROOT_PIDS_LOCAL_EVENTS;
+
+ if (root_flags & CGRP_ROOT_MEMORY_CMA_ACCOUNTING)
+ cgrp_dfl_root.flags |= CGRP_ROOT_MEMORY_CMA_ACCOUNTING;
+ else
+ cgrp_dfl_root.flags &= ~CGRP_ROOT_MEMORY_CMA_ACCOUNTING;
}
}

@@ -2085,6 +2095,8 @@ static int cgroup_show_options(struct seq_file *seq, struct kernfs_root *kf_root
seq_puts(seq, ",memory_hugetlb_accounting");
if (cgrp_dfl_root.flags & CGRP_ROOT_PIDS_LOCAL_EVENTS)
seq_puts(seq, ",pids_localevents");
+ if (cgrp_dfl_root.flags & CGRP_ROOT_MEMORY_CMA_ACCOUNTING)
+ seq_puts(seq, ",memory_cma_accounting");
return 0;
}

@@ -7520,7 +7532,8 @@ static ssize_t features_show(struct kobject *kobj, struct kobj_attribute *attr,
"memory_localevents\n"
"memory_recursiveprot\n"
"memory_hugetlb_accounting\n"
- "pids_localevents\n");
+ "pids_localevents\n"
+ "memory_cma_accounting\n");
}
static struct kobj_attribute cgroup_features_attr = __ATTR_RO(features);


--
2.53.0