Re: [RFC PATCH] mm/damon: introduce damos_sort_type for re-ordering regions list

Liew Rui Yan <[email protected]> Tue, 4 Aug 2026 20:05:38 +0800
Newsgroups dev.linux.lists.sashiko-reviews,dev.linux.lists.damon
Message-ID <[email protected]>
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
> - [High] Broken `stat.nr_snapshots` tracking in `damos_apply_sorted_scheme()` bypasses `max_nr_snapshots` limit enforcement.
> - [High] Sorted schemes are evaluated out of order, violating DAMON's strict scheme priority semantics.
> - [Medium] Silent disabling of schemes when `get_scheme_score` is not supported by the underlying operation set.
> --
> 
> --- Patch [1]: [RFC PATCH] mm/damon: introduce damos_sort_type for re-ordering regions list ---
> commit 2f127c3d13c04b9a2b95946211fee29deac96c0d
> Author: Liew Rui Yan <[email protected]>
> Subject: mm/damon: introduce damos_sort_type for re-ordering regions list
> 
> This patch adds a per-scheme sysfs attribute schemes/<N>/sort_type to allow a
> scheme to apply actions to target regions in descending order of their
> ops.get_scheme_score() values.
> 
> > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > index 644daf5a16560..b0c52c9eabe82 100644
> > --- a/mm/damon/core.c
> > +++ b/mm/damon/core.c
> 
> [ ... ]
> 
> > @@ -2673,6 +2684,107 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
> >  	}
> >  }
> >  
> > +struct damos_sort_priv {
> > +	struct damon_ctx *c;
> > +	struct damos *s;
> > +};
> > +
> > +static int damos_sort_score_desc_cmp(const void *a, const void *b,
> > +		const void *priv)
> > +{
> 
> [ ... ]
> 
> > +}
> > +
> > +static void damos_apply_sorted_scheme(struct damon_ctx *c,
> > +		struct damon_target *t, struct damos *s)
> > +{
> > +	struct damon_region **arr;
> > +	struct damon_region *r;
> > +	struct damos_quota *quota = &s->quota;
> > +	struct damos_sort_priv priv = { .c = c, .s = s };
> > +	unsigned long nr = 0, i = 0;
> > +
> > +	if (!c->ops.get_scheme_score)
> > +		return;
> 
> [Severity: Medium]
> When the operations set does not implement get_scheme_score, does this early
> return silently disable the scheme and prevent stat.nr_snapshots from ever
> incrementing?

You are correct. The original DAMON implementation still increments
s->stat.nr_snapshots even if damos_valid_target() returns false.

I will fix this missing behavior in the next revision.

> 
> The unsorted path gracefully handles a missing score callback by falling back
> to basic filtering without the score.
> 
> > +	/* Avoid unnecessary kvmalloc_array() */
> > +	if (damos_quota_is_full(quota, c->min_region_sz))
> > +		return;
> > +
> > +	damon_for_each_region(r, t) {
> > +		if (__damos_valid_target(r, s, c))
> > +			nr++;
> > +	}
> > +	if (nr == 0)
> > +		return;
> 
> [Severity: High]
> If there are no valid regions (nr == 0), this returns early without
> incrementing s->stat.nr_snapshots. Does this prevent the scheme from ever
> reaching max_nr_snapshots and automatically deactivating?

I am somewhat uncertain about the exact semantics of nr_snapshots.

The documentation defines it as:

    "Total number of DAMON snapshots that the scheme is tried to be
    applied."

But during damon_do_apply_schemes(), nr_snapshots does not increment
unless the scheme meets the aforementioned guard conditions, regardless
of how many times it has been attempted before.

> 
> > +	if (nr == 1)
> > +		goto single_valid_region;
> > +
> > +	arr = kvmalloc_array(nr, sizeof(*arr), GFP_KERNEL);
> > +
> > +	if (!arr)
> > +		return;
> > +
> > +	damon_for_each_region(r, t) {
> > +		if (__damos_valid_target(r, s, c))
> > +			arr[i++] = r;
> > +	}
> > +
> > +	sort_r_nonatomic(arr, nr, sizeof(*arr), damos_sort_score_desc_cmp, NULL, &priv);
> > +
> > +	for (i = 0; i < nr; i++) {
> > +		r = arr[i];
> > +
> > +		/* Check the quota */
> > +		if (damos_quota_is_full(quota, c->min_region_sz))
> > +			break;
> > +
> > +		if (s->max_nr_snapshots &&
> > +				s->max_nr_snapshots <= s->stat.nr_snapshots)
> > +			continue;
> > +
> > +		if (damos_valid_target(c, r, s)) {
> > +			damos_apply_scheme(c, t, r, s);
> > +		} else {
> > +			/*
> > +			 * There is no need to continue because the score is
> > +			 * already lower than quota.min_score.
> > +			 */
> > +			break;
> 
> [Severity: High]
> If a region fails damos_valid_target() due to low quota scores, this breaks
> out of the loop and skips the (i == nr - 1) check below. Does this omit
> tracking the snapshot and prevent the scheme from deactivating?

Yes. Same as the previous answers regarding nr_snapshots.

> 
> > +		}
> > +
> > +		if (i == nr - 1)
> > +			s->stat.nr_snapshots++;
> > +	}
> > +
> > +	kvfree(arr);
> > +	return;
> > +
> > +single_valid_region:
> > +	damon_for_each_region(r, t) {
> > +		if (__damos_valid_target(r, s, c))
> > +			break;
> > +	}
> > +
> > +	/* Check the quota */
> > +	if (damos_quota_is_full(quota, c->min_region_sz))
> > +		return;
> 
> [Severity: High]
> If the quota is full in this single_valid_region fast-path, it returns early.
> Does this also bypass incrementing s->stat.nr_snapshots?

Yes. Same as the previous answers regarding nr_snapshots.

> 
> > +
> > +	if (s->max_nr_snapshots &&
> > +			s->max_nr_snapshots <= s->stat.nr_snapshots)
> > +		return;
> > +
> > +	if (damos_valid_target(c, r, s))
> > +		damos_apply_scheme(c, t, r, s);
> > +
> > +	s->stat.nr_snapshots++;
> > +}
> > +
> >  /*
> >   * damos_apply_target() - Apply DAMOS schemes to a given target.
> >   * @c:			monitoring context to apply its DAMOS schemes to..
> > @@ -2695,6 +2807,17 @@ static void damos_apply_target(struct damon_ctx *c, struct damon_target *t,
> >  		unsigned long max_region_sz)
> >  {
> >  	struct damon_region *r;
> > +	struct damos *s;
> > +
> > +	damon_for_each_scheme(s, c) {
> > +		if (s->sort_type == DAMOS_SORT_NONE)
> > +			continue;
> > +		if (!s->wmarks.activated)
> > +			continue;
> > +		if (time_before(c->passed_sample_intervals, s->next_apply_sis))
> > +			continue;
> > +		damos_apply_sorted_scheme(c, t, s);
> > +	}
> >  
> >  	damon_for_each_region(r, t) {
> >  		struct damon_region *prev_r;
> >  
> >  		damon_do_apply_schemes(c, t, r);
> 
> [Severity: High]
> By iterating and applying all sorted schemes first, and then iterating to
> apply unsorted schemes via damon_do_apply_schemes(), are we executing sorted
> schemes out of order?
> 
> DAMON evaluates schemes in the order they are defined. If a user defines an
> unsorted scheme before a sorted scheme, this two-pass execution will cause
> the sorted scheme to evaluate the regions first, breaking the execution
> order priority.

Good catch! This is indeed a bug. I will fix this in the next revision
to ensure that the scheme evaluation order strictly same as the original
one.

> 
> -- 
> Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=1

Best regards,
Rui Yan