* [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests
@ 2026-05-21 14:34 SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 01/14] mm/damon/core: safely handle no region case in damon_set_regions() SeongJae Park
` (13 more replies)
0 siblings, 14 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, Brendan Higgins, David Gow,
Shuah Khan, damon, kunit-dev, linux-kernel, linux-kselftest,
linux-mm
Implement minor improvements on code readability and tests for DAMON.
First seven patches are for DAMON code readability and resulting
maintenance. Patches 1 and 2 make damon_set_regions() safer and easier
to read. Patches 3 and 4 remove fragmented DAMON API use cases. Patches
5-7 hides unused core functions that are unnecessarily exposed to API
callers.
The following seven patches are for DAMON tests improvement. Patches 8
and 9 adds and removes DAMON_DEBUG_SANITY verifications to ensure
reasonable test coverage without too high overhead. Patch 10 adds a new
kunit test for damon_set_regions(). Patch 11 makes sysfs.py selftest
more gracefully finishes under test failures. Patches 12-13 adds simple
sysfs.sh test cases for the monitoring intervals goal directory, the
addr_unit file and the pause file.
Changes from RFC v1.1
- RFC v1.1: https://lore.kernel.org/20260521035349.87565-1-sj@kernel.org
- Free DAMON target in vaddr unit test fail-out path.
Changes from RFC v1
- RFC v1: https://lore.kernel.org/20260520062858.167011-1-sj@kernel.org
- Handle damon_set_regions() failure in vaddr unit test.
- Free ranges array in vaddr unit test.
- Fix wrong region address verification.
- Fix typos in selftest: s/exit/exist/
SeongJae Park (14):
mm/damon/core: safely handle no region case in damon_set_regions()
mm/damon/core: do not use region out of a loop in damon_set_regions()
samples/damon/mtier: replace damon_add_region() with
damon_set_regions()
mm/damon/tests/vaddr-kunit: replace damon_add_region() with
damon_set_regions()
mm/damon/core: hide damon_add_region()
mm/damon/core: hide damon_insert_region()
mm/damon/core: hide damon_destroy_region()
mm/damon/core: add kdamond_call() debug_sanity check
mm/damon/core: remove damon_verify_nr_regions()
mm/damon/tests/core-kunit: add damon_set_regions() test cases
selftests/damon/sysfs.py: stop kdamonds before failing
selftests/damon/sysfs.sh: test monitoring intervals goal dir
selftests/damon/sysfs.sh: test addr_unit file existence
selftests/damon/sysfs.sh: test pause file existence
include/linux/damon.h | 13 ---
mm/damon/core.c | 92 ++++++++++++----
mm/damon/tests/core-kunit.h | 142 +++++++++++++++++++++----
mm/damon/tests/vaddr-kunit.h | 27 +++--
samples/damon/mtier.c | 10 +-
tools/testing/selftests/damon/sysfs.py | 4 +
tools/testing/selftests/damon/sysfs.sh | 14 +++
7 files changed, 233 insertions(+), 69 deletions(-)
base-commit: ac6b83c7bf3671e8ff0d541cf03e6eaeed00a79e
--
2.47.3
^ permalink raw reply [flat|nested] 18+ messages in thread
* [RFC PATCH v1.2 01/14] mm/damon/core: safely handle no region case in damon_set_regions()
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
2026-05-21 15:19 ` sashiko-bot
2026-05-21 14:34 ` [RFC PATCH v1.2 02/14] mm/damon/core: do not use region out of a loop " SeongJae Park
` (12 subsequent siblings)
13 siblings, 1 reply; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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] 18+ messages in thread
* [RFC PATCH v1.2 02/14] mm/damon/core: do not use region out of a loop in damon_set_regions()
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 01/14] mm/damon/core: safely handle no region case in damon_set_regions() SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 03/14] samples/damon/mtier: replace damon_add_region() with damon_set_regions() SeongJae Park
` (11 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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] 18+ messages in thread
* [RFC PATCH v1.2 03/14] samples/damon/mtier: replace damon_add_region() with damon_set_regions()
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 01/14] mm/damon/core: safely handle no region case in damon_set_regions() SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 02/14] mm/damon/core: do not use region out of a loop " SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 04/14] mm/damon/tests/vaddr-kunit: " SeongJae Park
` (10 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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] 18+ messages in thread
* [RFC PATCH v1.2 04/14] mm/damon/tests/vaddr-kunit: replace damon_add_region() with damon_set_regions()
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (2 preceding siblings ...)
2026-05-21 14:34 ` [RFC PATCH v1.2 03/14] samples/damon/mtier: replace damon_add_region() with damon_set_regions() SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 05/14] mm/damon/core: hide damon_add_region() SeongJae Park
` (9 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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 | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/mm/damon/tests/vaddr-kunit.h b/mm/damon/tests/vaddr-kunit.h
index 98e734d77d517..563fbc7e3f448 100644
--- a/mm/damon/tests/vaddr-kunit.h
+++ b/mm/damon/tests/vaddr-kunit.h
@@ -132,22 +132,35 @@ 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];
}
+ if (damon_set_regions(t, ranges, nr_regions / 2,
+ DAMON_MIN_REGION_SZ)) {
+ kfree(ranges);
+ damon_destroy_target(t, NULL);
+ kunit_skip(test, "damon_set_regions() fail");
+ }
+ kfree(ranges);
- damon_set_regions(t, three_regions, 3, DAMON_MIN_REGION_SZ);
+ if (damon_set_regions(t, three_regions, 3, DAMON_MIN_REGION_SZ)) {
+ damon_destroy_target(t, NULL);
+ kunit_skip(test, "second damon_set_regions() fail");
+ }
for (i = 0; i < nr_expected / 2; i++) {
r = __nth_region_of(t, i);
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [RFC PATCH v1.2 05/14] mm/damon/core: hide damon_add_region()
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (3 preceding siblings ...)
2026-05-21 14:34 ` [RFC PATCH v1.2 04/14] mm/damon/tests/vaddr-kunit: " SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 06/14] mm/damon/core: hide damon_insert_region() SeongJae Park
` (8 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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] 18+ messages in thread
* [RFC PATCH v1.2 06/14] mm/damon/core: hide damon_insert_region()
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (4 preceding siblings ...)
2026-05-21 14:34 ` [RFC PATCH v1.2 05/14] mm/damon/core: hide damon_add_region() SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 07/14] mm/damon/core: hide damon_destroy_region() SeongJae Park
` (7 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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] 18+ messages in thread
* [RFC PATCH v1.2 07/14] mm/damon/core: hide damon_destroy_region()
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (5 preceding siblings ...)
2026-05-21 14:34 ` [RFC PATCH v1.2 06/14] mm/damon/core: hide damon_insert_region() SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 08/14] mm/damon/core: add kdamond_call() debug_sanity check SeongJae Park
` (6 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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] 18+ messages in thread
* [RFC PATCH v1.2 08/14] mm/damon/core: add kdamond_call() debug_sanity check
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (6 preceding siblings ...)
2026-05-21 14:34 ` [RFC PATCH v1.2 07/14] mm/damon/core: hide damon_destroy_region() SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 09/14] mm/damon/core: remove damon_verify_nr_regions() SeongJae Park
` (5 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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..9cde5b47b9585 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] 18+ messages in thread
* [RFC PATCH v1.2 09/14] mm/damon/core: remove damon_verify_nr_regions()
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (7 preceding siblings ...)
2026-05-21 14:34 ` [RFC PATCH v1.2 08/14] mm/damon/core: add kdamond_call() debug_sanity check SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 10/14] mm/damon/tests/core-kunit: add damon_set_regions() test cases SeongJae Park
` (4 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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 9cde5b47b9585..265d51ade25bf 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] 18+ messages in thread
* [RFC PATCH v1.2 10/14] mm/damon/tests/core-kunit: add damon_set_regions() test cases
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (8 preceding siblings ...)
2026-05-21 14:34 ` [RFC PATCH v1.2 09/14] mm/damon/core: remove damon_verify_nr_regions() SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 11/14] selftests/damon/sysfs.py: stop kdamonds before failing SeongJae Park
` (3 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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] 18+ messages in thread
* [RFC PATCH v1.2 11/14] selftests/damon/sysfs.py: stop kdamonds before failing
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (9 preceding siblings ...)
2026-05-21 14:34 ` [RFC PATCH v1.2 10/14] mm/damon/tests/core-kunit: add damon_set_regions() test cases SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 12/14] selftests/damon/sysfs.sh: test monitoring intervals goal dir SeongJae Park
` (2 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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] 18+ messages in thread
* [RFC PATCH v1.2 12/14] selftests/damon/sysfs.sh: test monitoring intervals goal dir
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (10 preceding siblings ...)
2026-05-21 14:34 ` [RFC PATCH v1.2 11/14] selftests/damon/sysfs.py: stop kdamonds before failing SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 13/14] selftests/damon/sysfs.sh: test addr_unit file existence SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 14/14] selftests/damon/sysfs.sh: test pause " SeongJae Park
13 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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] 18+ messages in thread
* [RFC PATCH v1.2 13/14] selftests/damon/sysfs.sh: test addr_unit file existence
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (11 preceding siblings ...)
2026-05-21 14:34 ` [RFC PATCH v1.2 12/14] selftests/damon/sysfs.sh: test monitoring intervals goal dir SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 14/14] selftests/damon/sysfs.sh: test pause " SeongJae Park
13 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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..92b44c86818af 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" "exist" 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] 18+ messages in thread
* [RFC PATCH v1.2 14/14] selftests/damon/sysfs.sh: test pause file existence
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
` (12 preceding siblings ...)
2026-05-21 14:34 ` [RFC PATCH v1.2 13/14] selftests/damon/sysfs.sh: test addr_unit file existence SeongJae Park
@ 2026-05-21 14:34 ` SeongJae Park
13 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-05-21 14:34 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 92b44c86818af..78f4badb5bebb 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" "exist" 600
+ ensure_file "$context_dir/pause" "exist" 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] 18+ messages in thread
* Re: [RFC PATCH v1.2 01/14] mm/damon/core: safely handle no region case in damon_set_regions()
2026-05-21 14:34 ` [RFC PATCH v1.2 01/14] mm/damon/core: safely handle no region case in damon_set_regions() SeongJae Park
@ 2026-05-21 15:19 ` sashiko-bot
2026-05-22 2:16 ` SeongJae Park
0 siblings, 1 reply; 18+ messages in thread
From: sashiko-bot @ 2026-05-21 15:19 UTC (permalink / raw)
To: SeongJae Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Pre-existing issues:
- [Critical] The ALIGN() macro can overflow when processing malicious or overly large user-provided region 'end' values, creating invalid regions where start > end.
- [High] min_region_sz can be a non-power-of-2 value, which corrupts region boundary calculations when passed to ALIGN() and ALIGN_DOWN().
- [High] Userspace can maliciously trigger a kernel warning (WARN_ONCE) by providing a region where start == end via sysfs.
- [High] A memory allocation failure during region creation results in a partial state update without a rollback, potentially leaving the running DAMON context corrupted.
--
commit fa588352eaf7b151171cca8c2acb0bb710a71c75
Author: SeongJae Park <sj@kernel.org>
mm/damon/core: safely handle no region case in damon_set_regions()
This commit refactors damon_set_regions() to explicitly handle the empty
region list case without depending on the internal implementation of
list_first_entry().
> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index 4e223857a0f99..d0bdf6e01dff8 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),
[Severity: High]
This is a pre-existing issue, but can min_region_sz be a non-power-of-2
value here?
If sys_ctx->addr_unit is set to an arbitrary value via sysfs, min_region_sz
might not be a power of 2. The ALIGN() and ALIGN_DOWN() macros internally
perform bitwise AND operations with ~(a - 1), which assumes the alignment
is a power of 2.
Could passing a non-power-of-2 value truncate arbitrary bits and result in
misaligned boundaries where start > end?
> + ALIGN(ranges[i].end, min_region_sz));
[Severity: Critical]
This is a pre-existing issue, but can ALIGN() overflow when processing
overly large end values?
If a user passes ULONG_MAX as the region end via sysfs, ALIGN(ULONG_MAX,
4096) will overflow and wrap around to 0.
Would this result in damon_new_region(start, 0) being called, creating an
invalid region where start > end, which could underflow the size and cause
out-of-bounds memory accesses?
[Severity: High]
This isn't a bug introduced by this patch, but what happens if userspace
provides a region where start == end?
The sysfs interface end_store accepts arbitrary values, and if start == end,
both bypass the start > end validation check. Since ALIGN_DOWN() and ALIGN()
return identical values for identical inputs, would damon_new_region() be
invoked with equal start and end arguments, allowing an attacker with sysfs
access to maliciously trigger a WARN_ONCE(start >= end)?
> + if (!r)
> + return -ENOMEM;
[Severity: High]
This is a pre-existing issue, but does this allocation failure leave the
DAMON context in a corrupted state?
If damon_new_region() returns NULL due to memory pressure, the function
immediately returns -ENOMEM without rolling back the regions that were
already removed or added in the previous loop.
Could this leave the running kdamond thread with a partially modified list
of regions?
> + damon_add_region(r, t);
> + }
> + return 0;
> + }
> +
> r = damon_first_region(t);
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260521143428.83157-1-sj@kernel.org?part=1
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [RFC PATCH v1.2 01/14] mm/damon/core: safely handle no region case in damon_set_regions()
2026-05-21 15:19 ` sashiko-bot
@ 2026-05-22 2:16 ` SeongJae Park
2026-06-11 5:01 ` SeongJae Park
0 siblings, 1 reply; 18+ messages in thread
From: SeongJae Park @ 2026-05-22 2:16 UTC (permalink / raw)
To: sashiko-bot; +Cc: SeongJae Park, damon
On Thu, 21 May 2026 15:19:28 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
>
> Pre-existing issues:
> - [Critical] The ALIGN() macro can overflow when processing malicious or overly large user-provided region 'end' values, creating invalid regions where start > end.
> - [High] min_region_sz can be a non-power-of-2 value, which corrupts region boundary calculations when passed to ALIGN() and ALIGN_DOWN().
> - [High] Userspace can maliciously trigger a kernel warning (WARN_ONCE) by providing a region where start == end via sysfs.
> - [High] A memory allocation failure during region creation results in a partial state update without a rollback, potentially leaving the running DAMON context corrupted.
No one is caused by this patch, so no blocker for this patch.
The last finding seems worthy to separately work for. I will work on it.
Please read below for more details.
> --
>
> commit fa588352eaf7b151171cca8c2acb0bb710a71c75
> Author: SeongJae Park <sj@kernel.org>
>
> mm/damon/core: safely handle no region case in damon_set_regions()
>
> This commit refactors damon_set_regions() to explicitly handle the empty
> region list case without depending on the internal implementation of
> list_first_entry().
>
> > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > index 4e223857a0f99..d0bdf6e01dff8 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),
>
> [Severity: High]
> This is a pre-existing issue, but can min_region_sz be a non-power-of-2
> value here?
>
> If sys_ctx->addr_unit is set to an arbitrary value via sysfs, min_region_sz
> might not be a power of 2. The ALIGN() and ALIGN_DOWN() macros internally
> perform bitwise AND operations with ~(a - 1), which assumes the alignment
> is a power of 2.
>
> Could passing a non-power-of-2 value truncate arbitrary bits and result in
> misaligned boundaries where start > end?
DAMON_SYSFS enforces the power of 2 using damon_commit_ctx() based parameter
validation. DAMON_RECLAIM and DAMON_LRU_SORT also do the checks in their
..._apply_parameters() functions. So this cannot happen.
>
> > + ALIGN(ranges[i].end, min_region_sz));
>
> [Severity: Critical]
> This is a pre-existing issue, but can ALIGN() overflow when processing
> overly large end values?
>
> If a user passes ULONG_MAX as the region end via sysfs, ALIGN(ULONG_MAX,
> 4096) will overflow and wrap around to 0.
>
> Would this result in damon_new_region(start, 0) being called, creating an
> invalid region where start > end, which could underflow the size and cause
> out-of-bounds memory accesses?
As I previously answered [1], that input is unlikely in real use case.
>
> [Severity: High]
> This isn't a bug introduced by this patch, but what happens if userspace
> provides a region where start == end?
>
> The sysfs interface end_store accepts arbitrary values, and if start == end,
> both bypass the start > end validation check. Since ALIGN_DOWN() and ALIGN()
> return identical values for identical inputs, would damon_new_region() be
> invoked with equal start and end arguments, allowing an attacker with sysfs
> access to maliciously trigger a WARN_ONCE(start >= end)?
Again, unlikely input in real use case. To intentionally to this, the user
need sysfs write permission. If a malicious user got the permission, I think
they can do anything bad?
>
> > + if (!r)
> > + return -ENOMEM;
>
> [Severity: High]
> This is a pre-existing issue, but does this allocation failure leave the
> DAMON context in a corrupted state?
>
> If damon_new_region() returns NULL due to memory pressure, the function
> immediately returns -ENOMEM without rolling back the regions that were
> already removed or added in the previous loop.
>
> Could this leave the running kdamond thread with a partially modified list
> of regions?
Yes, and the caller should do damon_destroy_ctx() of the ctx. And DAMON_SYSFS
does that, while vaddr doesn't. I will work on this.
[1] https://lore.kernel.org/20260521060523.80684-1-sj@kernel.org
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [RFC PATCH v1.2 01/14] mm/damon/core: safely handle no region case in damon_set_regions()
2026-05-22 2:16 ` SeongJae Park
@ 2026-06-11 5:01 ` SeongJae Park
0 siblings, 0 replies; 18+ messages in thread
From: SeongJae Park @ 2026-06-11 5:01 UTC (permalink / raw)
To: SeongJae Park; +Cc: sashiko-bot, damon
On Thu, 21 May 2026 19:16:42 -0700 SeongJae Park <sj@kernel.org> wrote:
> On Thu, 21 May 2026 15:19:28 +0000 sashiko-bot@kernel.org wrote:
>
> > Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
> >
> > Pre-existing issues:
> > - [Critical] The ALIGN() macro can overflow when processing malicious or overly large user-provided region 'end' values, creating invalid regions where start > end.
> > - [High] min_region_sz can be a non-power-of-2 value, which corrupts region boundary calculations when passed to ALIGN() and ALIGN_DOWN().
> > - [High] Userspace can maliciously trigger a kernel warning (WARN_ONCE) by providing a region where start == end via sysfs.
> > - [High] A memory allocation failure during region creation results in a partial state update without a rollback, potentially leaving the running DAMON context corrupted.
>
> No one is caused by this patch, so no blocker for this patch.
>
> The last finding seems worthy to separately work for. I will work on it.
>
> Please read below for more details.
>
> > --
> >
> > commit fa588352eaf7b151171cca8c2acb0bb710a71c75
> > Author: SeongJae Park <sj@kernel.org>
> >
> > mm/damon/core: safely handle no region case in damon_set_regions()
> >
> > This commit refactors damon_set_regions() to explicitly handle the empty
> > region list case without depending on the internal implementation of
> > list_first_entry().
> >
> > > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > > index 4e223857a0f99..d0bdf6e01dff8 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,
[...]
> > > + if (!r)
> > > + return -ENOMEM;
> >
> > [Severity: High]
> > This is a pre-existing issue, but does this allocation failure leave the
> > DAMON context in a corrupted state?
> >
> > If damon_new_region() returns NULL due to memory pressure, the function
> > immediately returns -ENOMEM without rolling back the regions that were
> > already removed or added in the previous loop.
> >
> > Could this leave the running kdamond thread with a partially modified list
> > of regions?
>
> Yes, and the caller should do damon_destroy_ctx() of the ctx. And DAMON_SYSFS
> does that, while vaddr doesn't. I will work on this.
Hmm, but the vaddr's damon_set_regions() calls are only for the automated
mapping detection based monitoring target address rangs setup. In the mode,
the monitoring target address ranges setup is only the best effort, and
continuously retried for every operation set update interval. Hence, ignoring
the error is actually intentional and fine. So this is not a real issue and
therefore no fix is needed.
Let me know if I'm missing something, though.
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-06-11 5:01 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-21 14:34 [RFC PATCH v1.2 00/14] mm/damon: minor improvements for code readability and tests SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 01/14] mm/damon/core: safely handle no region case in damon_set_regions() SeongJae Park
2026-05-21 15:19 ` sashiko-bot
2026-05-22 2:16 ` SeongJae Park
2026-06-11 5:01 ` SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 02/14] mm/damon/core: do not use region out of a loop " SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 03/14] samples/damon/mtier: replace damon_add_region() with damon_set_regions() SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 04/14] mm/damon/tests/vaddr-kunit: " SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 05/14] mm/damon/core: hide damon_add_region() SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 06/14] mm/damon/core: hide damon_insert_region() SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 07/14] mm/damon/core: hide damon_destroy_region() SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 08/14] mm/damon/core: add kdamond_call() debug_sanity check SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 09/14] mm/damon/core: remove damon_verify_nr_regions() SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 10/14] mm/damon/tests/core-kunit: add damon_set_regions() test cases SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 11/14] selftests/damon/sysfs.py: stop kdamonds before failing SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 12/14] selftests/damon/sysfs.sh: test monitoring intervals goal dir SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 13/14] selftests/damon/sysfs.sh: test addr_unit file existence SeongJae Park
2026-05-21 14:34 ` [RFC PATCH v1.2 14/14] selftests/damon/sysfs.sh: test pause " SeongJae Park
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.