* [RFC PATCH 01/14] mm/damon/core: safely handle no region case in damon_set_regions()
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 02/14] mm/damon/core: do not use region out of a loop " SeongJae Park
` (12 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
damon_set_regions() calls damon_first_region() regardless of the number
of DAMON regions in a given DAMON target. damon_first_region()
internally uses list_first_entry(), which clearly documents the list is
expected to be not empty. Due to the internal implementation of the
macro, damon_set_regions() is safe for now. But the internal
implementation of the macro can be changed in future. Refactor the
function to explicitly and safely handle the empty region list case
without depending on the internal implementation.
No behavioral change is intended.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/core.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 0267faf216b95..40946a7f6f549 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -356,6 +356,19 @@ int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges,
damon_destroy_region(r, t);
}
+ if (!damon_nr_regions(t)) {
+ for (i = 0; i < nr_ranges; i++) {
+ r = damon_new_region(
+ ALIGN_DOWN(ranges[i].start,
+ min_region_sz),
+ ALIGN(ranges[i].end, min_region_sz));
+ if (!r)
+ return -ENOMEM;
+ damon_add_region(r, t);
+ }
+ return 0;
+ }
+
r = damon_first_region(t);
/* Add new regions or resize existing regions to fit in the ranges */
for (i = 0; i < nr_ranges; i++) {
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH 02/14] mm/damon/core: do not use region out of a loop in damon_set_regions()
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 01/14] mm/damon/core: safely handle no region case in damon_set_regions() SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 03/14] samples/damon/mtier: replace damon_add_region() with damon_set_regions() SeongJae Park
` (11 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
damon_set_regions() assumes the DAMON region iterator is referencing the
last region after the region iteration loop is completed. The code is
indeed implemented in the way, but that is not a documented safe
behavior. Hence it is unreliable and difficult to read. Cleanup the
code to avoid the case.
No behavioral change is intended.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/core.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 40946a7f6f549..e8cf3632115e5 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -374,6 +374,7 @@ int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges,
for (i = 0; i < nr_ranges; i++) {
struct damon_region *first = NULL, *last, *newr;
struct damon_addr_range *range;
+ bool insert_before_r = false;
range = &ranges[i];
/* Get the first/last regions intersecting with the range */
@@ -383,8 +384,10 @@ int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges,
first = r;
last = r;
}
- if (r->ar.start >= range->end)
+ if (r->ar.start >= range->end) {
+ insert_before_r = true;
break;
+ }
}
if (!first) {
/* no region intersects with this range */
@@ -394,7 +397,11 @@ int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges,
ALIGN(range->end, min_region_sz));
if (!newr)
return -ENOMEM;
- damon_insert_region(newr, damon_prev_region(r), r, t);
+ if (insert_before_r)
+ damon_insert_region(newr, damon_prev_region(r),
+ r, t);
+ else
+ damon_add_region(newr, t);
} else {
/* resize intersecting regions to fit in this range */
first->ar.start = ALIGN_DOWN(range->start,
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH 03/14] samples/damon/mtier: replace damon_add_region() with damon_set_regions()
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 01/14] mm/damon/core: safely handle no region case in damon_set_regions() SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 02/14] mm/damon/core: do not use region out of a loop " SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 04/14] mm/damon/tests/vaddr-kunit: " SeongJae Park
` (10 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, damon, linux-kernel, linux-mm
mtier DAMON sample module and DAMON virtual address operation set
(vaddr) unit tests are using damon_add_region() for setup of DAMON
monitoring target region boundaries setup. But, damon_set_regions() is
designed for exactly the purpose. All other DAMON API callers use the
function for the purpose. Replace damon_add_region() usage in mtier
sample module with damon_set_regions(), for unifying the use case and
reducing the maintenance cost.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
samples/damon/mtier.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/samples/damon/mtier.c b/samples/damon/mtier.c
index 775838a23d935..eb1143de8df17 100644
--- a/samples/damon/mtier.c
+++ b/samples/damon/mtier.c
@@ -75,11 +75,11 @@ static struct damon_ctx *damon_sample_mtier_build_ctx(bool promote)
struct damon_ctx *ctx;
struct damon_attrs attrs;
struct damon_target *target;
- struct damon_region *region;
struct damos *scheme;
struct damos_quota_goal *quota_goal;
struct damos_filter *filter;
struct region_range addr;
+ struct damon_addr_range range;
int ret;
ctx = damon_new_ctx();
@@ -120,10 +120,12 @@ static struct damon_ctx *damon_sample_mtier_build_ctx(bool promote)
addr.end = promote ? node1_end_addr : node0_end_addr;
}
- region = damon_new_region(addr.start, addr.end);
- if (!region)
+ range.start = addr.start;
+ range.end = addr.end;
+
+ ret = damon_set_regions(target, &range, 1, DAMON_MIN_REGION_SZ);
+ if (ret)
goto free_out;
- damon_add_region(region, target);
scheme = damon_new_scheme(
/* access pattern */
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH 04/14] mm/damon/tests/vaddr-kunit: replace damon_add_region() with damon_set_regions()
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (2 preceding siblings ...)
2026-05-20 6:28 ` [RFC PATCH 03/14] samples/damon/mtier: replace damon_add_region() with damon_set_regions() SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 05/14] mm/damon/core: hide damon_add_region() SeongJae Park
` (9 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, Brendan Higgins, David Gow, damon,
kunit-dev, linux-kernel, linux-kselftest, linux-mm
DAMON virtual address operation set (vaddr) unit tests is using
damon_add_region() for setup of DAMON monitoring target region
boundaries setup. But, damon_set_regions() is designed for exactly the
purpose. All other DAMON API callers use the function for the purpose.
Replace damon_add_region() usage in the unit tests with
damon_set_regions(), for unifying the use case and reducing the
maintenance cost.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/tests/vaddr-kunit.h | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/mm/damon/tests/vaddr-kunit.h b/mm/damon/tests/vaddr-kunit.h
index 98e734d77d517..23be9c3be75fa 100644
--- a/mm/damon/tests/vaddr-kunit.h
+++ b/mm/damon/tests/vaddr-kunit.h
@@ -132,20 +132,24 @@ static void damon_do_test_apply_three_regions(struct kunit *test,
unsigned long *expected, int nr_expected)
{
struct damon_target *t;
+ struct damon_addr_range *ranges;
struct damon_region *r;
int i;
t = damon_new_target();
if (!t)
kunit_skip(test, "target alloc fail");
+
+ ranges = kmalloc_array(nr_regions / 2, sizeof(*ranges), GFP_KERNEL);
+ if (!ranges) {
+ damon_destroy_target(t, NULL);
+ kunit_skip(test, "ranges alloc fail");
+ }
for (i = 0; i < nr_regions / 2; i++) {
- r = damon_new_region(regions[i * 2], regions[i * 2 + 1]);
- if (!r) {
- damon_destroy_target(t, NULL);
- kunit_skip(test, "region alloc fail");
- }
- damon_add_region(r, t);
+ ranges[i].start = regions[i * 2];
+ ranges[i].end = regions[i * 2 + 1];
}
+ damon_set_regions(t, ranges, nr_regions / 2, DAMON_MIN_REGION_SZ);
damon_set_regions(t, three_regions, 3, DAMON_MIN_REGION_SZ);
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH 05/14] mm/damon/core: hide damon_add_region()
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (3 preceding siblings ...)
2026-05-20 6:28 ` [RFC PATCH 04/14] mm/damon/tests/vaddr-kunit: " SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 06/14] mm/damon/core: hide damon_insert_region() SeongJae Park
` (8 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
damon_add_region() is being used by only DAMON core, but exposed to
DAMON API callers. Exposing something that is not really being used by
others will only increase the maintenance cost. Hide it.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/linux/damon.h | 1 -
mm/damon/core.c | 2 +-
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 4014fd0d463cb..b9370c1779cba 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -1024,7 +1024,6 @@ static inline void damon_insert_region(struct damon_region *r,
t->nr_regions++;
}
-void damon_add_region(struct damon_region *r, struct damon_target *t);
void damon_destroy_region(struct damon_region *r, struct damon_target *t);
int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges,
unsigned int nr_ranges, unsigned long min_region_sz);
diff --git a/mm/damon/core.c b/mm/damon/core.c
index e8cf3632115e5..7d1de6ff54eba 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -250,7 +250,7 @@ struct damon_region *damon_new_region(unsigned long start, unsigned long end)
return region;
}
-void damon_add_region(struct damon_region *r, struct damon_target *t)
+static void damon_add_region(struct damon_region *r, struct damon_target *t)
{
list_add_tail(&r->list, &t->regions_list);
t->nr_regions++;
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH 06/14] mm/damon/core: hide damon_insert_region()
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (4 preceding siblings ...)
2026-05-20 6:28 ` [RFC PATCH 05/14] mm/damon/core: hide damon_add_region() SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 07/14] mm/damon/core: hide damon_destroy_region() SeongJae Park
` (7 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
damon_insert_region() is being used by only DAMON core, but exposed to
DAMON API callers. Exposing something that is not really being used by
others will only increase the maintenance cost. Hide it.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/linux/damon.h | 11 -----------
mm/damon/core.c | 11 +++++++++++
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index b9370c1779cba..3acca7deb1693 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -1013,17 +1013,6 @@ void damon_add_probe(struct damon_ctx *ctx, struct damon_probe *probe);
struct damon_region *damon_new_region(unsigned long start, unsigned long end);
-/*
- * Add a region between two other regions
- */
-static inline void damon_insert_region(struct damon_region *r,
- struct damon_region *prev, struct damon_region *next,
- struct damon_target *t)
-{
- __list_add(&r->list, &prev->list, &next->list);
- t->nr_regions++;
-}
-
void damon_destroy_region(struct damon_region *r, struct damon_target *t);
int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges,
unsigned int nr_ranges, unsigned long min_region_sz);
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 7d1de6ff54eba..53b4bdd27b39d 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -256,6 +256,17 @@ static void damon_add_region(struct damon_region *r, struct damon_target *t)
t->nr_regions++;
}
+/*
+ * Add a region between two other regions
+ */
+static inline void damon_insert_region(struct damon_region *r,
+ struct damon_region *prev, struct damon_region *next,
+ struct damon_target *t)
+{
+ __list_add(&r->list, &prev->list, &next->list);
+ t->nr_regions++;
+}
+
#ifdef CONFIG_DAMON_DEBUG_SANITY
static void damon_verify_del_region(struct damon_target *t)
{
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH 07/14] mm/damon/core: hide damon_destroy_region()
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (5 preceding siblings ...)
2026-05-20 6:28 ` [RFC PATCH 06/14] mm/damon/core: hide damon_insert_region() SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 08/14] mm/damon/core: add kdamond_call() debug_sanity check SeongJae Park
` (6 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
damon_destroy_region() is being used by only DAMON core, but exposed to
DAMON API callers. Exposing something that is not really being used by
others will only increase the maintenance cost. Hide it.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/linux/damon.h | 1 -
mm/damon/core.c | 3 ++-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 3acca7deb1693..638ee65f88dcb 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -1013,7 +1013,6 @@ void damon_add_probe(struct damon_ctx *ctx, struct damon_probe *probe);
struct damon_region *damon_new_region(unsigned long start, unsigned long end);
-void damon_destroy_region(struct damon_region *r, struct damon_target *t);
int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges,
unsigned int nr_ranges, unsigned long min_region_sz);
void damon_update_region_access_rate(struct damon_region *r, bool accessed,
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 53b4bdd27b39d..8a9202937781c 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -291,7 +291,8 @@ static void damon_free_region(struct damon_region *r)
kmem_cache_free(damon_region_cache, r);
}
-void damon_destroy_region(struct damon_region *r, struct damon_target *t)
+static void damon_destroy_region(struct damon_region *r,
+ struct damon_target *t)
{
damon_del_region(r, t);
damon_free_region(r);
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH 08/14] mm/damon/core: add kdamond_call() debug_sanity check
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (6 preceding siblings ...)
2026-05-20 6:28 ` [RFC PATCH 07/14] mm/damon/core: hide damon_destroy_region() SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 09/14] mm/damon/core: remove damon_verify_nr_regions() SeongJae Park
` (5 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
kdamond_call() is the place where DAMON API callers are allowed to
access the DAMON context's public internal state including the
monitoring results. Hence it is important to ensure it is called with
the expected DAMON context state. Do the check under
DAMON_DEBUG_SANITY.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/core.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 8a9202937781c..22327a23c7e57 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -3331,6 +3331,37 @@ static void kdamond_usleep(unsigned long usecs)
usleep_range_idle(usecs, usecs + 1);
}
+#ifdef CONFIG_DAMON_DEBUG_SANITY
+static void damon_verify_ctx(struct damon_ctx *c)
+{
+ struct damon_target *t;
+ struct damon_region *r;
+
+ damon_for_each_target(t, c) {
+ struct damon_region *prev_r = NULL;
+ unsigned int nr_regions = 0;
+
+ damon_for_each_region(r, t) {
+ WARN_ONCE(r->ar.start <= r->ar.end,
+ "region start (%lu) <= end (%lu)\n",
+ r->ar.start, r->ar.end);
+ WARN_ONCE(prev_r && prev_r->ar.end > r->ar.start,
+ "region overlap (%lu > %lu)\n",
+ prev_r->ar.end, r->ar.start);
+ prev_r = r;
+ nr_regions++;
+ }
+ WARN_ONCE(damon_nr_regions(t) != nr_regions,
+ "nr_regions mismatch: %u != %u\n",
+ damon_nr_regions(t), nr_regions);
+ }
+}
+#else
+static void damon_verify_ctx(struct damon_ctx *c)
+{
+}
+#endif
+
/*
* kdamond_call() - handle damon_call_control objects.
* @ctx: The &struct damon_ctx of the kdamond.
@@ -3346,6 +3377,8 @@ static void kdamond_call(struct damon_ctx *ctx, bool cancel)
struct damon_call_control *control, *next;
LIST_HEAD(controls);
+ damon_verify_ctx(ctx);
+
mutex_lock(&ctx->call_controls_lock);
list_splice_tail_init(&ctx->call_controls, &controls);
mutex_unlock(&ctx->call_controls_lock);
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH 09/14] mm/damon/core: remove damon_verify_nr_regions()
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (7 preceding siblings ...)
2026-05-20 6:28 ` [RFC PATCH 08/14] mm/damon/core: add kdamond_call() debug_sanity check SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 10/14] mm/damon/tests/core-kunit: add damon_set_regions() test cases SeongJae Park
` (4 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
When CONFIG_DAMON_DEBUG_SANITY is enabled, damon_verify_nr_regions() is
called for each damon_nr_regions() invocation. damon_veify_nr_regions()
iterates all regions. damon_nr_regions() is called for each region in
kdamond_reset_aggregated() and damos_apply_scheme(). Hence it imposes
O(n**2) overhead where n is the number of regions.
Though the verification is enabled only under DAMON_DEBUG_SANITY, which
is not for production use cases, it could be too high overhead.
Meanwhile, damon_verify_ctx() is doing the damon_nr_regions() test.
Because damon_verify_ctx() is called for each kdamond_call(), the test
coverage from damon_verify_ctx() could be sufficient. Remove
damon_nr_regions() verification.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/core.c | 19 -------------------
1 file changed, 19 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 22327a23c7e57..b2d268c4102db 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -686,27 +686,8 @@ void damon_destroy_target(struct damon_target *t, struct damon_ctx *ctx)
damon_free_target(t);
}
-#ifdef CONFIG_DAMON_DEBUG_SANITY
-static void damon_verify_nr_regions(struct damon_target *t)
-{
- struct damon_region *r;
- unsigned int count = 0;
-
- damon_for_each_region(r, t)
- count++;
- WARN_ONCE(count != t->nr_regions, "t->nr_regions (%u) != count (%u)\n",
- t->nr_regions, count);
-}
-#else
-static void damon_verify_nr_regions(struct damon_target *t)
-{
-}
-#endif
-
unsigned int damon_nr_regions(struct damon_target *t)
{
- damon_verify_nr_regions(t);
-
return t->nr_regions;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH 10/14] mm/damon/tests/core-kunit: add damon_set_regions() test cases
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (8 preceding siblings ...)
2026-05-20 6:28 ` [RFC PATCH 09/14] mm/damon/core: remove damon_verify_nr_regions() SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 11/14] selftests/damon/sysfs.py: stop kdamonds before failing SeongJae Park
` (3 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, Brendan Higgins, David Gow, damon,
kunit-dev, linux-kernel, linux-kselftest, linux-mm
damon_set_regions() is one of the main DAMON kernel API functions that
set up the monitoring target memory region boundaries. Implement unit
tests for verifying its basic functionalities.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/tests/core-kunit.h | 142 ++++++++++++++++++++++++++++++------
1 file changed, 120 insertions(+), 22 deletions(-)
diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h
index 866f716e5760d..1cfb8c176b873 100644
--- a/mm/damon/tests/core-kunit.h
+++ b/mm/damon/tests/core-kunit.h
@@ -390,41 +390,139 @@ static void damon_test_ops_registration(struct kunit *test)
}
}
-static void damon_test_set_regions(struct kunit *test)
+static void damon_test_set_regions_for(struct kunit *test,
+ struct damon_addr_range *old_ranges, int sz_old_ranges,
+ struct damon_addr_range *new_ranges, int sz_new_ranges,
+ unsigned long min_region_sz,
+ struct damon_addr_range *expect_ranges, int sz_expect_ranges)
{
- struct damon_target *t = damon_new_target();
- struct damon_region *r1, *r2;
- struct damon_addr_range range = {.start = 8, .end = 28};
- unsigned long expects[] = {8, 16, 16, 24, 24, 28};
- int expect_idx = 0;
+ struct damon_target *t;
struct damon_region *r;
+ int i;
+ t = damon_new_target();
if (!t)
kunit_skip(test, "target alloc fail");
- r1 = damon_new_region(4, 16);
- if (!r1) {
- damon_free_target(t);
- kunit_skip(test, "region alloc fail");
- }
- r2 = damon_new_region(24, 32);
- if (!r2) {
- damon_free_target(t);
- damon_free_region(r1);
- kunit_skip(test, "second region alloc fail");
+ for (i = 0; i < sz_old_ranges; i++) {
+ r = damon_new_region(old_ranges[i].start, old_ranges[i].end);
+ if (!r) {
+ damon_destroy_target(t, NULL);
+ kunit_skip(test, "%d-th r alloc fail\n", i);
+ }
+ damon_add_region(r, t);
}
- damon_add_region(r1, t);
- damon_add_region(r2, t);
- damon_set_regions(t, &range, 1, 1);
+ damon_set_regions(t, new_ranges, sz_new_ranges, min_region_sz);
- KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 3);
+ KUNIT_EXPECT_EQ(test, damon_nr_regions(t), sz_expect_ranges);
+ if (damon_nr_regions(t) != sz_expect_ranges) {
+ damon_destroy_target(t, NULL);
+ return;
+ }
+ i = 0;
damon_for_each_region(r, t) {
- KUNIT_EXPECT_EQ(test, r->ar.start, expects[expect_idx++]);
- KUNIT_EXPECT_EQ(test, r->ar.end, expects[expect_idx++]);
+ KUNIT_EXPECT_EQ(test, r->ar.start, expect_ranges[i].start);
+ KUNIT_EXPECT_EQ(test, r->ar.end, expect_ranges[i++].end);
}
+
damon_destroy_target(t, NULL);
}
+static void damon_test_set_regions(struct kunit *test)
+{
+ /* Initial build up on empty target. */
+ damon_test_set_regions_for(test,
+ (struct damon_addr_range[]){}, 0,
+ (struct damon_addr_range[]){
+ {.start = 5, .end = 15},
+ {.start = 15, .end = 25},
+ }, 2,
+ 1,
+ (struct damon_addr_range[]){
+ {.start = 5, .end = 15},
+ {.start = 15, .end = 25},
+ }, 2);
+ /* Un-intersecting regions should be removed. */
+ damon_test_set_regions_for(test,
+ (struct damon_addr_range[]){
+ {.start = 4, .end = 16},
+ {.start = 24, .end = 32},
+ }, 2,
+ (struct damon_addr_range[]){
+ {.start = 18, .end = 23},
+ }, 1,
+ 1,
+ (struct damon_addr_range[]){
+ {.start = 18, .end = 23},
+ }, 1);
+ /*
+ * Holes should be filled up with new regions.
+ *
+ * old: [4, 16) [24, 32)
+ * new: [8, 28)
+ * expect: [8, 16)[16,24),[24, 28)
+ */
+ damon_test_set_regions_for(test,
+ (struct damon_addr_range[]){
+ {.start = 4, .end = 16},
+ {.start = 24, .end = 32},
+ }, 2,
+ (struct damon_addr_range[]){
+ {.start = 8, .end = 28},
+ }, 1,
+ 1,
+ (struct damon_addr_range[]){
+ {.start = 8, .end = 16},
+ {.start = 16, .end = 24},
+ {.start = 24, .end = 28},
+ }, 3);
+ /*
+ * New regions should be able to be appended.
+ *
+ * old: [0, 4)[4, 17)
+ * new: [0, 15) [25, 40)
+ * expect: [0, 4)[4, 15) [25, 40)
+ */
+ damon_test_set_regions_for(test,
+ (struct damon_addr_range[]){
+ {.start = 0, .end = 4},
+ {.start = 4, .end = 17},
+ }, 2,
+ (struct damon_addr_range[]){
+ {.start = 0, .end = 15},
+ {.start = 25, .end = 40},
+ }, 2,
+ 1,
+ (struct damon_addr_range[]){
+ {.start = 0, .end = 4},
+ {.start = 4, .end = 15},
+ {.start = 25, .end = 40},
+ }, 3);
+ /*
+ * New regions should be able to be inserted.
+ *
+ * old: [0, 4) [42, 52)
+ * new: [0, 15) [25, 40) [44, 50)
+ * expect: [0, 15) [25, 40) [44, 50)
+ */
+ damon_test_set_regions_for(test,
+ (struct damon_addr_range[]){
+ {.start = 0, .end = 4},
+ {.start = 42, .end = 52},
+ }, 2,
+ (struct damon_addr_range[]){
+ {.start = 0, .end = 15},
+ {.start = 25, .end = 40},
+ {.start = 44, .end = 50},
+ }, 3,
+ 1,
+ (struct damon_addr_range[]){
+ {.start = 0, .end = 15},
+ {.start = 25, .end = 40},
+ {.start = 44, .end = 50},
+ }, 3);
+}
+
static void damon_test_nr_accesses_to_accesses_bp(struct kunit *test)
{
struct damon_attrs attrs = {
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH 11/14] selftests/damon/sysfs.py: stop kdamonds before failing
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (9 preceding siblings ...)
2026-05-20 6:28 ` [RFC PATCH 10/14] mm/damon/tests/core-kunit: add damon_set_regions() test cases SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 12/14] selftests/damon/sysfs.sh: test monitoring intervals goal dir SeongJae Park
` (2 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, Shuah Khan, damon, linux-kernel, linux-kselftest,
linux-mm
When an assertion is failed, sysfs.py DAMON selftest immediately exits
the test program leaving the DAMON running behind. Many of the
following tests need to start DAMON on their own. But because DAMON
that was started by sysfs.py is still running, those start attempts
fail, and the tests are failed or skipped. Update sysfs.py to stop
DAMON before exiting the test program due to the assertion failure.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
tools/testing/selftests/damon/sysfs.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tools/testing/selftests/damon/sysfs.py b/tools/testing/selftests/damon/sysfs.py
index cd4d82c852113..aa03a1187489f 100755
--- a/tools/testing/selftests/damon/sysfs.py
+++ b/tools/testing/selftests/damon/sysfs.py
@@ -24,9 +24,12 @@ def dump_damon_status_dict(pid):
except Exception as e:
return None, 'json.load fail (%s)' % e
+kdamonds = None
def fail(expectation, status):
print('unexpected %s' % expectation)
print(json.dumps(status, indent=4))
+ if kdamonds is not None:
+ kdamonds.stop()
exit(1)
def assert_true(condition, expectation, status):
@@ -248,6 +251,7 @@ def assert_ctxs_committed(kdamonds):
ctx.pause = False
def main():
+ global kdamonds
kdamonds = _damon_sysfs.Kdamonds(
[_damon_sysfs.Kdamond(
contexts=[_damon_sysfs.DamonCtx(
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH 12/14] selftests/damon/sysfs.sh: test monitoring intervals goal dir
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (10 preceding siblings ...)
2026-05-20 6:28 ` [RFC PATCH 11/14] selftests/damon/sysfs.py: stop kdamonds before failing SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 13/14] selftests/damon/sysfs.sh: test addr_unit file existence SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 14/14] selftests/damon/sysfs.sh: test pause " SeongJae Park
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, Shuah Khan, damon, linux-kernel, linux-kselftest,
linux-mm
sysfs.sh DAMON selftest is not testing monitoring intervals goal
directory. Add the test.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
tools/testing/selftests/damon/sysfs.sh | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/tools/testing/selftests/damon/sysfs.sh b/tools/testing/selftests/damon/sysfs.sh
index 1ac3e2ce8e448..b3418214ed358 100755
--- a/tools/testing/selftests/damon/sysfs.sh
+++ b/tools/testing/selftests/damon/sysfs.sh
@@ -282,6 +282,17 @@ test_targets()
ensure_dir "$targets_dir/1" "not_exist"
}
+
+test_intervals_goal()
+{
+ goal_dir=$1
+ ensure_dir "$goal_dir" "exist"
+ ensure_file "$goal_dir/access_bp" "exist" "600"
+ ensure_file "$goal_dir/aggrs" "exist" "600"
+ ensure_file "$goal_dir/min_sample_us" "exist" "600"
+ ensure_file "$goal_dir/max_sample_us" "exist" "600"
+}
+
test_intervals()
{
intervals_dir=$1
@@ -289,6 +300,7 @@ test_intervals()
ensure_file "$intervals_dir/aggr_us" "exist" "600"
ensure_file "$intervals_dir/sample_us" "exist" "600"
ensure_file "$intervals_dir/update_us" "exist" "600"
+ test_intervals_goal "$intervals_dir/intervals_goal"
}
test_damon_filter()
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH 13/14] selftests/damon/sysfs.sh: test addr_unit file existence
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (11 preceding siblings ...)
2026-05-20 6:28 ` [RFC PATCH 12/14] selftests/damon/sysfs.sh: test monitoring intervals goal dir SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
2026-05-20 6:28 ` [RFC PATCH 14/14] selftests/damon/sysfs.sh: test pause " SeongJae Park
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, Shuah Khan, damon, linux-kernel, linux-kselftest,
linux-mm
sysfs.sh DAMON selftest is not testing the existence of addr_unit sysfs
file. Add the test.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
tools/testing/selftests/damon/sysfs.sh | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/testing/selftests/damon/sysfs.sh b/tools/testing/selftests/damon/sysfs.sh
index b3418214ed358..1e10881afabb6 100755
--- a/tools/testing/selftests/damon/sysfs.sh
+++ b/tools/testing/selftests/damon/sysfs.sh
@@ -365,6 +365,7 @@ test_context()
ensure_dir "$context_dir" "exist"
ensure_file "$context_dir/avail_operations" "exit" 400
ensure_file "$context_dir/operations" "exist" 600
+ ensure_file "$context_dir/addr_unit" "exit" 600
test_monitoring_attrs "$context_dir/monitoring_attrs"
test_targets "$context_dir/targets"
test_schemes "$context_dir/schemes"
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH 14/14] selftests/damon/sysfs.sh: test pause file existence
2026-05-20 6:28 [RFC PATCH 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (12 preceding siblings ...)
2026-05-20 6:28 ` [RFC PATCH 13/14] selftests/damon/sysfs.sh: test addr_unit file existence SeongJae Park
@ 2026-05-20 6:28 ` SeongJae Park
13 siblings, 0 replies; 15+ messages in thread
From: SeongJae Park @ 2026-05-20 6:28 UTC (permalink / raw)
Cc: SeongJae Park, Shuah Khan, damon, linux-kernel, linux-kselftest,
linux-mm
sysfs.sh DAMON selftest is not testing the existence of the 'pause'
sysfs file. Add the test.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
tools/testing/selftests/damon/sysfs.sh | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/testing/selftests/damon/sysfs.sh b/tools/testing/selftests/damon/sysfs.sh
index 1e10881afabb6..ae002dd3c0797 100755
--- a/tools/testing/selftests/damon/sysfs.sh
+++ b/tools/testing/selftests/damon/sysfs.sh
@@ -366,6 +366,7 @@ test_context()
ensure_file "$context_dir/avail_operations" "exit" 400
ensure_file "$context_dir/operations" "exist" 600
ensure_file "$context_dir/addr_unit" "exit" 600
+ ensure_file "$context_dir/pause" "exit" 600
test_monitoring_attrs "$context_dir/monitoring_attrs"
test_targets "$context_dir/targets"
test_schemes "$context_dir/schemes"
--
2.47.3
^ permalink raw reply related [flat|nested] 15+ messages in thread