[RFC PATCH v3 8/9] mm/damon/core: cap the region merge threshold per target

From: Ravi Jonnalagadda

Date: Sat Oct 03 2026 - 17:11:49 EST


kdamond_merge_regions() applies one context-wide threshold, the highest
merge score across all targets divided by 10, to every target. When a
high-traffic target and a low-traffic target share a context, the
high-traffic target sets a threshold permissive enough to erase the
hot/cold boundary in the low-traffic one: a region with nr_accesses=1
next to one with nr_accesses=0 merges because 1 <= threshold, even though
that difference is the only signal the cold scheme has to admit it.

On the regular merge pass, cap the threshold for each target by a tenth of
that target's own maximum merge score. The score is the one
damon_merge_regions_of() compares, so a probe-weighted context is capped
by its weighted hit sums rather than by nr_accesses, which stays near zero
when access checks are off.

The passes that follow the regular one exist only to bring the region
count under max_nr_regions by escalating the threshold. They keep using
the escalated threshold uncapped, so that bound still holds.

Signed-off-by: Ravi Jonnalagadda <ravis.opensrc@xxxxxxxxx>
---
mm/damon/core.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/mm/damon/core.c b/mm/damon/core.c
index 1d25f820e3f9..c2c74d0daf95 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -4175,12 +4175,36 @@ static noinline_for_stack void kdamond_merge_regions(struct damon_ctx *c,
unsigned int nr_regions;
unsigned int max_thres;
bool count_age = true;
+ bool use_probe_hits = damon_has_probe_weights(c);

max_thres = damon_nr_samples_per_aggr(&c->attrs);
while (true) {
nr_regions = 0;
damon_for_each_target(t, c) {
- damon_merge_regions_of(t, threshold, sz_limit, c,
+ struct damon_region *r;
+ unsigned int t_max = 0, t_thres = threshold;
+
+ /*
+ * On the regular pass, cap the threshold by this
+ * target's own maximum merge score. A high-traffic
+ * target in the same context must not set a threshold so
+ * permissive that a low-traffic target's hot/cold
+ * boundary merges away before the cold scheme can act on
+ * it. The score is the one damon_merge_regions_of()
+ * compares, so probe-weighted contexts are capped by
+ * their weighted hit sums rather than by nr_accesses.
+ *
+ * The passes that follow exist only to bring the region
+ * count under max_nr_regions, so they use the escalated
+ * threshold as is.
+ */
+ if (count_age) {
+ damon_for_each_region(r, t)
+ t_max = max(t_max, damon_merge_score(r,
+ false, c, use_probe_hits));
+ t_thres = min(threshold, t_max / 10);
+ }
+ damon_merge_regions_of(t, t_thres, sz_limit, c,
count_age);
nr_regions += damon_nr_regions(t);
}

--
Git-157)