@@ -266,6 +266,7 @@ struct damos {
enum damon_ops_id {
DAMON_OPS_VADDR,
DAMON_OPS_PADDR,
+ DAMON_OPS_CMA,
NR_DAMON_OPS,
};
@@ -2,7 +2,7 @@
obj-y := core.o
obj-$(CONFIG_DAMON_VADDR) += ops-common.o vaddr.o
-obj-$(CONFIG_DAMON_PADDR) += ops-common.o paddr.o
+obj-$(CONFIG_DAMON_PADDR) += ops-common.o paddr.o paddr-cma.o
obj-$(CONFIG_DAMON_SYSFS) += sysfs.o
obj-$(CONFIG_DAMON_DBGFS) += dbgfs.o
obj-$(CONFIG_DAMON_RECLAIM) += reclaim.o
new file mode 100644
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DAMON Primitives for The CMA Physical Address Space
+ *
+ * Author: Xin Hao <xhao@linux.alibaba.com>
+ */
+#ifdef CONFIG_CMA
+
+#define pr_fmt(fmt) "damon-cma: " fmt
+
+#include <linux/cma.h>
+
+#include "ops-common.h"
+#include "../cma.h"
+
+static int damon_cma_area_regions(struct damon_addr_range *regions, int nr_cma_area)
+{
+ int i;
+
+ if (!nr_cma_area || !regions)
+ return -EINVAL;
+
+ for (i = 0; i < nr_cma_area; i++) {
+ phys_addr_t base = cma_get_base(&cma_areas[i]);
+
+ regions[i].start = base;
+ regions[i].end = base + cma_get_size(&cma_areas[i]);
+ }
+
+ return 0;
+}
+
+static void __damon_cma_init_regions(struct damon_ctx *ctx,
+ struct damon_target *t)
+{
+ struct damon_target *ti;
+ struct damon_region *r;
+ struct damon_addr_range regions[MAX_CMA_AREAS];
+ unsigned long sz = 0, nr_pieces;
+ int i, tidx = 0;
+
+ if (damon_cma_area_regions(regions, cma_area_count)) {
+ damon_for_each_target(ti, ctx) {
+ if (ti == t)
+ break;
+ tidx++;
+ }
+ pr_err("Failed to get CMA regions of %dth target\n", tidx);
+ return;
+ }
+
+ for (i = 0; i < cma_area_count; i++)
+ sz += regions[i].end - regions[i].start;
+ if (ctx->min_nr_regions)
+ sz /= ctx->min_nr_regions;
+ if (sz < DAMON_MIN_REGION)
+ sz = DAMON_MIN_REGION;
+
+ /* Set the initial three regions of the target */
+ for (i = 0; i < cma_area_count; i++) {
+ r = damon_new_region(regions[i].start, regions[i].end);
+ if (!r) {
+ pr_err("%d'th init region creation failed\n", i);
+ return;
+ }
+ damon_add_region(r, t);
+
+ nr_pieces = (regions[i].end - regions[i].start) / sz;
+ damon_evenly_split_region(t, r, nr_pieces);
+ }
+}
+
+static void damon_cma_init(struct damon_ctx *ctx)
+{
+ struct damon_target *t;
+
+ damon_for_each_target(t, ctx) {
+ /* the user may set the target regions as they want */
+ if (!damon_nr_regions(t))
+ __damon_cma_init_regions(ctx, t);
+ }
+}
+
+static int __init damon_cma_initcall(void)
+{
+ struct damon_operations ops = {
+ .id = DAMON_OPS_CMA,
+ .init = damon_cma_init,
+ .update = NULL,
+ .prepare_access_checks = damon_pa_prepare_access_checks,
+ .check_accesses = damon_pa_check_accesses,
+ .reset_aggregated = NULL,
+ .target_valid = NULL,
+ .cleanup = NULL,
+ .apply_scheme = damon_pa_apply_scheme,
+ .get_scheme_score = damon_pa_scheme_score,
+ };
+
+ return damon_register_ops(&ops);
+};
+
+subsys_initcall(damon_cma_initcall);
+
+#endif /* CONFIG_CMA */
@@ -1761,6 +1761,7 @@ static struct kobj_type damon_sysfs_attrs_ktype = {
static const char * const damon_sysfs_ops_strs[] = {
"vaddr",
"paddr",
+ "cma",
};
struct damon_sysfs_context {
Users can do the CMA memory monitoring by writing a special keyword 'cma' to the 'operations' sysfs file. Then, DAMON will check the special keyword and configure the monitoring context to run with the CMA reserved physical address space. Unlike other physical memorys monitoring, the monitoring target region will be automatically set. Signed-off-by: Xin Hao <xhao@linux.alibaba.com> --- include/linux/damon.h | 1 + mm/damon/Makefile | 2 +- mm/damon/paddr-cma.c | 104 ++++++++++++++++++++++++++++++++++++++++++ mm/damon/sysfs.c | 1 + 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 mm/damon/paddr-cma.c