* [PATCH 00/19] mm/damon: introduce data attributes only monitoring
@ 2026-07-10 13:46 SJ Park
2026-07-10 13:46 ` [PATCH 01/19] mm/damon/core: introduce damon_probe->weight SJ Park
` (19 more replies)
0 siblings, 20 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton
Cc: SJ Park, Liam R. Howlett, David Hildenbrand, Jonathan Corbet,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka, damon, linux-doc,
linux-kernel, linux-mm
TL;DR: Introduce a way to get DAMON's best effort accuracy monitoring of
user-demanding non-access data attributes.
Background
==========
DAMON was initially designed for only access monitoring. It turned out
users want to get the information together with more data attributes.
For example, some users want to know how much of a hot memory region
belongs to huge pages or specific cgroups. Page level properties based
monitoring was introduced with commit 626ffabe67c2 ("mm/damon: clarify
trying vs applying on damos_stat kernel-doc comment") to fill the gap.
Because it works only at snapshot level and snapshot capturing in the
mode can induce high overhead, commit 45c49d9fd608 ("mm/damon/core:
introduce struct damon_probe") introduced data attributes monitoring.
Data attributes monitoring treats the attributes as only additional and
subordinate information. Data access monitoring is always turned on,
and regions are adjusted for best accuracy of the access information. In
some cases, users may be primarily interested in the attributes more
than the access. They might even not care about the access information
at all. Because DAMON treats data accesses as the only primary
information, such users cannot get high quality attributes information.
Design and Implementation
=========================
Introduce another way for treating data attributes as the primary
information. Add 'weight' property to each data attribute probe. When
any of the weights are set, the mode is enabled. Data access monitoring
is completely turned off in the mode. For region adjustment, the
weighted sum of probe hit counters is used instead of the nr_accesses.
Using the weights, users can specify to what attributes they are
interested in to what degree. DAMON will adjust the regions and provide
the best-effort quality monitoring that is optimized for the user
demands.
Extend damon_operations for efficient use of probe hits. Update regions
merge and kdamond main logic to support the new mode. Add a new struct
field and a sysfs file for API callers and ABI users, respectively.
Test
====
On ~7 GiB memory idle system, run a simple AI-assisted program. The
program allocates and faults 2 GiB anonymous pages. Then, it does
nothing but wait until the user terminates it. Hence, the system ~2 GiB
of anonymous pages with no active accesses.
Monitor the distribution of the anonymous pages using DAMON attributes
monitoring mode, using DAMON user-space tool, damo [1].
$ sudo ./damo start --probe_filter allow anon
$ sudo ./damo report access --dont_merge_regions
heatmap: 00000000000000000000000000000000000000000000000399999995111111146666666666666666
# min/max temperatures: -2,470,000,000, -1,620,000,000, column size: 99.800 MiB
intervals: sample 5 ms aggr 100 ms (max access hz 200)
# <start> <size> <freq> <age> <probe hits>
0 4.000 KiB 79.840 MiB 0 hz 24.700 s 2
1 79.844 MiB 718.562 MiB 0 hz 24.700 s 8
2 798.406 MiB 793.148 MiB 0 hz 24.700 s 7
3 1.554 GiB 797.828 MiB 0 hz 24.700 s 7
4 2.333 GiB 794.668 MiB 0 hz 24.600 s 8
5 3.109 GiB 791.117 MiB 0 hz 24.500 s 0
6 3.882 GiB 785.312 MiB 0 hz 24 s 2
7 4.649 GiB 787.867 MiB 0 hz 16.200 s 6
8 5.418 GiB 784.477 MiB 0 hz 23.300 s 6
9 6.184 GiB 783.820 MiB 0 hz 18.200 s 9
10 6.950 GiB 797.730 MiB 0 hz 18.900 s 7
11 7.729 GiB 69.625 MiB 0 hz 18.900 s 0
memory bw estimate: 0 B per second
total size: 7.797 GiB
record DAMON intervals: sample 5 ms, aggr 100 ms
Note that the line after the line starting with "intervals:" is not
provided by the current version of 'damo'. I manually added the legends
line for easier understanding of these results.
Each of the 12 lines after the legend line shows the DAMON-found
regions. Each line shows 1) index of the region, 2) start address of
the region, 3) size of the region, 4) access frequency of the region, 5)
age (how long the access frequency on the region was kept) of the
region, and finally 6) the probe hit count.
Because data access is the primary information that adjusts region for,
and there is only nearly zero access on the system, regions are naively
adjusted with the same size. Still <probe hits> show different
distribution of the anonymous pages, but it is obviously very rough
information.
Switch to the attributes only mode and show how it changes the picture:
$ sudo ./damo tune --probe_filter allow anon --probe_weight 100
$ sudo ./damo report access --dont_merge_regions
heatmap: 88888888888888888889888999999889999999000004888888888888889999988888898888888888
# min/max temperatures: -4,430,000,000, 0, column size: 99.800 MiB
intervals: sample 5 ms aggr 100 ms (max access hz 200)
# <start> <size> <freq> <age> <probe hits>
0 4.000 KiB 60.445 MiB 0 hz 700 ms 0
1 60.449 MiB 1.363 MiB 0 hz 600 ms 18
2 61.812 MiB 144.000 KiB 0 hz 0 ns 1
3 61.953 MiB 1.922 MiB 0 hz 2.400 s 19
4 63.875 MiB 12.133 MiB 0 hz 200 ms 0
[...]
500 5.132 GiB 8.000 KiB 0 hz 2 m 15.800 s 20
501 5.132 GiB 8.000 KiB 0 hz 2 m 16.200 s 0
502 5.132 GiB 16.000 KiB 0 hz 2 m 16.900 s 20
503 5.132 GiB 24.000 KiB 0 hz 2 m 14.200 s 0
504 5.132 GiB 8.000 KiB 0 hz 2 m 14.900 s 20
[...]
923 7.534 GiB 126.637 MiB 0 hz 0 ns 6
924 7.658 GiB 252.000 KiB 0 hz 54.800 s 20
925 7.658 GiB 142.242 MiB 0 hz 300 ms 0
memory bw estimate: 0 B per second
total size: 7.797 GiB
record DAMON intervals: sample 5 ms, aggr 100 ms
As expected, regions are adjusted to provide the best accurate picture
for the anonymous pages distribution (<probe hits>). The region 0
(60.445 MiB memory from the address 4.000 KiB) has nearly zero anonymous
pages. The region 1 (1.363 MiB memory from the address 60.449 MiB) is
nearly full with anonymous pages. Region 500 (8 KiB memory from the
address 5.132 GiB) is certainly two anonymous pages.
Future Work
===========
Attributes only monitoring disables access monitoring. We will enable
that in future, by extending the supported attributes to include data
accesses. This patch series, and the future work are parts of the
ongoing project [2] for extending DAMON. The project aims to extend
DAMON with primitives other than page table accessed bits such as AMD
IBS, Intel PEBS, and Arm SPE, to provide more powerful and detailed
information like per-CPUs/threads/reads/writes monitoring.
Patches Sequence
================
Patch 1 introduces damon_probe->weight for specifying the weights of
each attribute. Patches 2-6 extends apply_probe() damon_ops callback to
efficiently support the new mode. Patch 7 fixes wrong use of abs() in
the regions merge code. Patch 8 extends regions merge function to work
with probe hits in the mode. Patch 8 also introduces the function for
detecting the mode enablement but always returns false, for safe and
incremental changes. Patches 9 and 10 adds user parameters validation
to prevent theoretical overflow of probe hits and the weighted sum.
Patches 11-14 incrementally update kdamond_fn() to support the mode.
Patch 15 completes the mode detection function implementation, so that
the new mode really works. Patch 16 introduces a new sysfs file for ABI
users. Finally, patches 17-19 respectively updates design, usage and
ABI documents for the new feature and interfaces.
[1] https://github.com/damonitor/damo
[2] https://lore.kernel.org/20260525225208.1179-1-sj@kernel.org/
Changelog
=========
Changes from RFC v1.3
- RFC v1.3: https://lore.kernel.org/20260710002349.111414-1-sj@kernel.org
- Drop RFC tag.
- Rebase to latest mm-new.
Changes from RFC v1.2
- RFC v1.2: https://lore.kernel.org/20260709140600.90950-1-sj@kernel.org
- Fix two typos in comments.
Changes from RFC v1.1
- RFC v1.1: https://lore.kernel.org/20260706141912.88445-1-sj@kernel.org
- Fix typos in comments.
- Fix wrong use of abs() with abs_diff().
- Prevent probe hits and its weighted sum overflow.
Changes from RFC
- RFC: https://lore.kernel.org/20260705205743.98656-1-sj@kernel.org
- Add kernel-doc comment for damon_probe->weight.
- Fix typos in kernel-doc, design and usage documents.
SJ Park (19):
mm/damon/core: introduce damon_probe->weight
mm/damon/core: ask apply_probes() ops callback to set sampling address
mm/damon/paddr: set samples in apply_probes() if requested
mm/damon/core: ask apply_probe() to return max probe hits weighted sum
mm/damon/core: implement damon_probe_hits_wsum()
mm/damon/paddr: respect return_max_wsum
mm/damon/core: use abs_diff() instead of abs()
mm/damon/core: extend merge function to work with probe hits
mm/damon/core: disallow probe_hits overflow on attrs only monitoring
mm/damon/core: validate params for probe hits weighted sum overflow
mm/damon/core: disable access monitoring when probe weights are set
mm/damon/core: set samples in apply_probes() if probe weights are set
mm/damon/core: s/max_nr_accesses/max_merge_score/ in kdamond_fn()
mm/damon/core: get merge threshold from probe hits when weights are
set
mm/damon/core: implement damon_has_probe_weight()
mm/damon/sysfs: implement probe/weight file
Docs/mm/damon/design: document attrs-only monitoring
Docs/admin-guide/mm/damon/usage: document weight sysfs file
Docs/ABI/damon: document probe weight file
.../ABI/testing/sysfs-kernel-mm-damon | 6 +
Documentation/admin-guide/mm/damon/usage.rst | 11 +-
Documentation/mm/damon/design.rst | 25 ++++
include/linux/damon.h | 12 +-
mm/damon/core.c | 139 +++++++++++++++---
mm/damon/paddr.c | 11 +-
mm/damon/sysfs.c | 25 ++++
mm/damon/tests/core-kunit.h | 13 +-
8 files changed, 217 insertions(+), 25 deletions(-)
base-commit: 6af40ebf40984a5ea1bbf273c65c9ad4b6e73291
--
2.47.3
^ permalink raw reply [flat|nested] 39+ messages in thread
* [PATCH 01/19] mm/damon/core: introduce damon_probe->weight
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 13:46 ` [PATCH 02/19] mm/damon/core: ask apply_probes() ops callback to set sampling address SJ Park
` (18 subsequent siblings)
19 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
Add a new field, weight to damon_probe struct. The field is used to
specify the degree of the API caller's interest to the data attribute
of the probe.
Signed-off-by: SJ Park <sj@kernel.org>
---
include/linux/damon.h | 2 ++
mm/damon/core.c | 3 +++
2 files changed, 5 insertions(+)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 63f596957c1f1..d8251c83e6e55 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -760,10 +760,12 @@ struct damon_filter {
/**
* struct damon_probe - Data region attribute probe.
*
+ * @weight: Relative priority of the attribute for this probe.
* @filters: Filters for assessing if a given region is for this probe.
* @list: Siblings list.
*/
struct damon_probe {
+ unsigned int weight;
struct list_head filters;
struct list_head list;
};
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 11473aa1f70f4..327398fa4ee56 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -166,6 +166,7 @@ struct damon_probe *damon_new_probe(void)
p = kmalloc_obj(*p);
if (!p)
return NULL;
+ p->weight = 0;
INIT_LIST_HEAD(&p->filters);
INIT_LIST_HEAD(&p->list);
return p;
@@ -1658,6 +1659,7 @@ static int damon_commit_probes(struct damon_ctx *dst, struct damon_ctx *src)
damon_for_each_probe_safe(dst_probe, next, dst) {
src_probe = damon_nth_probe(i++, src);
if (src_probe) {
+ dst_probe->weight = src_probe->weight;
err = damon_commit_filters(dst_probe, src_probe);
if (err)
return err;
@@ -1674,6 +1676,7 @@ static int damon_commit_probes(struct damon_ctx *dst, struct damon_ctx *src)
if (!new_probe)
return -ENOMEM;
damon_add_probe(dst, new_probe);
+ new_probe->weight = src_probe->weight;
err = damon_commit_filters(new_probe, src_probe);
if (err)
return err;
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 02/19] mm/damon/core: ask apply_probes() ops callback to set sampling address
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
2026-07-10 13:46 ` [PATCH 01/19] mm/damon/core: introduce damon_probe->weight SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 13:56 ` sashiko-bot
2026-07-10 13:46 ` [PATCH 03/19] mm/damon/paddr: set samples in apply_probes() if requested SJ Park
` (17 subsequent siblings)
19 siblings, 1 reply; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
prepare_access_checks() DAMON ops callback sets the monitoring sampling
address per region. In future, DAMON will be able to call only
apply_probes(). In this case, applyy_probes() may need to do the
sampling address setup, to minimize unnecessary regions iteration.
Update the protocol for the request.
Signed-off-by: SJ Park <sj@kernel.org>
---
include/linux/damon.h | 5 +++--
mm/damon/core.c | 2 +-
mm/damon/paddr.c | 2 +-
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index d8251c83e6e55..aee28b05acc6c 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -647,7 +647,8 @@ enum damon_ops_id {
* It should also return max number of observed accesses that made as a result
* of its update. The value will be used for regions adjustment threshold.
* @apply_probes should apply the data attribute probes to each region and
- * accordingly update the probe hits counter of the region.
+ * accordingly update the probe hits counter of the region. It should also
+ * set &damon_region->sampling_addr of each region if ``set_samples`` is true.
* @get_scheme_score should return the priority score of a region for a scheme
* as an integer in [0, &DAMOS_MAX_SCORE].
* @apply_scheme is called from @kdamond when a region for user provided
@@ -665,7 +666,7 @@ struct damon_operations {
void (*update)(struct damon_ctx *context);
void (*prepare_access_checks)(struct damon_ctx *context);
unsigned int (*check_accesses)(struct damon_ctx *context);
- void (*apply_probes)(struct damon_ctx *context);
+ void (*apply_probes)(struct damon_ctx *context, bool set_samples);
int (*get_scheme_score)(struct damon_ctx *context,
struct damon_region *r, struct damos *scheme);
unsigned long (*apply_scheme)(struct damon_ctx *context,
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 327398fa4ee56..9fbea6204520b 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -3692,7 +3692,7 @@ static int kdamond_fn(void *data)
if (ctx->ops.check_accesses)
max_nr_accesses = ctx->ops.check_accesses(ctx);
if (ctx->ops.apply_probes)
- ctx->ops.apply_probes(ctx);
+ ctx->ops.apply_probes(ctx, false);
if (time_after_eq(ctx->passed_sample_intervals,
next_aggregation_sis)) {
diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
index 6172464981730..b13bf7c6eade3 100644
--- a/mm/damon/paddr.c
+++ b/mm/damon/paddr.c
@@ -166,7 +166,7 @@ static bool damon_pa_filter_pass(phys_addr_t pa, struct folio *folio,
return pass;
}
-static void damon_pa_apply_probes(struct damon_ctx *ctx)
+static void damon_pa_apply_probes(struct damon_ctx *ctx, bool set_samples)
{
struct damon_target *t;
struct damon_region *r;
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 03/19] mm/damon/paddr: set samples in apply_probes() if requested
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
2026-07-10 13:46 ` [PATCH 01/19] mm/damon/core: introduce damon_probe->weight SJ Park
2026-07-10 13:46 ` [PATCH 02/19] mm/damon/core: ask apply_probes() ops callback to set sampling address SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 14:01 ` sashiko-bot
2026-07-10 13:46 ` [PATCH 04/19] mm/damon/core: ask apply_probe() to return max probe hits weighted sum SJ Park
` (16 subsequent siblings)
19 siblings, 1 reply; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
apply_probe() callback implementation in DAMON_PADDR is ignoring
set_samples parameter. Respect it.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/paddr.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
index b13bf7c6eade3..ff4fcca949660 100644
--- a/mm/damon/paddr.c
+++ b/mm/damon/paddr.c
@@ -178,6 +178,10 @@ static void damon_pa_apply_probes(struct damon_ctx *ctx, bool set_samples)
phys_addr_t pa;
struct folio *folio;
+ if (set_samples)
+ r->sampling_addr = damon_rand(ctx, r->ar.start,
+ r->ar.end);
+
pa = damon_pa_phys_addr(r->sampling_addr,
ctx->addr_unit);
folio = damon_get_folio(PHYS_PFN(pa));
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 04/19] mm/damon/core: ask apply_probe() to return max probe hits weighted sum
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (2 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 03/19] mm/damon/paddr: set samples in apply_probes() if requested SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 14:01 ` sashiko-bot
2026-07-10 13:46 ` [PATCH 05/19] mm/damon/core: implement damon_probe_hits_wsum() SJ Park
` (15 subsequent siblings)
19 siblings, 1 reply; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
check_accesses() DAMON ops callback returns the maximum nr_accesses of
regions. DAMON core uses it to calculate a reasonable region merge
threshold. The core will need to adjust regions for not nr_accesses but
probe hits weighted sum in future. For that, the core needs to know the
maximum weighted sum of the regions. Update the protocol for the task.
Signed-off-by: SJ Park <sj@kernel.org>
---
include/linux/damon.h | 5 ++++-
mm/damon/core.c | 2 +-
mm/damon/paddr.c | 4 +++-
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index aee28b05acc6c..e7acd8e610a64 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -649,6 +649,8 @@ enum damon_ops_id {
* @apply_probes should apply the data attribute probes to each region and
* accordingly update the probe hits counter of the region. It should also
* set &damon_region->sampling_addr of each region if ``set_samples`` is true.
+ * It should also return maximum probe hits weighted sum of regions if
+ * ``return_max_wsum`` is true.
* @get_scheme_score should return the priority score of a region for a scheme
* as an integer in [0, &DAMOS_MAX_SCORE].
* @apply_scheme is called from @kdamond when a region for user provided
@@ -666,7 +668,8 @@ struct damon_operations {
void (*update)(struct damon_ctx *context);
void (*prepare_access_checks)(struct damon_ctx *context);
unsigned int (*check_accesses)(struct damon_ctx *context);
- void (*apply_probes)(struct damon_ctx *context, bool set_samples);
+ unsigned int (*apply_probes)(struct damon_ctx *context,
+ bool set_samples, bool return_max_wsum);
int (*get_scheme_score)(struct damon_ctx *context,
struct damon_region *r, struct damos *scheme);
unsigned long (*apply_scheme)(struct damon_ctx *context,
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 9fbea6204520b..9f6cdd810bd8a 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -3692,7 +3692,7 @@ static int kdamond_fn(void *data)
if (ctx->ops.check_accesses)
max_nr_accesses = ctx->ops.check_accesses(ctx);
if (ctx->ops.apply_probes)
- ctx->ops.apply_probes(ctx, false);
+ ctx->ops.apply_probes(ctx, false, false);
if (time_after_eq(ctx->passed_sample_intervals,
next_aggregation_sis)) {
diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
index ff4fcca949660..3eba3564a31fc 100644
--- a/mm/damon/paddr.c
+++ b/mm/damon/paddr.c
@@ -166,7 +166,8 @@ static bool damon_pa_filter_pass(phys_addr_t pa, struct folio *folio,
return pass;
}
-static void damon_pa_apply_probes(struct damon_ctx *ctx, bool set_samples)
+static unsigned int damon_pa_apply_probes(struct damon_ctx *ctx,
+ bool set_samples, bool return_max_wsum)
{
struct damon_target *t;
struct damon_region *r;
@@ -194,6 +195,7 @@ static void damon_pa_apply_probes(struct damon_ctx *ctx, bool set_samples)
folio_put(folio);
}
}
+ return 0;
}
/*
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 05/19] mm/damon/core: implement damon_probe_hits_wsum()
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (3 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 04/19] mm/damon/core: ask apply_probe() to return max probe hits weighted sum SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 13:46 ` [PATCH 06/19] mm/damon/paddr: respect return_max_wsum SJ Park
` (14 subsequent siblings)
19 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
When damon_probe->weight is set, the weighted sum of probe hits will be
useful. It will be useful for not only the users but also DAMON
internal logics like regions merging. Implement a function for
calculating it.
Signed-off-by: SJ Park <sj@kernel.org>
---
include/linux/damon.h | 2 ++
mm/damon/core.c | 24 ++++++++++++++++++++++++
2 files changed, 26 insertions(+)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index e7acd8e610a64..f69442a9d4312 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -1012,6 +1012,8 @@ unsigned int damon_nr_accesses_mvsum(struct damon_region *r,
struct damon_ctx *ctx);
unsigned char damon_probe_hits_mvsum(int probe_idx, struct damon_region *r,
struct damon_ctx *ctx);
+unsigned int damon_probe_hits_wsum(struct damon_region *r, bool last,
+ struct damon_ctx *ctx);
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 9f6cdd810bd8a..fea97399b5754 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -393,6 +393,30 @@ static bool damon_is_last_region(struct damon_region *r,
return list_is_last(&r->list, &t->regions_list);
}
+/**
+ * damon_probe_hits_wsum() - Returns probe hits weighted sum of a region.
+ * @r: region to get the weighted sum of.
+ * @last: if the request is for last-window aggregated probe hits.
+ * @ctx: context of &r.
+ *
+ * Return: the weighted sum of probe hits of the region.
+ */
+unsigned int damon_probe_hits_wsum(struct damon_region *r, bool last,
+ struct damon_ctx *ctx)
+{
+ struct damon_probe *probe;
+ unsigned int sum = 0;
+ int i = 0;
+
+ damon_for_each_probe(probe, ctx) {
+ if (last)
+ sum += r->last_probe_hits[i++] * probe->weight;
+ else
+ sum += r->probe_hits[i++] * probe->weight;
+ }
+ return sum;
+}
+
/*
* Check whether a region is intersecting an address range
*
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 06/19] mm/damon/paddr: respect return_max_wsum
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (4 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 05/19] mm/damon/core: implement damon_probe_hits_wsum() SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 13:46 ` [PATCH 07/19] mm/damon/core: use abs_diff() instead of abs() SJ Park
` (13 subsequent siblings)
19 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
apply_probes() ops implementation in DAMON_PADDR is ignoring
return_max_wsum. Respect it.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/paddr.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
index 3eba3564a31fc..b85f88a7a38f4 100644
--- a/mm/damon/paddr.c
+++ b/mm/damon/paddr.c
@@ -172,6 +172,7 @@ static unsigned int damon_pa_apply_probes(struct damon_ctx *ctx,
struct damon_target *t;
struct damon_region *r;
struct damon_probe *p;
+ unsigned int max_wsum = 0;
damon_for_each_target(t, ctx) {
damon_for_each_region(r, t) {
@@ -182,7 +183,6 @@ static unsigned int damon_pa_apply_probes(struct damon_ctx *ctx,
if (set_samples)
r->sampling_addr = damon_rand(ctx, r->ar.start,
r->ar.end);
-
pa = damon_pa_phys_addr(r->sampling_addr,
ctx->addr_unit);
folio = damon_get_folio(PHYS_PFN(pa));
@@ -193,9 +193,12 @@ static unsigned int damon_pa_apply_probes(struct damon_ctx *ctx,
}
if (folio)
folio_put(folio);
+ if (return_max_wsum)
+ max_wsum = max(damon_probe_hits_wsum(r, false,
+ ctx), max_wsum);
}
}
- return 0;
+ return max_wsum;
}
/*
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 07/19] mm/damon/core: use abs_diff() instead of abs()
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (5 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 06/19] mm/damon/paddr: respect return_max_wsum SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 14:10 ` sashiko-bot
2026-07-10 13:46 ` [PATCH 08/19] mm/damon/core: extend merge function to work with probe hits SJ Park
` (12 subsequent siblings)
19 siblings, 1 reply; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
Use of abs() in damon_merge_regions_of() could cause a silent integer
overflow since the macro casts unsigned int to signed int. It is
unlikely to have such a large value for nr_accesses. Even though it
happens, the user impact is just degraded monitoring results. Users
showing bad monitoring results for weird setup is quite trivial. But
the code is obviously wrong. Use abs_diff() instead.
The issue was discovered [1] by Sashiko.
[1] https://lore.kernel.org/20260705213817.100841-1-sj@kernel.org/
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index fea97399b5754..4c7e8a12a9b67 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -3261,7 +3261,7 @@ static void damon_merge_regions_of(struct damon_target *t, unsigned int thres,
struct damon_region *r, *prev = NULL, *next;
damon_for_each_region_safe(r, next, t) {
- if (abs(r->nr_accesses - r->last_nr_accesses) > thres)
+ if (abs_diff(r->nr_accesses, r->last_nr_accesses) > thres)
r->age = 0;
else if ((r->nr_accesses == 0) != (r->last_nr_accesses == 0))
r->age = 0;
@@ -3269,7 +3269,7 @@ static void damon_merge_regions_of(struct damon_target *t, unsigned int thres,
r->age++;
if (prev && prev->ar.end == r->ar.start &&
- abs(prev->nr_accesses - r->nr_accesses) <= thres &&
+ abs_diff(prev->nr_accesses, r->nr_accesses) <= thres &&
damon_sz_region(prev) + damon_sz_region(r) <= sz_limit)
damon_merge_two_regions(t, prev, r);
else
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 08/19] mm/damon/core: extend merge function to work with probe hits
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (6 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 07/19] mm/damon/core: use abs_diff() instead of abs() SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 14:05 ` sashiko-bot
2026-07-10 13:46 ` [PATCH 09/19] mm/damon/core: disallow probe_hits overflow on attrs only monitoring SJ Park
` (11 subsequent siblings)
19 siblings, 1 reply; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
When probe weights are set, users may want DAMON monitoring results to
be optimized for the weights. For that, regions adjustment should work
for the weighted sum of probe hits. Extend damon_merge_regions_of() to
detect if the weights are set, and work with probe hits in the case.
The weights setup detection function is incomplete. It always returns
false. It is intentional, so that more changes to completely support
weights can be made in an incremental but safe way. Until the function
is completed, all changes depend on it is no-op, so DAMON works in the
current mode.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/core.c | 49 +++++++++++++++++++++++++++++--------
mm/damon/tests/core-kunit.h | 13 ++++++++--
2 files changed, 50 insertions(+), 12 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 4c7e8a12a9b67..7d49420ea26c4 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -209,6 +209,11 @@ static struct damon_probe *damon_nth_probe(int n, struct damon_ctx *ctx)
return NULL;
}
+static bool damon_has_probe_weights(struct damon_ctx *c)
+{
+ return false;
+}
+
/*
* damon_mvsum() - Returns pseudo moving sum value for a time window.
* @current_nr: The value of the current aggregation window.
@@ -3248,6 +3253,16 @@ static void damon_merge_two_regions(struct damon_target *t,
damon_destroy_region(r, t);
}
+static unsigned int damon_merge_score(struct damon_region *r, bool last,
+ struct damon_ctx *ctx, bool use_probe_hits)
+{
+ if (use_probe_hits)
+ return damon_probe_hits_wsum(r, last, ctx);
+ if (last)
+ return r->last_nr_accesses;
+ return r->nr_accesses;
+}
+
/*
* Merge adjacent regions having similar access frequencies
*
@@ -3256,24 +3271,38 @@ static void damon_merge_two_regions(struct damon_target *t,
* sz_limit size upper limit of each region
*/
static void damon_merge_regions_of(struct damon_target *t, unsigned int thres,
- unsigned long sz_limit)
+ unsigned long sz_limit, struct damon_ctx *ctx)
{
struct damon_region *r, *prev = NULL, *next;
+ bool use_probe_hits = damon_has_probe_weights(ctx);
damon_for_each_region_safe(r, next, t) {
- if (abs_diff(r->nr_accesses, r->last_nr_accesses) > thres)
+ unsigned int score, last_score, diff;
+
+ score = damon_merge_score(r, false, ctx, use_probe_hits);
+ last_score = damon_merge_score(r, true, ctx, use_probe_hits);
+
+ if (abs_diff(score, last_score) > thres)
r->age = 0;
- else if ((r->nr_accesses == 0) != (r->last_nr_accesses == 0))
+ else if ((score == 0) != (last_score == 0))
r->age = 0;
else
r->age++;
- if (prev && prev->ar.end == r->ar.start &&
- abs_diff(prev->nr_accesses, r->nr_accesses) <= thres &&
- damon_sz_region(prev) + damon_sz_region(r) <= sz_limit)
- damon_merge_two_regions(t, prev, r);
- else
- prev = r;
+ if (!prev)
+ goto set_prev_continue;
+ if (prev->ar.end != r->ar.start)
+ goto set_prev_continue;
+ diff = abs_diff(score, damon_merge_score(prev, false, ctx,
+ use_probe_hits));
+ if (diff > thres)
+ goto set_prev_continue;
+ if (damon_sz_region(prev) + damon_sz_region(r) > sz_limit)
+ goto set_prev_continue;
+ damon_merge_two_regions(t, prev, r);
+ continue;
+set_prev_continue:
+ prev = r;
}
}
@@ -3306,7 +3335,7 @@ static void kdamond_merge_regions(struct damon_ctx *c, unsigned int threshold,
do {
nr_regions = 0;
damon_for_each_target(t, c) {
- damon_merge_regions_of(t, threshold, sz_limit);
+ damon_merge_regions_of(t, threshold, sz_limit, c);
nr_regions += damon_nr_regions(t);
}
threshold = max(1, threshold * 2);
diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h
index d97280270c27b..6ad73559dd8ea 100644
--- a/mm/damon/tests/core-kunit.h
+++ b/mm/damon/tests/core-kunit.h
@@ -226,6 +226,7 @@ static struct damon_region *__nth_region_of(struct damon_target *t, int idx)
static void damon_test_merge_regions_of(struct kunit *test)
{
+ struct damon_ctx *ctx;
struct damon_target *t;
struct damon_region *r;
unsigned long sa[] = {0, 100, 114, 122, 130, 156, 170, 184, 230};
@@ -236,20 +237,27 @@ static void damon_test_merge_regions_of(struct kunit *test)
unsigned long eaddrs[] = {112, 130, 156, 170, 230, 10170};
int i;
+ ctx = damon_new_ctx();
+ if (!ctx)
+ kunit_skip(test, "ctx alloc fail");
+
t = damon_new_target();
- if (!t)
+ if (!t) {
+ damon_destroy_ctx(ctx);
kunit_skip(test, "target alloc fail");
+ }
for (i = 0; i < ARRAY_SIZE(sa); i++) {
r = damon_new_region(sa[i], ea[i]);
if (!r) {
damon_free_target(t);
+ damon_destroy_ctx(ctx);
kunit_skip(test, "region alloc fail");
}
r->nr_accesses = nrs[i];
damon_add_region(r, t);
}
- damon_merge_regions_of(t, 9, 9999);
+ damon_merge_regions_of(t, 9, 9999, ctx);
/* 0-112, 114-130, 130-156, 156-170, 170-230, 230-10170 */
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 6u);
for (i = 0; i < 6; i++) {
@@ -258,6 +266,7 @@ static void damon_test_merge_regions_of(struct kunit *test)
KUNIT_EXPECT_EQ(test, r->ar.end, eaddrs[i]);
}
damon_free_target(t);
+ damon_destroy_ctx(ctx);
}
static void damon_test_split_regions_of(struct kunit *test)
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 09/19] mm/damon/core: disallow probe_hits overflow on attrs only monitoring
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (7 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 08/19] mm/damon/core: extend merge function to work with probe hits SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 13:46 ` [PATCH 10/19] mm/damon/core: validate params for probe hits weighted sum overflow SJ Park
` (10 subsequent siblings)
19 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
When any damon_probe->weight is set, DAMON will do only probe
monitoring. probe_hits is 'unsigned char'. It could overflow when the
aggregation interval is larger than the sampling interval times 256.
damon_as_probe_weights() always return false, so such overflow cannot
happen. Even if it happens, it only degrades the monitoring results.
That said, the overflow is not intentional. It is better to be
prevented as long as the cost is not expensive. Disallow the overflow
by adding a validation logic on the core layer parameters validation
function.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/core.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 7d49420ea26c4..4f1425e56950b 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1332,6 +1332,19 @@ static void damos_set_filters_default_reject(struct damos *s)
damos_filters_default_reject(&s->ops_filters);
}
+static bool damon_valid_probe_params(struct damon_ctx *ctx)
+{
+ unsigned long sample_interval;
+
+ if (!damon_has_probe_weights(ctx))
+ return true;
+
+ sample_interval = ctx->attrs.sample_interval ? : 1;
+ if (ctx->attrs.aggr_interval / sample_interval > U8_MAX)
+ return false;
+ return true;
+}
+
/*
* damos_commit_dests() - Copy migration destinations from @src to @dst.
* @dst: Destination structure to update.
@@ -1736,6 +1749,9 @@ static int __damon_commit_ctx(struct damon_ctx *dst, struct damon_ctx *src)
}
}
+ if (!damon_valid_probe_params(src))
+ return -EINVAL;
+
err = damon_commit_schemes(dst, src);
if (err)
return err;
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 10/19] mm/damon/core: validate params for probe hits weighted sum overflow
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (8 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 09/19] mm/damon/core: disallow probe_hits overflow on attrs only monitoring SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 14:07 ` sashiko-bot
2026-07-10 13:46 ` [PATCH 11/19] mm/damon/core: disable access monitoring when probe weights are set SJ Park
` (9 subsequent siblings)
19 siblings, 1 reply; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
damon_probe_hits_wsum() could overflow in weird setups. Users could set
the weight unreasonably high. They could also set the aggregation
interval unreasonably high compared to the sampling interval. Such user
setup is unlikely. Even if such setup is used,
damon_has_probe_weights() always returns false, so the overflow cannot
happen. The function may be completed in future, though. Even if the
overflow happens, the consequence is degraded monitoring results for the
unreasonable setup. It is just a trivial user experience issue.
It is still better to be prevented unless the cost is expensive. Avoid
the overflow by adding the parameter validation in the core layer
parameters validation function.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/core.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 4f1425e56950b..a0e6a5129fbf3 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1335,6 +1335,9 @@ static void damos_set_filters_default_reject(struct damos *s)
static bool damon_valid_probe_params(struct damon_ctx *ctx)
{
unsigned long sample_interval;
+ unsigned char max_probe_hits;
+ struct damon_probe *probe;
+ unsigned int wsum, wsum_to_add;
if (!damon_has_probe_weights(ctx))
return true;
@@ -1342,6 +1345,18 @@ static bool damon_valid_probe_params(struct damon_ctx *ctx)
sample_interval = ctx->attrs.sample_interval ? : 1;
if (ctx->attrs.aggr_interval / sample_interval > U8_MAX)
return false;
+
+ /* invalid if probe hits weighted sum can overflow */
+ max_probe_hits = damon_nr_samples_per_aggr(&ctx->attrs);
+ wsum = 0;
+ damon_for_each_probe(probe, ctx) {
+ if (probe->weight > UINT_MAX / max_probe_hits)
+ return false;
+ wsum_to_add = probe->weight * max_probe_hits;
+ if (UINT_MAX - wsum < wsum_to_add)
+ return false;
+ wsum += wsum_to_add;
+ }
return true;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 11/19] mm/damon/core: disable access monitoring when probe weights are set
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (9 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 10/19] mm/damon/core: validate params for probe hits weighted sum overflow SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 13:46 ` [PATCH 12/19] mm/damon/core: set samples in apply_probes() if " SJ Park
` (8 subsequent siblings)
19 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
When users set probe weights, they are interested in the data
attributes. Not necessarily they are interested in data access
patterns. Disable the data access monitoring in the case.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/core.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index a0e6a5129fbf3..65f91e3b58d2e 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -3763,17 +3763,18 @@ static int kdamond_fn(void *data)
unsigned long next_aggregation_sis = ctx->next_aggregation_sis;
unsigned long next_ops_update_sis = ctx->next_ops_update_sis;
unsigned long sample_interval = ctx->attrs.sample_interval;
+ bool access_check_disabled = damon_has_probe_weights(ctx);
if (kdamond_wait_activation(ctx))
break;
- if (ctx->ops.prepare_access_checks)
+ if (!access_check_disabled && ctx->ops.prepare_access_checks)
ctx->ops.prepare_access_checks(ctx);
kdamond_usleep(sample_interval);
ctx->passed_sample_intervals++;
- if (ctx->ops.check_accesses)
+ if (!access_check_disabled && ctx->ops.check_accesses)
max_nr_accesses = ctx->ops.check_accesses(ctx);
if (ctx->ops.apply_probes)
ctx->ops.apply_probes(ctx, false, false);
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 12/19] mm/damon/core: set samples in apply_probes() if probe weights are set
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (10 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 11/19] mm/damon/core: disable access monitoring when probe weights are set SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 14:02 ` sashiko-bot
2026-07-10 13:46 ` [PATCH 13/19] mm/damon/core: s/max_nr_accesses/max_merge_score/ in kdamond_fn() SJ Park
` (7 subsequent siblings)
19 siblings, 1 reply; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
When probe weights are set, the prepare_access_checks() ops callback is
not invoked, so sampling addresses of regions are unset. Ask
apply_probes() to set those together in the case.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 65f91e3b58d2e..dd0612e1a408b 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -3777,7 +3777,8 @@ static int kdamond_fn(void *data)
if (!access_check_disabled && ctx->ops.check_accesses)
max_nr_accesses = ctx->ops.check_accesses(ctx);
if (ctx->ops.apply_probes)
- ctx->ops.apply_probes(ctx, false, false);
+ ctx->ops.apply_probes(ctx, access_check_disabled,
+ false);
if (time_after_eq(ctx->passed_sample_intervals,
next_aggregation_sis)) {
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 13/19] mm/damon/core: s/max_nr_accesses/max_merge_score/ in kdamond_fn()
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (11 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 12/19] mm/damon/core: set samples in apply_probes() if " SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 13:46 ` [PATCH 14/19] mm/damon/core: get merge threshold from probe hits when weights are set SJ Park
` (6 subsequent siblings)
19 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
When probe weights are set, DAMON merge logic works with the probe hits
weighted sum. The core logic is setting the merge threshold based on
the access frequency, though. Before using probe hits based threshold,
rename the variables to look more general.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/core.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index dd0612e1a408b..f7782c69037da 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -3730,7 +3730,6 @@ static void kdamond_init_ctx(struct damon_ctx *ctx)
static int kdamond_fn(void *data)
{
struct damon_ctx *ctx = data;
- unsigned int max_nr_accesses = 0;
unsigned long sz_limit = 0;
pr_debug("kdamond (%d) starts\n", current->pid);
@@ -3764,6 +3763,7 @@ static int kdamond_fn(void *data)
unsigned long next_ops_update_sis = ctx->next_ops_update_sis;
unsigned long sample_interval = ctx->attrs.sample_interval;
bool access_check_disabled = damon_has_probe_weights(ctx);
+ unsigned int max_merge_score = 0;
if (kdamond_wait_activation(ctx))
break;
@@ -3775,7 +3775,7 @@ static int kdamond_fn(void *data)
ctx->passed_sample_intervals++;
if (!access_check_disabled && ctx->ops.check_accesses)
- max_nr_accesses = ctx->ops.check_accesses(ctx);
+ max_merge_score = ctx->ops.check_accesses(ctx);
if (ctx->ops.apply_probes)
ctx->ops.apply_probes(ctx, access_check_disabled,
false);
@@ -3783,7 +3783,7 @@ static int kdamond_fn(void *data)
if (time_after_eq(ctx->passed_sample_intervals,
next_aggregation_sis)) {
kdamond_merge_regions(ctx,
- max_nr_accesses / 10,
+ max_merge_score / 10,
sz_limit);
/* online updates might be made */
sz_limit = damon_apply_min_nr_regions(ctx);
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 14/19] mm/damon/core: get merge threshold from probe hits when weights are set
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (12 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 13/19] mm/damon/core: s/max_nr_accesses/max_merge_score/ in kdamond_fn() SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 14:05 ` sashiko-bot
2026-07-10 13:46 ` [PATCH 15/19] mm/damon/core: implement damon_has_probe_weight() SJ Park
` (5 subsequent siblings)
19 siblings, 1 reply; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
When probe weights are set, DAMON merges regions based on their probe
hits weighted sum. But the merge threshold is calculated based on the
access frequency. Update it to retrieve the maximum probe hits weighted
sum in the snapshot from apply_probes() ops callback, and generate the
threshold based on it.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/core.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index f7782c69037da..91964336ce31e 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -3763,7 +3763,8 @@ static int kdamond_fn(void *data)
unsigned long next_ops_update_sis = ctx->next_ops_update_sis;
unsigned long sample_interval = ctx->attrs.sample_interval;
bool access_check_disabled = damon_has_probe_weights(ctx);
- unsigned int max_merge_score = 0;
+ unsigned int max_merge_score = 0, max_wsum;
+ bool get_max_wsum;
if (kdamond_wait_activation(ctx))
break;
@@ -3776,9 +3777,18 @@ static int kdamond_fn(void *data)
if (!access_check_disabled && ctx->ops.check_accesses)
max_merge_score = ctx->ops.check_accesses(ctx);
- if (ctx->ops.apply_probes)
- ctx->ops.apply_probes(ctx, access_check_disabled,
- false);
+ if (ctx->ops.apply_probes) {
+ if (time_after_eq(ctx->passed_sample_intervals,
+ next_aggregation_sis) &&
+ access_check_disabled)
+ get_max_wsum = true;
+ else
+ get_max_wsum = false;
+ max_wsum = ctx->ops.apply_probes(ctx,
+ access_check_disabled, get_max_wsum);
+ if (get_max_wsum)
+ max_merge_score = max_wsum;
+ }
if (time_after_eq(ctx->passed_sample_intervals,
next_aggregation_sis)) {
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 15/19] mm/damon/core: implement damon_has_probe_weight()
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (13 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 14/19] mm/damon/core: get merge threshold from probe hits when weights are set SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 14:11 ` sashiko-bot
2026-07-10 13:46 ` [PATCH 16/19] mm/damon/sysfs: implement probe/weight file SJ Park
` (4 subsequent siblings)
19 siblings, 1 reply; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
DAMON monitors only data attributes when probe weights are set.
However, the function for detecting it is intentionally returning false
always. The intention was to make changes for complete support of the
mode in a safe and incremental way. Now all the building blocks are
made. Complete the mode detection function so that the mode can really
start working.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/core.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 91964336ce31e..806a67d02a6e9 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -211,6 +211,12 @@ static struct damon_probe *damon_nth_probe(int n, struct damon_ctx *ctx)
static bool damon_has_probe_weights(struct damon_ctx *c)
{
+ struct damon_probe *p;
+
+ damon_for_each_probe(p, c) {
+ if (p->weight)
+ return true;
+ }
return false;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 16/19] mm/damon/sysfs: implement probe/weight file
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (14 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 15/19] mm/damon/core: implement damon_has_probe_weight() SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 13:46 ` [PATCH 17/19] Docs/mm/damon/design: document attrs-only monitoring SJ Park
` (3 subsequent siblings)
19 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton; +Cc: SJ Park, damon, linux-kernel, linux-mm
Implement a new sysfs file, 'weight', under probe directory. Users will
be able to set the probe weight and enable the attributes only
monitoring using it.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/sysfs.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index 6d7e36c9e509d..b5fe036f78015 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -1065,6 +1065,7 @@ static const struct kobj_type damon_sysfs_filters_ktype = {
struct damon_sysfs_probe {
struct kobject kobj;
+ unsigned int weight;
struct damon_sysfs_filters *filters;
};
@@ -1100,12 +1101,35 @@ static void damon_sysfs_probe_rm_dirs(struct damon_sysfs_probe *probe)
}
}
+static ssize_t weight_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct damon_sysfs_probe *probe = container_of(kobj,
+ struct damon_sysfs_probe, kobj);
+
+ return sysfs_emit(buf, "%u\n", probe->weight);
+}
+
+static ssize_t weight_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_probe *probe = container_of(kobj,
+ struct damon_sysfs_probe, kobj);
+ int err = kstrtouint(buf, 0, &probe->weight);
+
+ return err ? err : count;
+}
+
static void damon_sysfs_probe_release(struct kobject *kobj)
{
kfree(container_of(kobj, struct damon_sysfs_probe, kobj));
}
+static struct kobj_attribute damon_sysfs_probe_weight_attr =
+ __ATTR_RW_MODE(weight, 0600);
+
static struct attribute *damon_sysfs_probe_attrs[] = {
+ &damon_sysfs_probe_weight_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(damon_sysfs_probe);
@@ -1965,6 +1989,7 @@ static int damon_sysfs_set_probes(struct damon_ctx *ctx,
return -ENOMEM;
damon_add_probe(ctx, p);
sys_probe = sys_probes->probes_arr[i];
+ p->weight = sys_probe->weight;
err = damon_sysfs_set_probe(p, sys_probe);
if (err)
return err;
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 17/19] Docs/mm/damon/design: document attrs-only monitoring
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (15 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 16/19] mm/damon/sysfs: implement probe/weight file SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 13:46 ` [PATCH 18/19] Docs/admin-guide/mm/damon/usage: document weight sysfs file SJ Park
` (2 subsequent siblings)
19 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton
Cc: SJ Park, Liam R. Howlett, David Hildenbrand, Jonathan Corbet,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka, damon, linux-doc,
linux-kernel, linux-mm
Update DAMON design document for the attributes only monitoring mode.
Signed-off-by: SJ Park <sj@kernel.org>
---
Documentation/mm/damon/design.rst | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst
index 457d6e8bc7878..6d79e7d69be84 100644
--- a/Documentation/mm/damon/design.rst
+++ b/Documentation/mm/damon/design.rst
@@ -316,6 +316,26 @@ Another way to do this for higher accuracy is using :ref:`DAMOS filter
information in page level. But, because it is operated in page level, the
overhead is proportional to the size of the memory.
+Data Attributes-only Monitoring
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Data access is the primary monitoring information for DAMON. Hence it
+:ref:`adjusts <damon_design_data_attrs_monitoring>` regions using the access
+:ref:`counter <damon_design_region_based_sampling>` (``nr_accesses``). In some
+use cases, however, users may want some of :ref:`attributes
+<damon_design_data_attrs_monitoring>` to be the primary information.
+
+Data attributes-only monitoring mode supports this use case. For the mode,
+each attribute probe has their priority weight value. Users can describe by
+what combination of the attributes the primary information is decided, by
+setting the priority weight value. If the total sum of the weights is not
+zero, the mode is enabled. The regions adjustment mechanism uses the weighted
+sum of the :ref:`probe hit counts <damon_design_data_attrs_monitoring>` instead
+of ``nr_accesses`` in the case. When the mode is enabled, access monitoring is
+automatically turned off. The access counter (``nr_accesses``) will always be
+zero and not updated. Hence the mode is called Data Attributes "only"
+monitoring.
+
Dynamic Target Space Updates Handling
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 18/19] Docs/admin-guide/mm/damon/usage: document weight sysfs file
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (16 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 17/19] Docs/mm/damon/design: document attrs-only monitoring SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 13:46 ` [PATCH 19/19] Docs/ABI/damon: document probe weight file SJ Park
2026-07-10 14:59 ` [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
19 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton
Cc: SJ Park, Liam R. Howlett, David Hildenbrand, Jonathan Corbet,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka, damon, linux-doc,
linux-kernel, linux-mm
Update DAMON usage document for newly added probe weight file.
Signed-off-by: SJ Park <sj@kernel.org>
---
Documentation/admin-guide/mm/damon/usage.rst | 11 ++++++++---
Documentation/mm/damon/design.rst | 5 +++++
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst
index b2649ea011f93..da5f9afd08aef 100644
--- a/Documentation/admin-guide/mm/damon/usage.rst
+++ b/Documentation/admin-guide/mm/damon/usage.rst
@@ -73,9 +73,10 @@ comma (",").
│ │ │ │ │ │ │ intervals_goal/access_bp,aggrs,min_sample_us,max_sample_us
│ │ │ │ │ │ nr_regions/min,max
│ │ │ │ │ │ :ref:`probes <damon_usage_sysfs_probes>`/nr_probes
- │ │ │ │ │ │ │ 0/filters/nr_filters
- │ │ │ │ │ │ │ │ 0/type,matching,allow,path
- │ │ │ │ │ │ │ │ ...
+ │ │ │ │ │ │ │ 0/weight
+ │ │ │ │ │ │ │ │ filters/nr_filters
+ │ │ │ │ │ │ │ │ │ 0/type,matching,allow,path
+ │ │ │ │ │ │ │ │ │ ...
│ │ │ │ │ │ │ ...
│ │ │ │ │ :ref:`targets <sysfs_targets>`/nr_targets
│ │ │ │ │ │ :ref:`0 <sysfs_target>`/pid_target,obsolete_target
@@ -286,6 +287,10 @@ In each probe directory, one directory, ``filters`` exists. The directory
contains files for installing filters for the probe, that is used to determine
the data attribute for the probe.
+Each probe directory also contains ``weight`` file. Reading from and writing
+to the file gets and sets the :ref:`attributes-only monitoring
+<damon_design_attrs_only_monitoring>` weight for the attribute of the probe.
+
In the beginning, ``filters`` directory has only one file, ``nr_filters``.
Writing a number (``N``) to the file creates the number of child directories
named ``0`` to ``N-1``. Each directory represents each filter and works in a
diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst
index 6d79e7d69be84..aed6cb1cf4831 100644
--- a/Documentation/mm/damon/design.rst
+++ b/Documentation/mm/damon/design.rst
@@ -316,6 +316,8 @@ Another way to do this for higher accuracy is using :ref:`DAMOS filter
information in page level. But, because it is operated in page level, the
overhead is proportional to the size of the memory.
+.. _damon_design_attrs_only_monitoring:
+
Data Attributes-only Monitoring
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -336,6 +338,9 @@ automatically turned off. The access counter (``nr_accesses``) will always be
zero and not updated. Hence the mode is called Data Attributes "only"
monitoring.
+Refer to the :ref:`admin guide <damon_usage_sysfs_probes>` to know how users
+can use the mode.
+
Dynamic Target Space Updates Handling
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 19/19] Docs/ABI/damon: document probe weight file
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (17 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 18/19] Docs/admin-guide/mm/damon/usage: document weight sysfs file SJ Park
@ 2026-07-10 13:46 ` SJ Park
2026-07-10 14:59 ` [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
19 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 13:46 UTC (permalink / raw)
To: Andrew Morton
Cc: SJ Park, Liam R. Howlett, David Hildenbrand, Lorenzo Stoakes,
Michal Hocko, Mike Rapoport, Suren Baghdasaryan, Vlastimil Babka,
damon, linux-kernel, linux-mm
Update DAMON ABI document for the newly added probe weight sysfs file.
Signed-off-by: SJ Park <sj@kernel.org>
---
Documentation/ABI/testing/sysfs-kernel-mm-damon | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/ABI/testing/sysfs-kernel-mm-damon b/Documentation/ABI/testing/sysfs-kernel-mm-damon
index dd6b5bd76e119..907a504fb64c5 100644
--- a/Documentation/ABI/testing/sysfs-kernel-mm-damon
+++ b/Documentation/ABI/testing/sysfs-kernel-mm-damon
@@ -164,6 +164,12 @@ Description: Writing a number 'N' to this file creates the number of
directories for each DAMON probe named '0' to 'N-1' under the
probes/ directory.
+What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/monitoring_attrs/probes/<P>/weight
+Date: Jul 2026
+Contact: SJ Park <sj@kernel.org>
+Description: Writing to and reading from this file sets and gets the
+ per-probe attribute weight.
+
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/monitoring_attrs/probes/<P>/filters/nr_filters
Date: May 2026
Contact: SJ Park <sj@kernel.org>
--
2.47.3
^ permalink raw reply related [flat|nested] 39+ messages in thread
* Re: [PATCH 02/19] mm/damon/core: ask apply_probes() ops callback to set sampling address
2026-07-10 13:46 ` [PATCH 02/19] mm/damon/core: ask apply_probes() ops callback to set sampling address SJ Park
@ 2026-07-10 13:56 ` sashiko-bot
2026-07-10 14:32 ` SJ Park
0 siblings, 1 reply; 39+ messages in thread
From: sashiko-bot @ 2026-07-10 13:56 UTC (permalink / raw)
To: SJ Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The `damon_pa_apply_probes` callback fails to implement the newly added `set_samples` parameter, violating the updated API operations contract.
--
--- Patch [2]: [PATCH 02/19] mm/damon/core: ask apply_probes() ops callback to set sampling address ---
commit 2da9028945951622496aef07a601ae5bfba7972a
Author: SJ Park <sj@kernel.org>
mm/damon/core: ask apply_probes() ops callback to set sampling address
This commit updates the DAMON ops callback apply_probes() to accept a
set_samples boolean parameter. The parameter allows the callback to setup
the sampling address per region to minimize unnecessary regions iteration.
> diff --git a/include/linux/damon.h b/include/linux/damon.h
> index d8251c83e6e55..aee28b05acc6c 100644
> --- a/include/linux/damon.h
> +++ b/include/linux/damon.h
[ ... ]
> @@ -647,7 +647,8 @@ enum damon_ops_id {
> * It should also return max number of observed accesses that made as a result
> * of its update. The value will be used for regions adjustment threshold.
> * @apply_probes should apply the data attribute probes to each region and
> - * accordingly update the probe hits counter of the region.
> + * accordingly update the probe hits counter of the region. It should also
> + * set &damon_region->sampling_addr of each region if ``set_samples`` is true.
> * @get_scheme_score should return the priority score of a region for a scheme
> * as an integer in [0, &DAMOS_MAX_SCORE].
> * @apply_scheme is called from @kdamond when a region for user provided
[ ... ]
> diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
> index 6172464981730..b13bf7c6eade3 100644
> --- a/mm/damon/paddr.c
> +++ b/mm/damon/paddr.c
[ ... ]
> @@ -166,7 +166,7 @@ static bool damon_pa_filter_pass(phys_addr_t pa, struct folio *folio,
> return pass;
> }
>
> -static void damon_pa_apply_probes(struct damon_ctx *ctx)
> +static void damon_pa_apply_probes(struct damon_ctx *ctx, bool set_samples)
> {
> struct damon_target *t;
> struct damon_region *r;
[Severity: Medium]
Will callers passing set_samples=true end up using stale sampling addresses?
The documentation in include/linux/damon.h states that apply_probes should
set &damon_region->sampling_addr if set_samples is true.
However, the updated damon_pa_apply_probes() does not seem to handle the
new parameter:
mm/damon/paddr.c:damon_pa_apply_probes() {
...
damon_for_each_region(r, t) {
int i = 0;
phys_addr_t pa;
struct folio *folio;
pa = damon_pa_phys_addr(r->sampling_addr,
ctx->addr_unit);
...
}
It reads the existing r->sampling_addr without generating a new random address
when set_samples is true.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=2
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 04/19] mm/damon/core: ask apply_probe() to return max probe hits weighted sum
2026-07-10 13:46 ` [PATCH 04/19] mm/damon/core: ask apply_probe() to return max probe hits weighted sum SJ Park
@ 2026-07-10 14:01 ` sashiko-bot
2026-07-10 14:35 ` SJ Park
0 siblings, 1 reply; 39+ messages in thread
From: sashiko-bot @ 2026-07-10 14:01 UTC (permalink / raw)
To: SJ Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The apply_probes callback fails to calculate and return the maximum probe hits weighted sum, unconditionally returning 0.
--
--- Patch [4]: [PATCH 04/19] mm/damon/core: ask apply_probe() to return max probe hits weighted sum ---
commit bb862935a31b8d93d0e79b24c1d5bb92b5faf39a
Author: SJ Park <sj@kernel.org>
mm/damon/core: ask apply_probe() to return max probe hits weighted sum
This commit updates the DAMON operations protocol to allow the apply_probes
callback to calculate and return the maximum probe hits weighted sum. It
modifies the function signature to take a return_max_wsum parameter and
updates the existing implementation in damon_pa_apply_probes() to return
an unsigned int.
> diff --git a/include/linux/damon.h b/include/linux/damon.h
> index aee28b05acc6c..e7acd8e610a64 100644
> --- a/include/linux/damon.h
> +++ b/include/linux/damon.h
[ ... ]
> @@ -649,6 +649,8 @@ enum damon_ops_id {
> * @apply_probes should apply the data attribute probes to each region and
> * accordingly update the probe hits counter of the region. It should also
> * set &damon_region->sampling_addr of each region if ``set_samples`` is true.
> + * It should also return maximum probe hits weighted sum of regions if
> + * ``return_max_wsum`` is true.
> * @get_scheme_score should return the priority score of a region for a scheme
> * as an integer in [0, &DAMOS_MAX_SCORE].
> * @apply_scheme is called from @kdamond when a region for user provided
[ ... ]
> diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
> index ff4fcca949660..3eba3564a31fc 100644
> --- a/mm/damon/paddr.c
> +++ b/mm/damon/paddr.c
[ ... ]
> @@ -166,7 +166,8 @@ static bool damon_pa_filter_pass(phys_addr_t pa, struct folio *folio,
> return pass;
> }
>
> -static void damon_pa_apply_probes(struct damon_ctx *ctx, bool set_samples)
> +static unsigned int damon_pa_apply_probes(struct damon_ctx *ctx,
> + bool set_samples, bool return_max_wsum)
> {
> struct damon_target *t;
> struct damon_region *r;
[ ... ]
> @@ -194,6 +195,7 @@ static void damon_pa_apply_probes(struct damon_ctx *ctx, bool set_samples)
> folio_put(folio);
> }
> }
> + return 0;
> }
[Severity: Medium]
Will this unconditionally return 0 even when return_max_wsum is true?
The struct documentation states the callback should return the maximum probe
hits weighted sum of regions if return_max_wsum is true. However, the
implementation in damon_pa_apply_probes() simply returns 0 at the end
without computing the weighted sum.
Should the maximum weighted sum calculation be implemented here to fulfill
the updated protocol?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=4
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 03/19] mm/damon/paddr: set samples in apply_probes() if requested
2026-07-10 13:46 ` [PATCH 03/19] mm/damon/paddr: set samples in apply_probes() if requested SJ Park
@ 2026-07-10 14:01 ` sashiko-bot
2026-07-10 14:33 ` SJ Park
0 siblings, 1 reply; 39+ messages in thread
From: sashiko-bot @ 2026-07-10 14:01 UTC (permalink / raw)
To: SJ Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Address advancement using `folio_size()` from an unaligned address within a large folio overshoots the next folio.
--
--- Patch [3]: [PATCH 03/19] mm/damon/paddr: set samples in apply_probes() if requested ---
commit 60a9acbe070a2be34c313d6be62fe7e4acb7ec54
Author: SJ Park <sj@kernel.org>
mm/damon/paddr: set samples in apply_probes() if requested
This commit updates damon_pa_apply_probes() to respect the set_samples
parameter. It adds logic to randomize the sampling address within the
region boundaries using damon_rand() when requested.
> diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
> index b13bf7c6eade3..ff4fcca949660 100644
> --- a/mm/damon/paddr.c
> +++ b/mm/damon/paddr.c
> @@ -178,6 +178,10 @@ static void damon_pa_apply_probes(struct damon_ctx *ctx, bool set_samples)
> phys_addr_t pa;
> struct folio *folio;
>
> + if (set_samples)
> + r->sampling_addr = damon_rand(ctx, r->ar.start,
> + r->ar.end);
> +
> pa = damon_pa_phys_addr(r->sampling_addr,
> ctx->addr_unit);
> folio = damon_get_folio(PHYS_PFN(pa));
[Severity: High]
This is a pre-existing issue in this file, but can the address advancement
logic skip over pages during region iteration?
Looking at iteration functions like damon_pa_pageout(),
damon_pa_de_activate(), damon_pa_migrate(), and damon_pa_stat() in
mm/damon/paddr.c, they all use a pattern for advancing the address
similar to this:
mm/damon/paddr.c:damon_pa_pageout() {
...
folio = damon_get_folio(PHYS_PFN(addr));
if (!folio) {
addr += PAGE_SIZE;
continue;
}
...
addr += folio_size(folio);
...
}
If the initial iteration address is not aligned to the folio boundary (for
example, after a region split or hole), wouldn't adding the full folio size
to this unaligned address cause it to overshoot the end of the current folio?
This seems like it would skip over the beginning of the next physical folio,
causing those pages to incorrectly escape reclaim, migration, or statistics
gathering.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=3
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 12/19] mm/damon/core: set samples in apply_probes() if probe weights are set
2026-07-10 13:46 ` [PATCH 12/19] mm/damon/core: set samples in apply_probes() if " SJ Park
@ 2026-07-10 14:02 ` sashiko-bot
2026-07-10 14:52 ` SJ Park
0 siblings, 1 reply; 39+ messages in thread
From: sashiko-bot @ 2026-07-10 14:02 UTC (permalink / raw)
To: SJ Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] kdamond_merge_regions() uses a stale or 0 threshold (max_nr_accesses) when probe weights are set, preventing proper region merging.
--
--- Patch [12]: [PATCH 12/19] mm/damon/core: set samples in apply_probes() if probe weights are set ---
commit c57b42d6ad5d1b962d67f040aa171492d081c859
Author: SJ Park <sj@kernel.org>
mm/damon/core: set samples in apply_probes() if probe weights are set
When probe weights are set, the prepare_access_checks() ops callback is
not invoked, so sampling addresses of regions are unset. Ask apply_probes()
to set those together in the case.
> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index 65f91e3b58d2e..dd0612e1a408b 100644
> --- a/mm/damon/core.c
> +++ b/mm/damon/core.c
> @@ -3777,7 +3777,8 @@ static int kdamond_fn(void *data)
> if (!access_check_disabled && ctx->ops.check_accesses)
> max_nr_accesses = ctx->ops.check_accesses(ctx);
> if (ctx->ops.apply_probes)
> - ctx->ops.apply_probes(ctx, false, false);
> + ctx->ops.apply_probes(ctx, access_check_disabled,
> + false);
>
> if (time_after_eq(ctx->passed_sample_intervals,
> next_aggregation_sis)) {
[Severity: Medium]
When access_check_disabled is true, ctx->ops.check_accesses() is skipped.
Does this leave max_nr_accesses stale or set to 0 when it is subsequently
passed to kdamond_merge_regions() shortly after this block?
If max_nr_accesses evaluates to 0, it seems this might defeat the 10 percent
tolerance logic for region aggregation.
Could this force adjacent regions to merge only when their scores match
exactly, leading to region fragmentation until the maximum region limit
is hit?
Since damon_has_probe_weights() currently returns false unconditionally
to safely stage the new feature, this appears to be unreachable today, but
might become a regression once the feature is fully enabled.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=12
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 14/19] mm/damon/core: get merge threshold from probe hits when weights are set
2026-07-10 13:46 ` [PATCH 14/19] mm/damon/core: get merge threshold from probe hits when weights are set SJ Park
@ 2026-07-10 14:05 ` sashiko-bot
2026-07-10 14:54 ` SJ Park
0 siblings, 1 reply; 39+ messages in thread
From: sashiko-bot @ 2026-07-10 14:05 UTC (permalink / raw)
To: SJ Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Silent monitoring failure when probe weights are set on operations lacking apply_probes.
- [Medium] kdamond_merge_regions loop termination condition still uses unweighted access frequency as max_thres.
--
--- Patch [14]: [PATCH 14/19] mm/damon/core: get merge threshold from probe hits when weights are set ---
commit 0b09a73e4b353610f5bc3d4f305131a2f9d7fea8
Author: SJ Park <sj@kernel.org>
mm/damon/core: get merge threshold from probe hits when weights are set
When probe weights are set, DAMON merges regions based on their probe
hits weighted sum. But the merge threshold is calculated based on the
access frequency. Update it to retrieve the maximum probe hits weighted
sum in the snapshot from apply_probes() ops callback, and generate the
threshold based on it.
> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index f7782c69037da..91964336ce31e 100644
> --- a/mm/damon/core.c
> +++ b/mm/damon/core.c
> @@ -3776,9 +3777,18 @@ static int kdamond_fn(void *data)
>
> if (!access_check_disabled && ctx->ops.check_accesses)
> max_merge_score = ctx->ops.check_accesses(ctx);
> - if (ctx->ops.apply_probes)
> - ctx->ops.apply_probes(ctx, access_check_disabled,
> - false);
> + if (ctx->ops.apply_probes) {
[Severity: Medium]
If a user configures a DAMON context with ops that lack apply_probes
(such as vaddr), adds a probe with a weight, and starts monitoring,
could this result in a silent monitoring failure?
Since damon_valid_probe_params() allows this configuration:
mm/damon/core.c:damon_valid_probe_params() {
...
return true;
}
access_check_disabled will be true, causing check_accesses() to be
skipped. With ctx->ops.apply_probes being NULL, no monitoring data
would be collected and max_merge_score would remain 0.
> + if (time_after_eq(ctx->passed_sample_intervals,
> + next_aggregation_sis) &&
> + access_check_disabled)
> + get_max_wsum = true;
> + else
> + get_max_wsum = false;
> + max_wsum = ctx->ops.apply_probes(ctx,
> + access_check_disabled, get_max_wsum);
> + if (get_max_wsum)
> + max_merge_score = max_wsum;
> + }
>
> if (time_after_eq(ctx->passed_sample_intervals,
> next_aggregation_sis)) {
[Severity: Medium]
When kdamond_merge_regions() is called with this new max_merge_score based
on weighted probe hits, could the fallback loop terminate prematurely?
mm/damon/core.c:kdamond_fn() {
...
kdamond_merge_regions(ctx,
max_merge_score / 10,
sz_limit);
...
}
Looking at kdamond_merge_regions(), max_thres is hardcoded to the
unweighted maximum access frequency:
mm/damon/core.c:kdamond_merge_regions() {
max_thres = c->attrs.aggr_interval /
(c->attrs.sample_interval ? c->attrs.sample_interval : 1);
do {
...
} while (nr_regions > c->attrs.max_nr_regions &&
threshold / 2 < max_thres);
}
If a user sets a probe weight such that max_merge_score / 10 > max_thres * 2,
the loop condition threshold / 2 < max_thres will evaluate to false immediately,
failing to enforce the max_nr_regions limit during region merging.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=14
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 08/19] mm/damon/core: extend merge function to work with probe hits
2026-07-10 13:46 ` [PATCH 08/19] mm/damon/core: extend merge function to work with probe hits SJ Park
@ 2026-07-10 14:05 ` sashiko-bot
2026-07-10 14:49 ` SJ Park
0 siblings, 1 reply; 39+ messages in thread
From: sashiko-bot @ 2026-07-10 14:05 UTC (permalink / raw)
To: SJ Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
New issues:
- [Medium] Unscaled merge threshold breaks region merging when using weighted probe hits.
- [Medium] Potential 32-bit integer overflow in `damon_probe_hits_wsum()` when accumulating weighted sums.
Pre-existing issues:
- [High] Region ages are evaluated and mutated inside a retry loop, leading to age corruption.
- [High] Calculations for merged regions' weighted averages overflow on 32-bit architectures.
- [Medium] Test NULL pointer dereference in `damon_test_merge_regions_of`.
--
--- Patch [8]: [PATCH 08/19] mm/damon/core: extend merge function to work with probe hits ---
commit 5e9a094bb8d36feea59f27615cb45bcbce00e4c3
Author: SJ Park <sj@kernel.org>
mm/damon/core: extend merge function to work with probe hits
When probe weights are set, users may want DAMON monitoring results to
be optimized for the weights. For that, regions adjustment should work
for the weighted sum of probe hits. Extend damon_merge_regions_of() to
detect if the weights are set, and work with probe hits in the case.
> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index 4c7e8a12a9b67..7d49420ea26c4 100644
> --- a/mm/damon/core.c
> +++ b/mm/damon/core.c
[ ... ]
> @@ -3248,6 +3253,16 @@ static void damon_merge_two_regions(struct damon_target *t,
[Severity: High]
This is a pre-existing issue, but can the calculations for merged regions'
weighted averages overflow on 32-bit architectures?
mm/damon/core.c:damon_merge_two_regions() {
unsigned long sz_l = damon_sz_region(l), sz_r = damon_sz_region(r);
...
l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) /
(sz_l + sz_r);
l->age = (l->age * sz_l + r->age * sz_r) / (sz_l + sz_r);
...
}
Since sz_l and sz_r are unsigned long (32 bits on 32-bit architectures),
multiplying them by a 32-bit unsigned int produces a 32-bit intermediate
product. For large region sizes, this might wrap around UINT_MAX prior to
division, leading to incorrect page reclaim decisions.
> damon_destroy_region(r, t);
> }
>
> +static unsigned int damon_merge_score(struct damon_region *r, bool last,
> + struct damon_ctx *ctx, bool use_probe_hits)
> +{
> + if (use_probe_hits)
> + return damon_probe_hits_wsum(r, last, ctx);
[Severity: Medium]
Can accumulating the weighted sums in damon_probe_hits_wsum() overflow a
32-bit integer?
mm/damon/core.c:damon_probe_hits_wsum() {
...
unsigned int sum = 0;
...
if (last)
sum += r->last_probe_hits[i++] * probe->weight;
else
sum += r->probe_hits[i++] * probe->weight;
...
}
If user space configures a large weight, multiplying it by the probe hits
across multiple probes might easily exceed UINT_MAX, causing silent
overflow. This wrapped around value would then corrupt the region merging
heuristic.
> + if (last)
> + return r->last_nr_accesses;
> + return r->nr_accesses;
> +}
> +
> /*
> * Merge adjacent regions having similar access frequencies
> *
> @@ -3256,24 +3271,38 @@ static void damon_merge_two_regions(struct damon_target *t,
> * sz_limit size upper limit of each region
> */
> static void damon_merge_regions_of(struct damon_target *t, unsigned int thres,
> - unsigned long sz_limit)
> + unsigned long sz_limit, struct damon_ctx *ctx)
> {
> struct damon_region *r, *prev = NULL, *next;
> + bool use_probe_hits = damon_has_probe_weights(ctx);
>
> damon_for_each_region_safe(r, next, t) {
> - if (abs_diff(r->nr_accesses, r->last_nr_accesses) > thres)
> + unsigned int score, last_score, diff;
> +
> + score = damon_merge_score(r, false, ctx, use_probe_hits);
> + last_score = damon_merge_score(r, true, ctx, use_probe_hits);
> +
> + if (abs_diff(score, last_score) > thres)
[Severity: Medium]
When probe weights are enabled and use_probe_hits is true, score and
last_score are scaled by probe->weight via damon_probe_hits_wsum().
However, kdamond_merge_regions() calculates the initial threshold using
unweighted access metrics. Will comparing this unscaled threshold against
the newly scaled weighted scores prevent region merges and force the retry
loop to inappropriately scale the threshold?
> r->age = 0;
> - else if ((r->nr_accesses == 0) != (r->last_nr_accesses == 0))
> + else if ((score == 0) != (last_score == 0))
> r->age = 0;
> else
> r->age++;
[Severity: High]
This is a pre-existing issue, but does mutating the region age inside this
retry loop corrupt the age metric?
In kdamond_merge_regions(), damon_merge_regions_of() is called inside a
do-while loop that repeats if nr_regions > max_nr_regions. Every time
damon_merge_regions_of() executes, it unconditionally mutates r->age for
every region based on the current threshold. Because the outer loop
doubles the threshold and retries, r->age might be artificially inflated or
repeatedly reset to 0 multiple times per aggregation interval.
[ ... ]
> diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h
> index d97280270c27b..6ad73559dd8ea 100644
> --- a/mm/damon/tests/core-kunit.h
> +++ b/mm/damon/tests/core-kunit.h
[ ... ]
> @@ -258,6 +266,7 @@ static void damon_test_merge_regions_of(struct kunit *test)
> KUNIT_EXPECT_EQ(test, r->ar.end, eaddrs[i]);
> }
[Severity: Medium]
This is a pre-existing issue, but could this test cause a NULL pointer
dereference and leak test resources?
If the internal damon_merge_regions_of logic unexpectedly merges too many
regions, damon_nr_regions(t) might fall below 6. The KUNIT_EXPECT_EQ check
logs a failure but does not halt the test.
The subsequent loop executes 6 times regardless:
mm/damon/tests/core-kunit.h:damon_test_merge_regions_of() {
...
for (i = 0; i < 6; i++) {
r = __nth_region_of(t, i);
KUNIT_EXPECT_EQ(test, r->ar.start, saddrs[i]);
...
}
This would cause __nth_region_of() to return NULL, which is immediately
dereferenced in the KUNIT_EXPECT_EQ macro without validation.
> damon_free_target(t);
> + damon_destroy_ctx(ctx);
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=8
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 10/19] mm/damon/core: validate params for probe hits weighted sum overflow
2026-07-10 13:46 ` [PATCH 10/19] mm/damon/core: validate params for probe hits weighted sum overflow SJ Park
@ 2026-07-10 14:07 ` sashiko-bot
2026-07-10 14:51 ` SJ Park
0 siblings, 1 reply; 39+ messages in thread
From: sashiko-bot @ 2026-07-10 14:07 UTC (permalink / raw)
To: SJ Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Pre-existing integer overflow in `damon_merge_two_regions()` during weighted average calculations.
- [High] Pre-existing integer overflows in `damon_sample_bp_to_count()` and `damon_sample_count_to_bp()`.
--
--- Patch [10]: [PATCH 10/19] mm/damon/core: validate params for probe hits weighted sum overflow ---
commit 74455514643a15cd1b70c8a9afa3237ba4226d34
Author: SJ Park <sj@kernel.org>
Date: Fri Jul 10 13:46:39 2026 +0000
mm/damon/core: validate params for probe hits weighted sum overflow
This commit adds parameter validation to prevent integer overflows in probe
hits weighted sum calculations. It ensures that user-configured probe weights
do not cause the weighted sum of probe hits to exceed the maximum possible
value during monitoring.
> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index 4f1425e56950b..a0e6a5129fbf3 100644
> --- a/mm/damon/core.c
> +++ b/mm/damon/core.c
> @@ -1335,6 +1335,9 @@ static void damos_set_filters_default_reject(struct damos *s)
> static bool damon_valid_probe_params(struct damon_ctx *ctx)
> {
> unsigned long sample_interval;
> + unsigned char max_probe_hits;
> + struct damon_probe *probe;
> + unsigned int wsum, wsum_to_add;
>
> if (!damon_has_probe_weights(ctx))
> return true;
> @@ -1342,6 +1345,18 @@ static bool damon_valid_probe_params(struct damon_ctx *ctx)
> sample_interval = ctx->attrs.sample_interval ? : 1;
> if (ctx->attrs.aggr_interval / sample_interval > U8_MAX)
> return false;
> +
> + /* invalid if probe hits weighted sum can overflow */
> + max_probe_hits = damon_nr_samples_per_aggr(&ctx->attrs);
> + wsum = 0;
> + damon_for_each_probe(probe, ctx) {
> + if (probe->weight > UINT_MAX / max_probe_hits)
> + return false;
> + wsum_to_add = probe->weight * max_probe_hits;
> + if (UINT_MAX - wsum < wsum_to_add)
> + return false;
> + wsum += wsum_to_add;
> + }
> return true;
> }
>
[Severity: High]
This is a pre-existing issue, but does damon_merge_two_regions() suffer from an
unsigned long overflow during average calculations?
mm/damon/core.c:damon_merge_two_regions() {
...
l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) /
(sz_l + sz_r);
l->age = (l->age * sz_l + r->age * sz_r) / (sz_l + sz_r);
...
}
During the calculation of the merged region metrics, if a region size reaches
1GB and nr_accesses is just 4, their product is 4,294,967,296. On 32-bit
architectures where unsigned long is 32 bits, this will instantly overflow.
Additionally, on 64-bit architectures, the age variable could grow indefinitely
and overflow if a region becomes very large over a long uptime. Can this lead
to corrupted statistics and misfiring of memory management actions?
[Severity: High]
This is a pre-existing issue, but I noticed a potential integer overflow in
damon_sample_bp_to_count() and damon_sample_count_to_bp():
mm/damon/core.c:damon_sample_bp_to_count() {
return bp * damon_nr_samples_per_aggr(attrs) / 10000;
}
mm/damon/core.c:damon_sample_count_to_bp() {
return mult_frac(count, 10000, damon_nr_samples_per_aggr(attrs));
}
Can these calculations overflow? The functions perform 32-bit multiplication of
bp (or the remainder in mult_frac) and the max samples using unsigned int
arithmetic.
If max_samples (aggr_interval / sample_interval) exceeds 429,496, which is
possible with a high aggregation interval compared to the sampling interval
(e.g., 5s aggregation and 10us sample intervals), the result could exceed
UINT_MAX (4,294,967,295) and silently overflow. Could this corrupt monitoring
region access counts during dynamic DAMON attribute updates?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=10
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 07/19] mm/damon/core: use abs_diff() instead of abs()
2026-07-10 13:46 ` [PATCH 07/19] mm/damon/core: use abs_diff() instead of abs() SJ Park
@ 2026-07-10 14:10 ` sashiko-bot
2026-07-10 14:43 ` SJ Park
0 siblings, 1 reply; 39+ messages in thread
From: sashiko-bot @ 2026-07-10 14:10 UTC (permalink / raw)
To: SJ Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Unchecked memory allocation failure in `damon_apply_min_nr_regions()` leads to heap corruption and infinite loops
--
--- Patch [7]: [PATCH 07/19] mm/damon/core: use abs_diff() instead of abs() ---
commit 168e2738a1f4077551ffee47ed4ecb0a582831f3
Author: SJ Park <sj@kernel.org>
mm/damon/core: use abs_diff() instead of abs()
Replaces abs() with abs_diff() in damon_merge_regions_of() to prevent
silent integer overflow when casting unsigned int to signed int.
Link: https://lore.kernel.org/20260705213817.100841-1-sj@kernel.org/
> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index fea97399b5754..4c7e8a12a9b67 100644
> --- a/mm/damon/core.c
> +++ b/mm/damon/core.c
[ ... ]
> @@ -3269,7 +3269,7 @@ static void damon_merge_regions_of(struct damon_target *t, unsigned int thres,
> r->age++;
>
> if (prev && prev->ar.end == r->ar.start &&
> - abs(prev->nr_accesses - r->nr_accesses) <= thres &&
> + abs_diff(prev->nr_accesses, r->nr_accesses) <= thres &&
> damon_sz_region(prev) + damon_sz_region(r) <= sz_limit)
> damon_merge_two_regions(t, prev, r);
> else
[Severity: Critical]
This is a pre-existing issue and was not introduced by the patch under review,
but I noticed a potential memory corruption issue in
damon_apply_min_nr_regions() when a memory allocation fails.
If damon_split_region_at() fails to allocate memory, it aborts silently and
leaves r->ar.end unchanged.
The loop then unconditionally advances r:
mm/damon/core.c:damon_apply_min_nr_regions() {
damon_for_each_target(t, ctx) {
damon_for_each_region_safe(r, next, t) {
while (damon_sz_region(r) > max_region_sz) {
damon_split_region_at(t, r, max_region_sz);
r = damon_next_region(r);
}
}
}
}
Can this corrupt memory or cause infinite loops if the allocation fails on
the last region in the list?
If this occurs on the last region in the target's list,
r = damon_next_region(r) resolves to the list head (&t->regions_list).
Because the list head is embedded inside struct damon_target, container_of()
returns a bogus struct damon_region pointer pointing before the damon_target
object.
The next iteration of the while loop would read r->ar.start and r->ar.end
from this invalid memory. If the computed difference exceeds max_region_sz,
it enters the loop again. A successful damon_split_region_at() could then
write the new region's start address to r->ar.end, corrupting memory before
the damon_target structure.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=7
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 15/19] mm/damon/core: implement damon_has_probe_weight()
2026-07-10 13:46 ` [PATCH 15/19] mm/damon/core: implement damon_has_probe_weight() SJ Park
@ 2026-07-10 14:11 ` sashiko-bot
2026-07-10 14:55 ` SJ Park
0 siblings, 1 reply; 39+ messages in thread
From: sashiko-bot @ 2026-07-10 14:11 UTC (permalink / raw)
To: SJ Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Setting probe weights unconditionally disables access checks without validating if the active operation set supports data attribute probes (`apply_probes`), silently breaking monitoring.
--
--- Patch [15]: [PATCH 15/19] mm/damon/core: implement damon_has_probe_weight() ---
commit 7b3dfd9b2d27b35cdf18598b48bc4927675cb47a
Author: SJ Park <sj@kernel.org>
mm/damon/core: implement damon_has_probe_weight()
This commit updates damon_has_probe_weights() to properly iterate over the
probes and return true if any probe has a weight configured. This enables the
data attribute monitoring mode that previously returned false intentionally
during incremental development.
> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index 91964336ce31e..806a67d02a6e9 100644
> --- a/mm/damon/core.c
> +++ b/mm/damon/core.c
> @@ -211,6 +211,12 @@ static struct damon_probe *damon_nth_probe(int n, struct damon_ctx *ctx)
>
> static bool damon_has_probe_weights(struct damon_ctx *c)
> {
> + struct damon_probe *p;
> +
> + damon_for_each_probe(p, c) {
> + if (p->weight)
> + return true;
> + }
[Severity: High]
If a user configures a DAMON context with an operation set that does not
implement apply_probes (e.g. vaddr operations) and adds a probe with a
non-zero weight, will this silently break monitoring?
With this change, damon_has_probe_weights() returning true will skip
standard access monitoring in kdamond_fn():
mm/damon/core.c:kdamond_fn() {
...
bool access_check_disabled = damon_has_probe_weights(ctx);
unsigned int max_merge_score = 0;
...
if (!access_check_disabled && ctx->ops.check_accesses)
max_merge_score = ctx->ops.check_accesses(ctx);
if (ctx->ops.apply_probes) {
/* bypassed if apply_probes is not implemented */
...
}
...
/* max_merge_score remains 0 */
if (time_after_eq(ctx->passed_sample_intervals,
next_aggregation_sis)) {
kdamond_merge_regions(ctx, max_merge_score / 10, sz_limit);
...
}
Should damon_valid_probe_params() or damon_has_probe_weights() also verify
that ctx->ops.apply_probes is implemented before allowing this mode, to
prevent kdamond_merge_regions() from unconditionally merging regions with
a threshold of 0?
> return false;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=15
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 02/19] mm/damon/core: ask apply_probes() ops callback to set sampling address
2026-07-10 13:56 ` sashiko-bot
@ 2026-07-10 14:32 ` SJ Park
0 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 14:32 UTC (permalink / raw)
To: sashiko-bot; +Cc: SJ Park, damon
On Fri, 10 Jul 2026 13:56:08 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] The `damon_pa_apply_probes` callback fails to implement the newly added `set_samples` parameter, violating the updated API operations contract.
> --
>
> --- Patch [2]: [PATCH 02/19] mm/damon/core: ask apply_probes() ops callback to set sampling address ---
> commit 2da9028945951622496aef07a601ae5bfba7972a
> Author: SJ Park <sj@kernel.org>
>
> mm/damon/core: ask apply_probes() ops callback to set sampling address
>
> This commit updates the DAMON ops callback apply_probes() to accept a
> set_samples boolean parameter. The parameter allows the callback to setup
> the sampling address per region to minimize unnecessary regions iteration.
>
> > diff --git a/include/linux/damon.h b/include/linux/damon.h
> > index d8251c83e6e55..aee28b05acc6c 100644
> > --- a/include/linux/damon.h
> > +++ b/include/linux/damon.h
> [ ... ]
> > @@ -647,7 +647,8 @@ enum damon_ops_id {
> > * It should also return max number of observed accesses that made as a result
> > * of its update. The value will be used for regions adjustment threshold.
> > * @apply_probes should apply the data attribute probes to each region and
> > - * accordingly update the probe hits counter of the region.
> > + * accordingly update the probe hits counter of the region. It should also
> > + * set &damon_region->sampling_addr of each region if ``set_samples`` is true.
> > * @get_scheme_score should return the priority score of a region for a scheme
> > * as an integer in [0, &DAMOS_MAX_SCORE].
> > * @apply_scheme is called from @kdamond when a region for user provided
>
> [ ... ]
>
> > diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
> > index 6172464981730..b13bf7c6eade3 100644
> > --- a/mm/damon/paddr.c
> > +++ b/mm/damon/paddr.c
> [ ... ]
> > @@ -166,7 +166,7 @@ static bool damon_pa_filter_pass(phys_addr_t pa, struct folio *folio,
> > return pass;
> > }
> >
> > -static void damon_pa_apply_probes(struct damon_ctx *ctx)
> > +static void damon_pa_apply_probes(struct damon_ctx *ctx, bool set_samples)
> > {
> > struct damon_target *t;
> > struct damon_region *r;
>
> [Severity: Medium]
> Will callers passing set_samples=true end up using stale sampling addresses?
>
> The documentation in include/linux/damon.h states that apply_probes should
> set &damon_region->sampling_addr if set_samples is true.
>
> However, the updated damon_pa_apply_probes() does not seem to handle the
> new parameter:
>
> mm/damon/paddr.c:damon_pa_apply_probes() {
> ...
> damon_for_each_region(r, t) {
> int i = 0;
> phys_addr_t pa;
> struct folio *folio;
>
> pa = damon_pa_phys_addr(r->sampling_addr,
> ctx->addr_unit);
> ...
> }
>
> It reads the existing r->sampling_addr without generating a new random address
> when set_samples is true.
No issue since no caller sets set_samples true.
And a later patch in this series will respect the argument before a caller sets
it true.
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=2
Thanks,
SJ
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 03/19] mm/damon/paddr: set samples in apply_probes() if requested
2026-07-10 14:01 ` sashiko-bot
@ 2026-07-10 14:33 ` SJ Park
0 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 14:33 UTC (permalink / raw)
To: sashiko-bot; +Cc: SJ Park, damon
On Fri, 10 Jul 2026 14:01:55 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] Address advancement using `folio_size()` from an unaligned address within a large folio overshoots the next folio.
> --
>
> --- Patch [3]: [PATCH 03/19] mm/damon/paddr: set samples in apply_probes() if requested ---
> commit 60a9acbe070a2be34c313d6be62fe7e4acb7ec54
> Author: SJ Park <sj@kernel.org>
>
> mm/damon/paddr: set samples in apply_probes() if requested
>
> This commit updates damon_pa_apply_probes() to respect the set_samples
> parameter. It adds logic to randomize the sampling address within the
> region boundaries using damon_rand() when requested.
>
> > diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
> > index b13bf7c6eade3..ff4fcca949660 100644
> > --- a/mm/damon/paddr.c
> > +++ b/mm/damon/paddr.c
> > @@ -178,6 +178,10 @@ static void damon_pa_apply_probes(struct damon_ctx *ctx, bool set_samples)
> > phys_addr_t pa;
> > struct folio *folio;
> >
> > + if (set_samples)
> > + r->sampling_addr = damon_rand(ctx, r->ar.start,
> > + r->ar.end);
> > +
> > pa = damon_pa_phys_addr(r->sampling_addr,
> > ctx->addr_unit);
> > folio = damon_get_folio(PHYS_PFN(pa));
>
> [Severity: High]
> This is a pre-existing issue in this file, but can the address advancement
> logic skip over pages during region iteration?
>
> Looking at iteration functions like damon_pa_pageout(),
> damon_pa_de_activate(), damon_pa_migrate(), and damon_pa_stat() in
> mm/damon/paddr.c, they all use a pattern for advancing the address
> similar to this:
>
> mm/damon/paddr.c:damon_pa_pageout() {
> ...
> folio = damon_get_folio(PHYS_PFN(addr));
> if (!folio) {
> addr += PAGE_SIZE;
> continue;
> }
> ...
> addr += folio_size(folio);
> ...
> }
>
> If the initial iteration address is not aligned to the folio boundary (for
> example, after a region split or hole), wouldn't adding the full folio size
> to this unaligned address cause it to overshoot the end of the current folio?
>
> This seems like it would skip over the beginning of the next physical folio,
> causing those pages to incorrectly escape reclaim, migration, or statistics
> gathering.
Known issue. I'm working on it. No blocker of this patch.
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=3
Thanks,
SJ
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 04/19] mm/damon/core: ask apply_probe() to return max probe hits weighted sum
2026-07-10 14:01 ` sashiko-bot
@ 2026-07-10 14:35 ` SJ Park
0 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 14:35 UTC (permalink / raw)
To: sashiko-bot; +Cc: SJ Park, damon
On Fri, 10 Jul 2026 14:01:19 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] The apply_probes callback fails to calculate and return the maximum probe hits weighted sum, unconditionally returning 0.
> --
>
> --- Patch [4]: [PATCH 04/19] mm/damon/core: ask apply_probe() to return max probe hits weighted sum ---
> commit bb862935a31b8d93d0e79b24c1d5bb92b5faf39a
> Author: SJ Park <sj@kernel.org>
>
> mm/damon/core: ask apply_probe() to return max probe hits weighted sum
>
> This commit updates the DAMON operations protocol to allow the apply_probes
> callback to calculate and return the maximum probe hits weighted sum. It
> modifies the function signature to take a return_max_wsum parameter and
> updates the existing implementation in damon_pa_apply_probes() to return
> an unsigned int.
>
> > diff --git a/include/linux/damon.h b/include/linux/damon.h
> > index aee28b05acc6c..e7acd8e610a64 100644
> > --- a/include/linux/damon.h
> > +++ b/include/linux/damon.h
> [ ... ]
> > @@ -649,6 +649,8 @@ enum damon_ops_id {
> > * @apply_probes should apply the data attribute probes to each region and
> > * accordingly update the probe hits counter of the region. It should also
> > * set &damon_region->sampling_addr of each region if ``set_samples`` is true.
> > + * It should also return maximum probe hits weighted sum of regions if
> > + * ``return_max_wsum`` is true.
> > * @get_scheme_score should return the priority score of a region for a scheme
> > * as an integer in [0, &DAMOS_MAX_SCORE].
> > * @apply_scheme is called from @kdamond when a region for user provided
>
> [ ... ]
>
> > diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
> > index ff4fcca949660..3eba3564a31fc 100644
> > --- a/mm/damon/paddr.c
> > +++ b/mm/damon/paddr.c
> [ ... ]
> > @@ -166,7 +166,8 @@ static bool damon_pa_filter_pass(phys_addr_t pa, struct folio *folio,
> > return pass;
> > }
> >
> > -static void damon_pa_apply_probes(struct damon_ctx *ctx, bool set_samples)
> > +static unsigned int damon_pa_apply_probes(struct damon_ctx *ctx,
> > + bool set_samples, bool return_max_wsum)
> > {
> > struct damon_target *t;
> > struct damon_region *r;
> [ ... ]
> > @@ -194,6 +195,7 @@ static void damon_pa_apply_probes(struct damon_ctx *ctx, bool set_samples)
> > folio_put(folio);
> > }
> > }
> > + return 0;
> > }
>
> [Severity: Medium]
> Will this unconditionally return 0 even when return_max_wsum is true?
>
> The struct documentation states the callback should return the maximum probe
> hits weighted sum of regions if return_max_wsum is true. However, the
> implementation in damon_pa_apply_probes() simply returns 0 at the end
> without computing the weighted sum.
>
> Should the maximum weighted sum calculation be implemented here to fulfill
> the updated protocol?
No issue. No caller sets return_max_wsum true at this moment.
And a later patch in this series will make the argument be respected before
someone sets it true.
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=4
Thanks,
SJ
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 07/19] mm/damon/core: use abs_diff() instead of abs()
2026-07-10 14:10 ` sashiko-bot
@ 2026-07-10 14:43 ` SJ Park
0 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 14:43 UTC (permalink / raw)
To: sashiko-bot; +Cc: SJ Park, damon
On Fri, 10 Jul 2026 14:10:54 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [Critical] Unchecked memory allocation failure in `damon_apply_min_nr_regions()` leads to heap corruption and infinite loops
> --
>
> --- Patch [7]: [PATCH 07/19] mm/damon/core: use abs_diff() instead of abs() ---
> commit 168e2738a1f4077551ffee47ed4ecb0a582831f3
> Author: SJ Park <sj@kernel.org>
>
> mm/damon/core: use abs_diff() instead of abs()
>
> Replaces abs() with abs_diff() in damon_merge_regions_of() to prevent
> silent integer overflow when casting unsigned int to signed int.
>
> Link: https://lore.kernel.org/20260705213817.100841-1-sj@kernel.org/
>
> > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > index fea97399b5754..4c7e8a12a9b67 100644
> > --- a/mm/damon/core.c
> > +++ b/mm/damon/core.c
> [ ... ]
> > @@ -3269,7 +3269,7 @@ static void damon_merge_regions_of(struct damon_target *t, unsigned int thres,
> > r->age++;
> >
> > if (prev && prev->ar.end == r->ar.start &&
> > - abs(prev->nr_accesses - r->nr_accesses) <= thres &&
> > + abs_diff(prev->nr_accesses, r->nr_accesses) <= thres &&
> > damon_sz_region(prev) + damon_sz_region(r) <= sz_limit)
> > damon_merge_two_regions(t, prev, r);
> > else
>
> [Severity: Critical]
> This is a pre-existing issue and was not introduced by the patch under review,
> but I noticed a potential memory corruption issue in
> damon_apply_min_nr_regions() when a memory allocation fails.
>
> If damon_split_region_at() fails to allocate memory, it aborts silently and
> leaves r->ar.end unchanged.
>
> The loop then unconditionally advances r:
>
> mm/damon/core.c:damon_apply_min_nr_regions() {
> damon_for_each_target(t, ctx) {
> damon_for_each_region_safe(r, next, t) {
> while (damon_sz_region(r) > max_region_sz) {
> damon_split_region_at(t, r, max_region_sz);
> r = damon_next_region(r);
> }
> }
> }
> }
>
> Can this corrupt memory or cause infinite loops if the allocation fails on
> the last region in the list?
>
> If this occurs on the last region in the target's list,
> r = damon_next_region(r) resolves to the list head (&t->regions_list).
>
> Because the list head is embedded inside struct damon_target, container_of()
> returns a bogus struct damon_region pointer pointing before the damon_target
> object.
>
> The next iteration of the while loop would read r->ar.start and r->ar.end
> from this invalid memory. If the computed difference exceeds max_region_sz,
> it enters the loop again. A successful damon_split_region_at() could then
> write the new region's start address to r->ar.end, corrupting memory before
> the damon_target structure.
Good finding. Not a blocker of this patch, though. I will separately work on
this.
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=7
Thanks,
SJ
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 08/19] mm/damon/core: extend merge function to work with probe hits
2026-07-10 14:05 ` sashiko-bot
@ 2026-07-10 14:49 ` SJ Park
0 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 14:49 UTC (permalink / raw)
To: sashiko-bot; +Cc: SJ Park, damon
On Fri, 10 Jul 2026 14:05:31 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
>
> New issues:
> - [Medium] Unscaled merge threshold breaks region merging when using weighted probe hits.
> - [Medium] Potential 32-bit integer overflow in `damon_probe_hits_wsum()` when accumulating weighted sums.
>
> Pre-existing issues:
> - [High] Region ages are evaluated and mutated inside a retry loop, leading to age corruption.
> - [High] Calculations for merged regions' weighted averages overflow on 32-bit architectures.
> - [Medium] Test NULL pointer dereference in `damon_test_merge_regions_of`.
> --
>
> --- Patch [8]: [PATCH 08/19] mm/damon/core: extend merge function to work with probe hits ---
> commit 5e9a094bb8d36feea59f27615cb45bcbce00e4c3
> Author: SJ Park <sj@kernel.org>
>
> mm/damon/core: extend merge function to work with probe hits
>
> When probe weights are set, users may want DAMON monitoring results to
> be optimized for the weights. For that, regions adjustment should work
> for the weighted sum of probe hits. Extend damon_merge_regions_of() to
> detect if the weights are set, and work with probe hits in the case.
>
> > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > index 4c7e8a12a9b67..7d49420ea26c4 100644
> > --- a/mm/damon/core.c
> > +++ b/mm/damon/core.c
> [ ... ]
> > @@ -3248,6 +3253,16 @@ static void damon_merge_two_regions(struct damon_target *t,
> [Severity: High]
> This is a pre-existing issue, but can the calculations for merged regions'
> weighted averages overflow on 32-bit architectures?
>
> mm/damon/core.c:damon_merge_two_regions() {
> unsigned long sz_l = damon_sz_region(l), sz_r = damon_sz_region(r);
> ...
> l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) /
> (sz_l + sz_r);
> l->age = (l->age * sz_l + r->age * sz_r) / (sz_l + sz_r);
> ...
> }
>
> Since sz_l and sz_r are unsigned long (32 bits on 32-bit architectures),
> multiplying them by a 32-bit unsigned int produces a 32-bit intermediate
> product. For large region sizes, this might wrap around UINT_MAX prior to
> division, leading to incorrect page reclaim decisions.
Known low priority issue. No blocker.
>
> > damon_destroy_region(r, t);
> > }
> >
> > +static unsigned int damon_merge_score(struct damon_region *r, bool last,
> > + struct damon_ctx *ctx, bool use_probe_hits)
> > +{
> > + if (use_probe_hits)
> > + return damon_probe_hits_wsum(r, last, ctx);
> [Severity: Medium]
> Can accumulating the weighted sums in damon_probe_hits_wsum() overflow a
> 32-bit integer?
>
> mm/damon/core.c:damon_probe_hits_wsum() {
> ...
> unsigned int sum = 0;
> ...
> if (last)
> sum += r->last_probe_hits[i++] * probe->weight;
> else
> sum += r->probe_hits[i++] * probe->weight;
> ...
> }
>
> If user space configures a large weight, multiplying it by the probe hits
> across multiple probes might easily exceed UINT_MAX, causing silent
> overflow. This wrapped around value would then corrupt the region merging
> heuristic.
No issue. Nobody calls this function at the moment. A later patch in this
series will prevent such user input before this can be really used.
>
> > + if (last)
> > + return r->last_nr_accesses;
> > + return r->nr_accesses;
> > +}
> > +
> > /*
> > * Merge adjacent regions having similar access frequencies
> > *
> > @@ -3256,24 +3271,38 @@ static void damon_merge_two_regions(struct damon_target *t,
> > * sz_limit size upper limit of each region
> > */
> > static void damon_merge_regions_of(struct damon_target *t, unsigned int thres,
> > - unsigned long sz_limit)
> > + unsigned long sz_limit, struct damon_ctx *ctx)
> > {
> > struct damon_region *r, *prev = NULL, *next;
> > + bool use_probe_hits = damon_has_probe_weights(ctx);
> >
> > damon_for_each_region_safe(r, next, t) {
> > - if (abs_diff(r->nr_accesses, r->last_nr_accesses) > thres)
> > + unsigned int score, last_score, diff;
> > +
> > + score = damon_merge_score(r, false, ctx, use_probe_hits);
> > + last_score = damon_merge_score(r, true, ctx, use_probe_hits);
> > +
> > + if (abs_diff(score, last_score) > thres)
> [Severity: Medium]
> When probe weights are enabled and use_probe_hits is true, score and
> last_score are scaled by probe->weight via damon_probe_hits_wsum().
> However, kdamond_merge_regions() calculates the initial threshold using
> unweighted access metrics. Will comparing this unscaled threshold against
> the newly scaled weighted scores prevent region merges and force the retry
> loop to inappropriately scale the threshold?
No issue. damon_has_probe_weights() always return false. A later patch in
this series will change that before damon_has_probe_weights() can return true.
>
> > r->age = 0;
> > - else if ((r->nr_accesses == 0) != (r->last_nr_accesses == 0))
> > + else if ((score == 0) != (last_score == 0))
> > r->age = 0;
> > else
> > r->age++;
> [Severity: High]
> This is a pre-existing issue, but does mutating the region age inside this
> retry loop corrupt the age metric?
>
> In kdamond_merge_regions(), damon_merge_regions_of() is called inside a
> do-while loop that repeats if nr_regions > max_nr_regions. Every time
> damon_merge_regions_of() executes, it unconditionally mutates r->age for
> every region based on the current threshold. Because the outer loop
> doubles the threshold and retries, r->age might be artificially inflated or
> repeatedly reset to 0 multiple times per aggregation interval.
Known issue. I'm working on this.
>
> [ ... ]
> > diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h
> > index d97280270c27b..6ad73559dd8ea 100644
> > --- a/mm/damon/tests/core-kunit.h
> > +++ b/mm/damon/tests/core-kunit.h
> [ ... ]
> > @@ -258,6 +266,7 @@ static void damon_test_merge_regions_of(struct kunit *test)
> > KUNIT_EXPECT_EQ(test, r->ar.end, eaddrs[i]);
> > }
> [Severity: Medium]
> This is a pre-existing issue, but could this test cause a NULL pointer
> dereference and leak test resources?
>
> If the internal damon_merge_regions_of logic unexpectedly merges too many
> regions, damon_nr_regions(t) might fall below 6. The KUNIT_EXPECT_EQ check
> logs a failure but does not halt the test.
>
> The subsequent loop executes 6 times regardless:
>
> mm/damon/tests/core-kunit.h:damon_test_merge_regions_of() {
> ...
> for (i = 0; i < 6; i++) {
> r = __nth_region_of(t, i);
> KUNIT_EXPECT_EQ(test, r->ar.start, saddrs[i]);
> ...
> }
>
> This would cause __nth_region_of() to return NULL, which is immediately
> dereferenced in the KUNIT_EXPECT_EQ macro without validation.
Good catch. No blocker, though. I will separately work on this.
>
> > damon_free_target(t);
> > + damon_destroy_ctx(ctx);
> > }
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=8
Thanks,
SJ
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 10/19] mm/damon/core: validate params for probe hits weighted sum overflow
2026-07-10 14:07 ` sashiko-bot
@ 2026-07-10 14:51 ` SJ Park
0 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 14:51 UTC (permalink / raw)
To: sashiko-bot; +Cc: SJ Park, damon
On Fri, 10 Jul 2026 14:07:43 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] Pre-existing integer overflow in `damon_merge_two_regions()` during weighted average calculations.
> - [High] Pre-existing integer overflows in `damon_sample_bp_to_count()` and `damon_sample_count_to_bp()`.
> --
>
> --- Patch [10]: [PATCH 10/19] mm/damon/core: validate params for probe hits weighted sum overflow ---
> commit 74455514643a15cd1b70c8a9afa3237ba4226d34
> Author: SJ Park <sj@kernel.org>
> Date: Fri Jul 10 13:46:39 2026 +0000
>
> mm/damon/core: validate params for probe hits weighted sum overflow
>
> This commit adds parameter validation to prevent integer overflows in probe
> hits weighted sum calculations. It ensures that user-configured probe weights
> do not cause the weighted sum of probe hits to exceed the maximum possible
> value during monitoring.
>
> > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > index 4f1425e56950b..a0e6a5129fbf3 100644
> > --- a/mm/damon/core.c
> > +++ b/mm/damon/core.c
> > @@ -1335,6 +1335,9 @@ static void damos_set_filters_default_reject(struct damos *s)
> > static bool damon_valid_probe_params(struct damon_ctx *ctx)
> > {
> > unsigned long sample_interval;
> > + unsigned char max_probe_hits;
> > + struct damon_probe *probe;
> > + unsigned int wsum, wsum_to_add;
> >
> > if (!damon_has_probe_weights(ctx))
> > return true;
> > @@ -1342,6 +1345,18 @@ static bool damon_valid_probe_params(struct damon_ctx *ctx)
> > sample_interval = ctx->attrs.sample_interval ? : 1;
> > if (ctx->attrs.aggr_interval / sample_interval > U8_MAX)
> > return false;
> > +
> > + /* invalid if probe hits weighted sum can overflow */
> > + max_probe_hits = damon_nr_samples_per_aggr(&ctx->attrs);
> > + wsum = 0;
> > + damon_for_each_probe(probe, ctx) {
> > + if (probe->weight > UINT_MAX / max_probe_hits)
> > + return false;
> > + wsum_to_add = probe->weight * max_probe_hits;
> > + if (UINT_MAX - wsum < wsum_to_add)
> > + return false;
> > + wsum += wsum_to_add;
> > + }
> > return true;
> > }
> >
>
> [Severity: High]
> This is a pre-existing issue, but does damon_merge_two_regions() suffer from an
> unsigned long overflow during average calculations?
>
> mm/damon/core.c:damon_merge_two_regions() {
> ...
> l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) /
> (sz_l + sz_r);
> l->age = (l->age * sz_l + r->age * sz_r) / (sz_l + sz_r);
> ...
> }
>
> During the calculation of the merged region metrics, if a region size reaches
> 1GB and nr_accesses is just 4, their product is 4,294,967,296. On 32-bit
> architectures where unsigned long is 32 bits, this will instantly overflow.
>
> Additionally, on 64-bit architectures, the age variable could grow indefinitely
> and overflow if a region becomes very large over a long uptime. Can this lead
> to corrupted statistics and misfiring of memory management actions?
Known low priority issue.
>
>
> [Severity: High]
> This is a pre-existing issue, but I noticed a potential integer overflow in
> damon_sample_bp_to_count() and damon_sample_count_to_bp():
>
> mm/damon/core.c:damon_sample_bp_to_count() {
> return bp * damon_nr_samples_per_aggr(attrs) / 10000;
> }
>
> mm/damon/core.c:damon_sample_count_to_bp() {
> return mult_frac(count, 10000, damon_nr_samples_per_aggr(attrs));
> }
>
> Can these calculations overflow? The functions perform 32-bit multiplication of
> bp (or the remainder in mult_frac) and the max samples using unsigned int
> arithmetic.
>
> If max_samples (aggr_interval / sample_interval) exceeds 429,496, which is
> possible with a high aggregation interval compared to the sampling interval
> (e.g., 5s aggregation and 10us sample intervals), the result could exceed
> UINT_MAX (4,294,967,295) and silently overflow. Could this corrupt monitoring
> region access counts during dynamic DAMON attribute updates?
Known low priority issue.
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=10
Thanks,
SJ
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 12/19] mm/damon/core: set samples in apply_probes() if probe weights are set
2026-07-10 14:02 ` sashiko-bot
@ 2026-07-10 14:52 ` SJ Park
0 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 14:52 UTC (permalink / raw)
To: sashiko-bot; +Cc: SJ Park, damon
On Fri, 10 Jul 2026 14:02:54 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] kdamond_merge_regions() uses a stale or 0 threshold (max_nr_accesses) when probe weights are set, preventing proper region merging.
> --
>
> --- Patch [12]: [PATCH 12/19] mm/damon/core: set samples in apply_probes() if probe weights are set ---
> commit c57b42d6ad5d1b962d67f040aa171492d081c859
> Author: SJ Park <sj@kernel.org>
>
> mm/damon/core: set samples in apply_probes() if probe weights are set
>
> When probe weights are set, the prepare_access_checks() ops callback is
> not invoked, so sampling addresses of regions are unset. Ask apply_probes()
> to set those together in the case.
>
> > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > index 65f91e3b58d2e..dd0612e1a408b 100644
> > --- a/mm/damon/core.c
> > +++ b/mm/damon/core.c
> > @@ -3777,7 +3777,8 @@ static int kdamond_fn(void *data)
> > if (!access_check_disabled && ctx->ops.check_accesses)
> > max_nr_accesses = ctx->ops.check_accesses(ctx);
> > if (ctx->ops.apply_probes)
> > - ctx->ops.apply_probes(ctx, false, false);
> > + ctx->ops.apply_probes(ctx, access_check_disabled,
> > + false);
> >
> > if (time_after_eq(ctx->passed_sample_intervals,
> > next_aggregation_sis)) {
>
> [Severity: Medium]
> When access_check_disabled is true, ctx->ops.check_accesses() is skipped.
> Does this leave max_nr_accesses stale or set to 0 when it is subsequently
> passed to kdamond_merge_regions() shortly after this block?
>
> If max_nr_accesses evaluates to 0, it seems this might defeat the 10 percent
> tolerance logic for region aggregation.
>
> Could this force adjacent regions to merge only when their scores match
> exactly, leading to region fragmentation until the maximum region limit
> is hit?
>
> Since damon_has_probe_weights() currently returns false unconditionally
> to safely stage the new feature, this appears to be unreachable today, but
> might become a regression once the feature is fully enabled.
No issue. access_check_disabled is always false at this moment. A later patch
in this series will avoid the issue before it can be true.
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=12
Thanks,
SJ
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 14/19] mm/damon/core: get merge threshold from probe hits when weights are set
2026-07-10 14:05 ` sashiko-bot
@ 2026-07-10 14:54 ` SJ Park
0 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 14:54 UTC (permalink / raw)
To: sashiko-bot; +Cc: SJ Park, damon
On Fri, 10 Jul 2026 14:05:10 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [Medium] Silent monitoring failure when probe weights are set on operations lacking apply_probes.
> - [Medium] kdamond_merge_regions loop termination condition still uses unweighted access frequency as max_thres.
> --
>
> --- Patch [14]: [PATCH 14/19] mm/damon/core: get merge threshold from probe hits when weights are set ---
> commit 0b09a73e4b353610f5bc3d4f305131a2f9d7fea8
> Author: SJ Park <sj@kernel.org>
>
> mm/damon/core: get merge threshold from probe hits when weights are set
>
> When probe weights are set, DAMON merges regions based on their probe
> hits weighted sum. But the merge threshold is calculated based on the
> access frequency. Update it to retrieve the maximum probe hits weighted
> sum in the snapshot from apply_probes() ops callback, and generate the
> threshold based on it.
>
> > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > index f7782c69037da..91964336ce31e 100644
> > --- a/mm/damon/core.c
> > +++ b/mm/damon/core.c
> > @@ -3776,9 +3777,18 @@ static int kdamond_fn(void *data)
> >
> > if (!access_check_disabled && ctx->ops.check_accesses)
> > max_merge_score = ctx->ops.check_accesses(ctx);
> > - if (ctx->ops.apply_probes)
> > - ctx->ops.apply_probes(ctx, access_check_disabled,
> > - false);
> > + if (ctx->ops.apply_probes) {
>
> [Severity: Medium]
> If a user configures a DAMON context with ops that lack apply_probes
> (such as vaddr), adds a probe with a weight, and starts monitoring,
> could this result in a silent monitoring failure?
>
> Since damon_valid_probe_params() allows this configuration:
>
> mm/damon/core.c:damon_valid_probe_params() {
> ...
> return true;
> }
>
> access_check_disabled will be true, causing check_accesses() to be
> skipped. With ctx->ops.apply_probes being NULL, no monitoring data
> would be collected and max_merge_score would remain 0.
Intentional behavior. No issue.
>
> > + if (time_after_eq(ctx->passed_sample_intervals,
> > + next_aggregation_sis) &&
> > + access_check_disabled)
> > + get_max_wsum = true;
> > + else
> > + get_max_wsum = false;
> > + max_wsum = ctx->ops.apply_probes(ctx,
> > + access_check_disabled, get_max_wsum);
> > + if (get_max_wsum)
> > + max_merge_score = max_wsum;
> > + }
> >
> > if (time_after_eq(ctx->passed_sample_intervals,
> > next_aggregation_sis)) {
>
> [Severity: Medium]
> When kdamond_merge_regions() is called with this new max_merge_score based
> on weighted probe hits, could the fallback loop terminate prematurely?
>
> mm/damon/core.c:kdamond_fn() {
> ...
> kdamond_merge_regions(ctx,
> max_merge_score / 10,
> sz_limit);
> ...
> }
>
> Looking at kdamond_merge_regions(), max_thres is hardcoded to the
> unweighted maximum access frequency:
>
> mm/damon/core.c:kdamond_merge_regions() {
> max_thres = c->attrs.aggr_interval /
> (c->attrs.sample_interval ? c->attrs.sample_interval : 1);
> do {
> ...
> } while (nr_regions > c->attrs.max_nr_regions &&
> threshold / 2 < max_thres);
> }
>
> If a user sets a probe weight such that max_merge_score / 10 > max_thres * 2,
> the loop condition threshold / 2 < max_thres will evaluate to false immediately,
> failing to enforce the max_nr_regions limit during region merging.
Known issue. I'm separately working on it.
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=14
Thanks,
SJ
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 15/19] mm/damon/core: implement damon_has_probe_weight()
2026-07-10 14:11 ` sashiko-bot
@ 2026-07-10 14:55 ` SJ Park
0 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 14:55 UTC (permalink / raw)
To: sashiko-bot; +Cc: SJ Park, damon
On Fri, 10 Jul 2026 14:11:00 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] Setting probe weights unconditionally disables access checks without validating if the active operation set supports data attribute probes (`apply_probes`), silently breaking monitoring.
> --
>
> --- Patch [15]: [PATCH 15/19] mm/damon/core: implement damon_has_probe_weight() ---
> commit 7b3dfd9b2d27b35cdf18598b48bc4927675cb47a
> Author: SJ Park <sj@kernel.org>
>
> mm/damon/core: implement damon_has_probe_weight()
>
> This commit updates damon_has_probe_weights() to properly iterate over the
> probes and return true if any probe has a weight configured. This enables the
> data attribute monitoring mode that previously returned false intentionally
> during incremental development.
>
> > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > index 91964336ce31e..806a67d02a6e9 100644
> > --- a/mm/damon/core.c
> > +++ b/mm/damon/core.c
> > @@ -211,6 +211,12 @@ static struct damon_probe *damon_nth_probe(int n, struct damon_ctx *ctx)
> >
> > static bool damon_has_probe_weights(struct damon_ctx *c)
> > {
> > + struct damon_probe *p;
> > +
> > + damon_for_each_probe(p, c) {
> > + if (p->weight)
> > + return true;
> > + }
>
> [Severity: High]
> If a user configures a DAMON context with an operation set that does not
> implement apply_probes (e.g. vaddr operations) and adds a probe with a
> non-zero weight, will this silently break monitoring?
>
> With this change, damon_has_probe_weights() returning true will skip
> standard access monitoring in kdamond_fn():
>
> mm/damon/core.c:kdamond_fn() {
> ...
> bool access_check_disabled = damon_has_probe_weights(ctx);
> unsigned int max_merge_score = 0;
> ...
> if (!access_check_disabled && ctx->ops.check_accesses)
> max_merge_score = ctx->ops.check_accesses(ctx);
>
> if (ctx->ops.apply_probes) {
> /* bypassed if apply_probes is not implemented */
> ...
> }
> ...
> /* max_merge_score remains 0 */
> if (time_after_eq(ctx->passed_sample_intervals,
> next_aggregation_sis)) {
> kdamond_merge_regions(ctx, max_merge_score / 10, sz_limit);
> ...
> }
>
> Should damon_valid_probe_params() or damon_has_probe_weights() also verify
> that ctx->ops.apply_probes is implemented before allowing this mode, to
> prevent kdamond_merge_regions() from unconditionally merging regions with
> a threshold of 0?
No issue. This is an intentional behavior.
>
> > return false;
> > }
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260710134651.18084-1-sj@kernel.org?part=15
Thanks,
SJ
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 00/19] mm/damon: introduce data attributes only monitoring
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
` (18 preceding siblings ...)
2026-07-10 13:46 ` [PATCH 19/19] Docs/ABI/damon: document probe weight file SJ Park
@ 2026-07-10 14:59 ` SJ Park
19 siblings, 0 replies; 39+ messages in thread
From: SJ Park @ 2026-07-10 14:59 UTC (permalink / raw)
To: SJ Park
Cc: Andrew Morton, Liam R. Howlett, David Hildenbrand,
Jonathan Corbet, Lorenzo Stoakes, Michal Hocko, Mike Rapoport,
Shuah Khan, Suren Baghdasaryan, Vlastimil Babka, damon, linux-doc,
linux-kernel, linux-mm
On Fri, 10 Jul 2026 06:46:29 -0700 SJ Park <sj@kernel.org> wrote:
> TL;DR: Introduce a way to get DAMON's best effort accuracy monitoring of
> user-demanding non-access data attributes.
Sashiko found no blocker for this series. Sashiko sent findings to damon@
mailing list [1], and I replied to all the comments. Please read those for
details.
[1] https://lore.kernel.org/damon/
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 39+ messages in thread
end of thread, other threads:[~2026-07-10 14:59 UTC | newest]
Thread overview: 39+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-10 13:46 [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
2026-07-10 13:46 ` [PATCH 01/19] mm/damon/core: introduce damon_probe->weight SJ Park
2026-07-10 13:46 ` [PATCH 02/19] mm/damon/core: ask apply_probes() ops callback to set sampling address SJ Park
2026-07-10 13:56 ` sashiko-bot
2026-07-10 14:32 ` SJ Park
2026-07-10 13:46 ` [PATCH 03/19] mm/damon/paddr: set samples in apply_probes() if requested SJ Park
2026-07-10 14:01 ` sashiko-bot
2026-07-10 14:33 ` SJ Park
2026-07-10 13:46 ` [PATCH 04/19] mm/damon/core: ask apply_probe() to return max probe hits weighted sum SJ Park
2026-07-10 14:01 ` sashiko-bot
2026-07-10 14:35 ` SJ Park
2026-07-10 13:46 ` [PATCH 05/19] mm/damon/core: implement damon_probe_hits_wsum() SJ Park
2026-07-10 13:46 ` [PATCH 06/19] mm/damon/paddr: respect return_max_wsum SJ Park
2026-07-10 13:46 ` [PATCH 07/19] mm/damon/core: use abs_diff() instead of abs() SJ Park
2026-07-10 14:10 ` sashiko-bot
2026-07-10 14:43 ` SJ Park
2026-07-10 13:46 ` [PATCH 08/19] mm/damon/core: extend merge function to work with probe hits SJ Park
2026-07-10 14:05 ` sashiko-bot
2026-07-10 14:49 ` SJ Park
2026-07-10 13:46 ` [PATCH 09/19] mm/damon/core: disallow probe_hits overflow on attrs only monitoring SJ Park
2026-07-10 13:46 ` [PATCH 10/19] mm/damon/core: validate params for probe hits weighted sum overflow SJ Park
2026-07-10 14:07 ` sashiko-bot
2026-07-10 14:51 ` SJ Park
2026-07-10 13:46 ` [PATCH 11/19] mm/damon/core: disable access monitoring when probe weights are set SJ Park
2026-07-10 13:46 ` [PATCH 12/19] mm/damon/core: set samples in apply_probes() if " SJ Park
2026-07-10 14:02 ` sashiko-bot
2026-07-10 14:52 ` SJ Park
2026-07-10 13:46 ` [PATCH 13/19] mm/damon/core: s/max_nr_accesses/max_merge_score/ in kdamond_fn() SJ Park
2026-07-10 13:46 ` [PATCH 14/19] mm/damon/core: get merge threshold from probe hits when weights are set SJ Park
2026-07-10 14:05 ` sashiko-bot
2026-07-10 14:54 ` SJ Park
2026-07-10 13:46 ` [PATCH 15/19] mm/damon/core: implement damon_has_probe_weight() SJ Park
2026-07-10 14:11 ` sashiko-bot
2026-07-10 14:55 ` SJ Park
2026-07-10 13:46 ` [PATCH 16/19] mm/damon/sysfs: implement probe/weight file SJ Park
2026-07-10 13:46 ` [PATCH 17/19] Docs/mm/damon/design: document attrs-only monitoring SJ Park
2026-07-10 13:46 ` [PATCH 18/19] Docs/admin-guide/mm/damon/usage: document weight sysfs file SJ Park
2026-07-10 13:46 ` [PATCH 19/19] Docs/ABI/damon: document probe weight file SJ Park
2026-07-10 14:59 ` [PATCH 00/19] mm/damon: introduce data attributes only monitoring SJ Park
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox