[PATCH 06/11] memcg: register per-area usage counters in cgroupfs

Eric Chanudet <[email protected]>
Newsgroups org.kernel.vger.cgroups,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest,org.kvack.linux-mm
Message-ID <[email protected]>
Expose memory.cma.<area>.{current,max} files under each non-root cgroup
when cgroupfs memory_cma_accounting option is enabled.

memory.cma.<area>.current reports the cgroup's CMA usage for that area.
memory.cma.<area>.max is a read-write limit (default: max).

Each CMA area gets a cftype template with its name set from the CMA
area's name.

Signed-off-by: Eric Chanudet <[email protected]>
---
 Documentation/admin-guide/cgroup-v2.rst | 15 ++++++
 mm/memcontrol.c                         | 89 +++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+)

diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
index 3dfc13f31a0c..39871a7a08a8 100644
--- a/Documentation/admin-guide/cgroup-v2.rst
+++ b/Documentation/admin-guide/cgroup-v2.rst
@@ -1928,6 +1928,21 @@ The following nested keys are defined.
 	This setting has no effect if zswap is disabled, and swapping
 	is allowed unless memory.swap.max is set to 0.
 
+  memory.cma.<area>.current
+        A read-only single value file which exists on non-root cgroups. <area>
+        is the CMA area name (e.g. "reserved" for the default DMA CMA area).
+
+        The total amount of CMA memory currently charged to the cgroup for the
+        given CMA area. Only accounted when memory_cma_accounting is enabled.
+
+  memory.cma.<area>.max
+        A read-write single value file which exists on non-root cgroups. The
+        default is "max".
+
+        CMA usage hard limit for the given area. If a cgroup's CMA usage for
+        this area exceeds this limit, the allocation will fail. Only enforced
+        when memory_cma_accounting is enabled.
+
   memory.pressure
 	A read-only nested-keyed file.
 
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 8eca00d30fc5..f28d610a59ce 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -6182,3 +6182,92 @@ void mem_cgroup_show_protected_memory(struct mem_cgroup *memcg)
 		K(atomic_long_read(&memcg->memory.children_min_usage)),
 		K(atomic_long_read(&memcg->memory.children_low_usage)));
 }
+
+#ifdef CONFIG_CMA
+static int memory_cma_current_show(struct seq_file *m, void *v)
+{
+	struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
+	int idx = seq_cft(m)->private;
+	unsigned long cur = page_counter_read(&memcg->cma_counters[idx]);
+
+	seq_printf(m, "%lu\n", cur * PAGE_SIZE);
+
+	return 0;
+}
+
+static int memory_cma_max_show(struct seq_file *m, void *v)
+{
+	struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
+	int idx = seq_cft(m)->private;
+	unsigned long max = READ_ONCE(memcg->cma_counters[idx].max);
+
+	return seq_puts_memcg_tunable(m, max);
+}
+
+static ssize_t memory_cma_max_write(struct kernfs_open_file *of, char *buf,
+				    size_t nbytes, loff_t off)
+{
+	struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
+	int idx = of_cft(of)->private;
+	unsigned long max;
+	int rc;
+
+	buf = strstrip(buf);
+	rc = page_counter_memparse(buf, "max", &max);
+	if (rc)
+		return rc;
+
+	xchg(&memcg->cma_counters[idx].max, max);
+
+	return nbytes;
+}
+
+static struct cftype cma_dfl_tmpl[] = {
+	{
+		.name = "current",
+		.seq_show = memory_cma_current_show,
+		.flags = CFTYPE_NOT_ON_ROOT,
+	},
+	{
+		.name = "max",
+		.seq_show = memory_cma_max_show,
+		.write = memory_cma_max_write,
+		.flags = CFTYPE_NOT_ON_ROOT,
+	},
+	{ }
+};
+#define CMA_DFL_TMPL_SIZE	(ARRAY_SIZE(cma_dfl_tmpl) - 1)
+
+static struct cftype *cma_dfl_files;
+
+static int __init mem_cgroup_cma_init(void)
+{
+	struct cftype *cft;
+	unsigned int i, j;
+	int count;
+
+	if (mem_cgroup_disabled() || !cma_area_count)
+		return 0;
+
+	count = cma_area_count * CMA_DFL_TMPL_SIZE;
+	cma_dfl_files = kcalloc(count + 1, sizeof(*cma_dfl_tmpl), GFP_KERNEL);
+	if (!cma_dfl_files)
+		return -ENOMEM;
+
+	for (i = 0; i < cma_area_count; ++i)
+		for (j = 0; j < CMA_DFL_TMPL_SIZE; ++j) {
+			cft = &cma_dfl_files[i * CMA_DFL_TMPL_SIZE + j];
+			*cft = cma_dfl_tmpl[j];
+			snprintf(cft->name, MAX_CFTYPE_NAME, "cma.%s.%s",
+				 cma_get_name(&cma_areas[i]),
+				 cma_dfl_tmpl[j].name);
+			cft->private = i; /* cma area index for counters in callbacks. */
+			lockdep_register_key(&cft->lockdep_key);
+		}
+
+	WARN_ON(cgroup_add_dfl_cftypes(&memory_cgrp_subsys, cma_dfl_files));
+
+	return 0;
+}
+subsys_initcall(mem_cgroup_cma_init);
+#endif /* CONFIG_CMA */

-- 
2.53.0
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.