[RFC PATCH v4 02/11] mm/damon/core: merge quota-sliced regions back

From: SeongJae Park

Date: Thu Apr 09 2026 - 10:25:07 EST


damos_apply_scheme() splits the given region to avoid applying action to
the region results in applying action to more than the quota limit
memory. When such a split happens multiple times, theoretically that
could result in violating the user-set max_nr_regions limit. If that
happens, DAMON could impose overhead larger than the max_nr_regions
based expectation.

Such cases should be rare since usually the real number of DAMON regions
are much lower than the max_nr_regions. Even if it happens, because the
split operations could be made only up to the number of schemes per
scheme apply interval, the impact will be negligible. The impact could
be higher after the following commit, though. The following commit will
allow the action-failed region to be charged in a different (less than
region size) ratio. As a result, the split operation could be made more
frequently in a corner case.

Still it is a theoretical corner case. But it would still be better to
be avoided unless it causes other issues, as max_nr_regions is one of
the important user parameters.

Avoid the violation and resulting overhead by merging the sliced regions
back, as soon as the schemes handling for the slices are done.

Signed-off-by: SeongJae Park <sj@xxxxxxxxxx>
---
mm/damon/core.c | 32 ++++++++++++++++++++++++++++----
1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/mm/damon/core.c b/mm/damon/core.c
index c7d05d2385fe8..98ee776d98cd0 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -2159,6 +2159,33 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
}
}

+static void damos_apply_target(struct damon_ctx *c, struct damon_target *t)
+{
+ struct damon_region *r, *next, *orig_region = NULL;
+ unsigned long orig_end_addr;
+
+ damon_for_each_region_safe(r, next, t) {
+ /*
+ * damon_do_apply_schemes() split the region if applying the
+ * action to the whole region can make quota exceeded. That
+ * split can result in DAMON snapshot having more than
+ * max_nr_regions regions.
+ *
+ * Merge back the sliced regions to the original region, as
+ * soon as the schemes-handling of the slice is completed.
+ */
+ if (!orig_region || orig_end_addr <= r->ar.start) {
+ orig_region = r;
+ orig_end_addr = r->ar.end;
+ }
+ damon_do_apply_schemes(c, t, r);
+ if (r == orig_region)
+ continue;
+ orig_region->ar.end = r->ar.end;
+ damon_destroy_region(r, t);
+ }
+}
+
/*
* damon_feed_loop_next_input() - get next input to achieve a target score.
* @last_input The last input.
@@ -2528,7 +2555,6 @@ static void damos_trace_stat(struct damon_ctx *c, struct damos *s)
static void kdamond_apply_schemes(struct damon_ctx *c)
{
struct damon_target *t;
- struct damon_region *r;
struct damos *s;
bool has_schemes_to_apply = false;

@@ -2551,9 +2577,7 @@ static void kdamond_apply_schemes(struct damon_ctx *c)
damon_for_each_target(t, c) {
if (c->ops.target_valid && c->ops.target_valid(t) == false)
continue;
-
- damon_for_each_region(r, t)
- damon_do_apply_schemes(c, t, r);
+ damos_apply_target(c, t);
}

damon_for_each_scheme(s, c) {
--
2.47.3