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 <[email protected]>
---
 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


Reply via email to