]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mm/damon/core: do non-safe region walk on kdamond_apply_schemes()
authorSeongJae Park <sj@kernel.org>
Fri, 27 Feb 2026 17:06:21 +0000 (09:06 -0800)
committerAndrew Morton <akpm@linux-foundation.org>
Sun, 5 Apr 2026 20:53:10 +0000 (13:53 -0700)
kdamond_apply_schemes() is using damon_for_each_region_safe(), which is
safe for deallocation of the region inside the loop.  However, the loop
internal logic does not deallocate regions.  Hence it is only wasting the
next pointer.  Also, it causes a problem.

When an address filter is applied, and there is a region that intersects
with the filter, the filter splits the region on the filter boundary.  The
intention is to let DAMOS apply action to only filtered-in address ranges.
However, it is using damon_for_each_region_safe(), which sets the next
region before the execution of the iteration.  Hence, the region that
split and now will be next to the previous region, is simply ignored.  As
a result, DAMOS applies the action to target regions bit slower than
expected, when the address filter is used.  Shouldn't be a big problem but
definitely better to be fixed.  damos_skip_charged_region() was working
around the issue using a double pointer hack.

Use damon_for_each_region(), which is safe for this use case.  And drop
the work around in damos_skip_charged_region().

Link: https://lkml.kernel.org/r/20260227170623.95384-3-sj@kernel.org
Signed-off-by: SeongJae Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/damon/core.c

index 722dcb8fff7a195dc65d17235a24eed7504244c3..a97d8799c228896ddcfb5f5375e18b2dc6015607 100644 (file)
@@ -1717,17 +1717,18 @@ static bool damos_valid_target(struct damon_ctx *c, struct damon_region *r,
  * This function checks if a given region should be skipped or not for the
  * reason.  If only the starting part of the region has previously charged,
  * this function splits the region into two so that the second one covers the
- * area that not charged in the previous charge widnow and saves the second
- * region in *rp and returns false, so that the caller can apply DAMON action
- * to the second one.
+ * area that not charged in the previous charge widnow, and return true.  The
+ * caller can see the second one on the next iteration of the region walk.
+ * Note that this means the caller should use damon_for_each_region() instead
+ * of damon_for_each_region_safe().  If damon_for_each_region_safe() is used,
+ * the second region will just be ignored.
  *
- * Return: true if the region should be entirely skipped, false otherwise.
+ * Return: true if the region should be skipped, false otherwise.
  */
 static bool damos_skip_charged_region(struct damon_target *t,
-               struct damon_region **rp, struct damos *s,
+               struct damon_region *r, struct damos *s,
                unsigned long min_region_sz)
 {
-       struct damon_region *r = *rp;
        struct damos_quota *quota = &s->quota;
        unsigned long sz_to_skip;
 
@@ -1754,8 +1755,7 @@ static bool damos_skip_charged_region(struct damon_target *t,
                                sz_to_skip = min_region_sz;
                        }
                        damon_split_region_at(t, r, sz_to_skip);
-                       r = damon_next_region(r);
-                       *rp = r;
+                       return true;
                }
                quota->charge_target_from = NULL;
                quota->charge_addr_from = 0;
@@ -2014,7 +2014,7 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
                if (quota->esz && quota->charged_sz >= quota->esz)
                        continue;
 
-               if (damos_skip_charged_region(t, &r, s, c->min_region_sz))
+               if (damos_skip_charged_region(t, r, s, c->min_region_sz))
                        continue;
 
                if (s->max_nr_snapshots &&
@@ -2357,7 +2357,7 @@ 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, *next_r;
+       struct damon_region *r;
        struct damos *s;
        unsigned long sample_interval = c->attrs.sample_interval ?
                c->attrs.sample_interval : 1;
@@ -2383,7 +2383,7 @@ static void kdamond_apply_schemes(struct damon_ctx *c)
                if (c->ops.target_valid && c->ops.target_valid(t) == false)
                        continue;
 
-               damon_for_each_region_safe(r, next_r, t)
+               damon_for_each_region(r, t)
                        damon_do_apply_schemes(c, t, r);
        }