* [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring
@ 2026-05-16 18:36 SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 01/28] mm/damon/core: introduce struct damon_probe SeongJae Park
` (29 more replies)
0 siblings, 30 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Liam R. Howlett, Andrew Morton, David Hildenbrand,
Jonathan Corbet, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Mike Rapoport, Shuah Khan,
Shuah Khan, Steven Rostedt, Suren Baghdasaryan, Vlastimil Babka,
damon, linux-doc, linux-kernel, linux-kselftest, linux-mm,
linux-trace-kernel
TL; DR
======
Extend DAMON for monitoring general data attributes other than accesses.
The short term motivation is lightweight page type (e.g., belonging
cgroup) aware monitoring. In long term, this will help extending DAMON
for multiple access events capture primitives (e.g., page faults and
PMU) and eventually pivotting DAMON to a "Data Attributes Monitoring and
Operations eNgine" in long term.
Background: High Cost of Page Level Properties Monitoring
=========================================================
DAMON is initially introduced as a Data Access MONitor. It has been
extended for not only access monitoring but also data access-aware
system operations (DAMOS). But still the monitoring part is only for
data accesses.
Data access patterns is good information, but some users need more
holistic views. Particularly, users want to show the access pattern
information together with the types of the memory. For example, users
who work for making huge pages efficiently want to know how much of
DAMON-found hot/cold regions are backed by huge pages. Users who run
multiple workloads with different cgroups want to know how much of
DAMON-found hot/cold regions belong to specific cgroups.
For the user demand, we developed a DAMOS extension for page level
properties based monitoring [1], which has landed on 6.14. Using the
feature, users can inform the page level data properties that they are
interested in, in a flexible format that uses DAMOS filters. Then,
DAMON applies the filters to each folio of the entire DAMON region and
lets users know how many bytes of memory in each DAMON region passed the
given filters.
This gives page level detailed and deterministic information to users.
But, because the operation is done at page level, the overhead is
proportional to the memory size. It was useful for test or debugging
purposes on a small number of machines. But it was obviously too heavy
to be enabled always on all machines running the real user workloads.
For real world workloads, it was recommended to use the feature with
user-space controlled sampling approaches. For example, users could do
the page level monitoring only once per hour, on randomly selected one
percent of machines of their fleet. If the runtime and the size of the
fleet is long and big enough, it should provide statistically meaningful
data.
But users are too busy to implement such controls on their own.
Data Attributes Monitoring
==========================
Extend DAMON to monitor not only data accesses, but also general data
attributes. Do the extension while keeping the main promise of DAMON,
the bounded and best-effort minimum overhead.
Allow users to specify what data attributes in addition to the data
access they want to monitor. Users can install one 'data probe' per
data attribute of their interest for this purpose. The 'data probe'
should be able to be applied to any memory, and determine if the given
memory has the appropriate data attribute. E.g., if memory of physical
address 42 belongs to cgroup A. Each 'data probe' is configured with
filters that are very similar to the DAMOS filters.
When DAMON checks if each sampling address memory of each region is
accessed since the last check, it applies data probes if registered.
Same to the number of access check-positive samples accounting
(nr_accesses), it accounts the number of each data probe-positive
samples in another per-region counters array, namely 'probe_hits'. When
DAMON resets nr_accesses every aggregation interval, it resets
'probe_hits' together.
Users can read 'probe_hits' just before the values are reset. In this
way, users can know how many hot/cold memory regions have data
attributes of their interest. E.g., 30 percent of this system's hot
memory is belonging to cgroup A, and 80 percent of the cgroup
A-belonging hot memory is backed by huge pages.
Patches Sequence
================
First eight patches implement the core feature, interface and the
working support. Patch 1 introduces data probe data structure, namely
damon_probe. Patch 2 extends damon_ctx for installing data probes.
Patch 3 introduces another data structure for filters of each data
probe, namely damon_filter. Patch 4 updates damon_ctx commit function
to handle the probes. Patch 5 extends damon_region for the per-region
per-probe positive samples counter, namely probe_hits. Patch 6 extends
damon_operations for applying probes on the underlying DAMON operations
implementation. Patch 7 updates kdamond_fn() to invoke the probes
applying callback. Patch 8 finally implements the probes support on
paddr ops.
Ten changes for user interface (patches 9-18) come next. Patches 9-13
implements sysfs directories and files for setting data probes, namely
probes directory, probe directory, filters directory, filter directory
and filter directory internal files, respectively. Patch 14 connects
the user inputs that are made via the sysfs files to DAMON core.
Following three patches (patches 15-17) implement sysfs directories and
files for showing the probe_hits to users, namely probes directory,
probe directory and hits files, respectively. Patch 18 introduces a new
tracepoint for showing the probe_hits via tracefs.
Patch 19 adds a selftest for the sysfs files.
Patches 20 and 21 documents the design and usage of the new feature,
respectively.
Seven additional patches (patches 22-28) for monitoring belonging memory
cgroup follow. Depending on the feedback, this part might be separated
to another series in future. Patch 22 defines the DAMON filter type for
the new attribute, namely DAMON_FILTER_TYPE_MEMCG. Patch 23 add the
support on paddr ops. Patch 24 updates the sysfs interface for setup of
the target memcg. Patch 25 move code for easy reuse of the filter
target memcg setup. Patch 26 connects the user input to the core layer.
Finally, patches 27 and 28 update the design and usage documents for the
memcg attribute monitoring support.
Discussions
===========
This allows the page properties monitoring with overhead that is low
enough to be enabled always on real world workloads. Because the
sampling time for access check is reused for data attributes check, the
upper-bounded and best-effort minimum overhead of DAMON is kept.
Because the sampling memory for access check is reused for data
attributes check, additional overhead is minimum.
Still DAMOS-based page level properties monitoring should be useful,
because it provides a deterministic page level information. When in
doubt of the sampling based information, running DAMOS-based one
together and comparing the results would be useful, for debugging and
tuning.
Plan for Dropping RFC tag
=========================
Making changes for feedback from myself, humans and Sashiko should be
the major remaining work.
I'm currently hoping to drop the RFC tag by 7.2-rc1.
Future Works: Mid Term
========================
This version of implementation is limiting the maximum number of data
probes to four. I will try to find a way to remove the limit in future.
I personally think it should be enough for common use cases, though, and
therefore not giving high priority at the moment.
Future Works: Long Term
=======================
There are user requests for extending DAMON with detailed access
information, for example, per-CPUs/threads/read/writes monitoring. For
that, I was working [2] on extending DAMON to use page fault events as
another access check primitives, and making the infrastructure flexible
for future use of yet another access check primitive. Actually there is
another ongoing work [3] for extending DAMON with PMU events. The
motivation of the work is reducing the overhead, though.
In my work [2], I was introducing a new interface for access sampling
primitives control. Now I think this data probe interface can be used
for that, too. That is, data access becomes just one type of data
attribute. Also, pg_idle-confirmed access, page fault-confirmed access,
and PMU event-confirmed access will be different types of data
attributes.
The regions adjustment mechanism is currently working based on the
access information. That's because DAMON is designed for data access
monitoring. That is, data access information is the primary interest,
and therefore DAMON adjusts regions in a way that can best-present the
information.
Once data access becomes just one of data attributes, there is no reason
to think data access that special. There might be some users not
interested in access at all but want to know the location of memory of
specific type. Data probes interface will allow doing that. Further,
we could extend the interface to let users set any data attribute as the
'primary' attribute. Then, DAMON will split and merge regions in a way
that can best-present the 'primary' attributes.
DAMOS will also be extended, to specify targets based on not only the
data access pattern, but all user-registered data attributes. From this
stage, we may be able to call DAMON as a "Data Attributes Monitoring and
Operations eNgine".
[1] https://lore.kernel.org/20250106193401.109161-1-sj@kernel.org
[2] https://lore.kernel.org/20251208062943.68824-1-sj@kernel.org/
[3] https://lore.kernel.org/20260423004211.7037-1-akinobu.mita@gmail.com
Changes from RFC v2.2
- rfc v2.2: https://lore.kernel.org/20260515004433.128933-1-sj@kernel.org
- Rename damon_aggregated_v2 trace event to damon_region_aggregated.
- Address Sashiko issues.
- Enclose arguments on damon_for_each_{probe,filter}[_safe]() macros.
- Fix typos in comments and documents.
- Update probe_hits for region split and merge.
- Add more documentation for damon_operation->apply_probes() callback.
- Reduce unnecessary folio_{get,put}() in damon_pa_apply_probes().
- Define damon_sysfs_probe_attrs as static.
- Link scheme tried region sysfs dir and increase the count only after
all internal dir population success.
- Commit damon_filter->memcg_id for newly added filters.
Changes from RFC v2.1
- rfc v2.1: https://lore.kernel.org/20260514140904.119781-1-sj@kernel.org
- Rebase to mm-stable (7.1-rc3) to avoid Sashiko patch apply failure.
Changes from RFC v2
- rfc v2: https://lore.kernel.org/20260512143645.113201-1-sj@kernel.org
- Optimize nr_probes calculation for probe_hits tracepoint.
- Use TRACE_EVENT_CONDITION() for probe_hits tracepoint.
- Rebase to latest mm-new.
Changes from RFC
- rfc: https://lore.kernel.org/all/20260426205222.93895-1-sj@kernel.org/
- Support memcg DAMON filter.
- Use per-probe probe_hits sysfs file.
- Use dynamic_array for probe_hits tracing.
- Fix filter matching field.
- Fix folio leaking in damon_pa_filter_pass().
- Move nr_regions of damon_aggregated_v2 tracepoint after end.
- Rename DAMON_TEST_TYPE_ANON to DAMON_FILTER_TYPE_ANON.
SeongJae Park (28):
mm/damon/core: introduce struct damon_probe
mm/damon/core: embed damon_probe objects in damon_ctx
mm/damon/core: introduce damon_filter
mm/damon/core: commit probes
mm/damon/core: introduce damon_region->probe_hits
mm/damon/core: introduce damon_ops->apply_probes
mm/damon/core: do data attributes monitoring
mm/damon/paddr: support data attributes monitoring
mm/damon/sysfs: implement probes dir
mm/damon/sysfs: implement probe dir
mm/damon/sysfs: implement filters directory
mm/damon/sysfs: implement filter dir
mm/damon/sysfs: implement filter dir files
mm/damon/sysfs: setup probes on DAMON core API parameters
mm/damon/sysfs-schemes: implement tried_regions/<r>/probes/
mm/damon/sysfs-schemes: implement probe dir
mm/damon/sysfs-schemes: implement probe/hits file
mm/damon: trace probe_hits
selftests/damon/sysfs.sh: test probes dir
Docs/mm/damon/design: document data attributes monitoring
Docs/admin-guide/mm/damon/usage: document data attributes monitoring
mm/damon/core: introduce DAMON_FILTER_TYPE_MEMCG
mm/damon/paddr: support DAMON_FILTER_TYPE_MEMCG
mm/damon/sysfs: add filters/<F>/path file
mm/damon/sysfs-schemes: move memcg_path_to_id() to sysfs-common
mm/damon/sysfs: setup damon_filter->memcg_id from path
Docs/mm/damon/design: update for memcg damon filter
Docs/admin-guide/mm/damon/usage: update for memcg damon filter
Documentation/admin-guide/mm/damon/usage.rst | 46 +-
Documentation/mm/damon/design.rst | 39 ++
include/linux/damon.h | 69 +++
include/trace/events/damon.h | 38 ++
mm/damon/core.c | 211 +++++++
mm/damon/paddr.c | 76 +++
mm/damon/sysfs-common.c | 41 ++
mm/damon/sysfs-common.h | 2 +
mm/damon/sysfs-schemes.c | 226 ++++++--
mm/damon/sysfs.c | 557 +++++++++++++++++++
tools/testing/selftests/damon/sysfs.sh | 48 ++
11 files changed, 1305 insertions(+), 48 deletions(-)
base-commit: 5d6919055dec134de3c40167a490f33c74c12581
--
2.47.3
^ permalink raw reply [flat|nested] 43+ messages in thread
* [RFC PATCH v3 01/28] mm/damon/core: introduce struct damon_probe
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 02/28] mm/damon/core: embed damon_probe objects in damon_ctx SeongJae Park
` (28 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, damon, linux-kernel, linux-mm
Introduce a data structure for data attribute probe. It is just a
linked list header at this step. It will be extended in a way that it
can determine if a given memory has a specific data attribute.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/linux/damon.h | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index f2cdb7c3f5e6c..a8fff5325b010 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -721,6 +721,15 @@ struct damon_intervals_goal {
unsigned long max_sample_us;
};
+/**
+ * struct damon_probe - Data region attribute probe.
+ *
+ * @list: Siblings list.
+ */
+struct damon_probe {
+ struct list_head list;
+};
+
/**
* struct damon_attrs - Monitoring attributes for accuracy/overhead control.
*
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 02/28] mm/damon/core: embed damon_probe objects in damon_ctx
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 01/28] mm/damon/core: introduce struct damon_probe SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 03/28] mm/damon/core: introduce damon_filter SeongJae Park
` (27 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Let damon_probe objects be able to be installed on a given damon_ctx, by
adding a linked list header for storing the objects. Add initialization
and cleanup of the new field with helper functions, too.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/linux/damon.h | 9 +++++++++
mm/damon/core.c | 38 ++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index a8fff5325b010..d15f47a321d88 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -847,6 +847,7 @@ struct damon_ctx {
/* public: */
struct damon_operations ops;
+ struct list_head probes;
unsigned long addr_unit;
unsigned long min_region_sz;
@@ -879,6 +880,11 @@ static inline unsigned long damon_sz_region(struct damon_region *r)
return r->ar.end - r->ar.start;
}
+#define damon_for_each_probe(p, ctx) \
+ list_for_each_entry(p, &(ctx)->probes, list)
+
+#define damon_for_each_probe_safe(p, next, ctx) \
+ list_for_each_entry_safe(p, next, &(ctx)->probes, list)
#define damon_for_each_region(r, t) \
list_for_each_entry(r, &t->regions_list, list)
@@ -921,6 +927,9 @@ static inline unsigned long damon_sz_region(struct damon_region *r)
#ifdef CONFIG_DAMON
+struct damon_probe *damon_new_probe(void);
+void damon_add_probe(struct damon_ctx *ctx, struct damon_probe *probe);
+
struct damon_region *damon_new_region(unsigned long start, unsigned long end);
/*
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 3dbbbfdeff719..0e55fa70fa5b6 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -109,6 +109,38 @@ int damon_select_ops(struct damon_ctx *ctx, enum damon_ops_id id)
return err;
}
+struct damon_probe *damon_new_probe(void)
+{
+ struct damon_probe *p;
+
+ p = kmalloc_obj(*p);
+ if (!p)
+ return NULL;
+ INIT_LIST_HEAD(&p->list);
+ return p;
+}
+
+void damon_add_probe(struct damon_ctx *ctx, struct damon_probe *probe)
+{
+ list_add_tail(&probe->list, &ctx->probes);
+}
+
+static void damon_del_probe(struct damon_probe *p)
+{
+ list_del(&p->list);
+}
+
+static void damon_free_probe(struct damon_probe *p)
+{
+ kfree(p);
+}
+
+static void damon_destroy_probe(struct damon_probe *p)
+{
+ damon_del_probe(p);
+ damon_free_probe(p);
+}
+
#ifdef CONFIG_DAMON_DEBUG_SANITY
static void damon_verify_new_region(unsigned long start, unsigned long end)
{
@@ -601,6 +633,8 @@ struct damon_ctx *damon_new_ctx(void)
ctx->attrs.min_nr_regions = 10;
ctx->attrs.max_nr_regions = 1000;
+ INIT_LIST_HEAD(&ctx->probes);
+
ctx->addr_unit = 1;
ctx->min_region_sz = DAMON_MIN_REGION_SZ;
@@ -621,12 +655,16 @@ static void damon_destroy_targets(struct damon_ctx *ctx)
void damon_destroy_ctx(struct damon_ctx *ctx)
{
struct damos *s, *next_s;
+ struct damon_probe *p, *next_p;
damon_destroy_targets(ctx);
damon_for_each_scheme_safe(s, next_s, ctx)
damon_destroy_scheme(s);
+ damon_for_each_probe_safe(p, next_p, ctx)
+ damon_destroy_probe(p);
+
kfree(ctx);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 03/28] mm/damon/core: introduce damon_filter
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 01/28] mm/damon/core: introduce struct damon_probe SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 02/28] mm/damon/core: embed damon_probe objects in damon_ctx SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 04/28] mm/damon/core: commit probes SeongJae Park
` (26 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Define a data structure for constructing damon_probe's attributes check,
namely damon_filter. It is very similar to damos_filter but works only
for monitoring purposes. Also embed that into damon_probe, implement
essential handling of the link, with fundamental helpers.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/linux/damon.h | 36 ++++++++++++++++++++++++++++++++++++
mm/damon/core.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index d15f47a321d88..32005b8b1f8cd 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -721,12 +721,38 @@ struct damon_intervals_goal {
unsigned long max_sample_us;
};
+/**
+ * enum damon_filter_type - Type of &struct damon_filter
+ *
+ * @DAMON_FILTER_TYPE_ANON: Anonymous pages.
+ */
+enum damon_filter_type {
+ DAMON_FILTER_TYPE_ANON,
+};
+
+/**
+ * struct damon_filter - DAMON region filter for &struct damon_probe.
+ *
+ * @type: Type of the region.
+ * @matching: Whether this filter is for the type-matching ones.
+ * @allow: Whether the @type-@matching ones should pass this filter.
+ * @list: Siblings list.
+ */
+struct damon_filter {
+ enum damon_filter_type type;
+ bool matching;
+ bool allow;
+ struct list_head list;
+};
+
/**
* struct damon_probe - Data region attribute probe.
*
+ * @filters: Filters for assessing if a given region is for this probe.
* @list: Siblings list.
*/
struct damon_probe {
+ struct list_head filters;
struct list_head list;
};
@@ -880,6 +906,12 @@ static inline unsigned long damon_sz_region(struct damon_region *r)
return r->ar.end - r->ar.start;
}
+#define damon_for_each_filter(f, p) \
+ list_for_each_entry(f, &(p)->filters, list)
+
+#define damon_for_each_filter_safe(f, next, p) \
+ list_for_each_entry_safe(f, next, &(p)->filters, list)
+
#define damon_for_each_probe(p, ctx) \
list_for_each_entry(p, &(ctx)->probes, list)
@@ -927,6 +959,10 @@ static inline unsigned long damon_sz_region(struct damon_region *r)
#ifdef CONFIG_DAMON
+struct damon_filter *damon_new_filter(enum damon_filter_type type,
+ bool matching, bool allow);
+void damon_add_filter(struct damon_probe *probe, struct damon_filter *f);
+
struct damon_probe *damon_new_probe(void);
void damon_add_probe(struct damon_ctx *ctx, struct damon_probe *probe);
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 0e55fa70fa5b6..44943d654dcce 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -109,6 +109,31 @@ int damon_select_ops(struct damon_ctx *ctx, enum damon_ops_id id)
return err;
}
+struct damon_filter *damon_new_filter(enum damon_filter_type type,
+ bool matching, bool allow)
+{
+ struct damon_filter *filter;
+
+ filter = kmalloc_obj(*filter);
+ if (!filter)
+ return NULL;
+ filter->type = type;
+ filter->matching = matching;
+ filter->allow = allow;
+ INIT_LIST_HEAD(&filter->list);
+ return filter;
+}
+
+void damon_add_filter(struct damon_probe *p, struct damon_filter *f)
+{
+ list_add_tail(&f->list, &p->filters);
+}
+
+static void damon_free_filter(struct damon_filter *f)
+{
+ kfree(f);
+}
+
struct damon_probe *damon_new_probe(void)
{
struct damon_probe *p;
@@ -116,6 +141,7 @@ struct damon_probe *damon_new_probe(void)
p = kmalloc_obj(*p);
if (!p)
return NULL;
+ INIT_LIST_HEAD(&p->filters);
INIT_LIST_HEAD(&p->list);
return p;
}
@@ -132,6 +158,10 @@ static void damon_del_probe(struct damon_probe *p)
static void damon_free_probe(struct damon_probe *p)
{
+ struct damon_filter *f, *next;
+
+ damon_for_each_filter_safe(f, next, p)
+ damon_free_filter(f);
kfree(p);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 04/28] mm/damon/core: commit probes
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (2 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 03/28] mm/damon/core: introduce damon_filter SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 05/28] mm/damon/core: introduce damon_region->probe_hits SeongJae Park
` (25 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Update damon_commit_ctx() to commit installed data probes, too.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/core.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 104 insertions(+)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 44943d654dcce..15f2795a1156f 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -129,11 +129,34 @@ void damon_add_filter(struct damon_probe *p, struct damon_filter *f)
list_add_tail(&f->list, &p->filters);
}
+static void damon_del_filter(struct damon_filter *f)
+{
+ list_del(&f->list);
+}
+
static void damon_free_filter(struct damon_filter *f)
{
kfree(f);
}
+static void damon_destroy_filter(struct damon_filter *f)
+{
+ damon_del_filter(f);
+ damon_free_filter(f);
+}
+
+static struct damon_filter *damon_nth_filter(int n, struct damon_probe *p)
+{
+ struct damon_filter *f;
+ int i = 0;
+
+ damon_for_each_filter(f, p) {
+ if (i++ == n)
+ return f;
+ }
+ return NULL;
+}
+
struct damon_probe *damon_new_probe(void)
{
struct damon_probe *p;
@@ -171,6 +194,18 @@ static void damon_destroy_probe(struct damon_probe *p)
damon_free_probe(p);
}
+static struct damon_probe *damon_nth_probe(int n, struct damon_ctx *ctx)
+{
+ struct damon_probe *p;
+ int i = 0;
+
+ damon_for_each_probe(p, ctx) {
+ if (i++ == n)
+ return p;
+ }
+ return NULL;
+}
+
#ifdef CONFIG_DAMON_DEBUG_SANITY
static void damon_verify_new_region(unsigned long start, unsigned long end)
{
@@ -1378,6 +1413,72 @@ static int damon_commit_targets(
return 0;
}
+static void damon_commit_filter(struct damon_filter *dst,
+ struct damon_filter *src)
+{
+ dst->type = src->type;
+ dst->matching = src->matching;
+ dst->allow = src->allow;
+}
+
+static int damon_commit_filters(struct damon_probe *dst,
+ struct damon_probe *src)
+{
+ struct damon_filter *dst_filter, *next, *src_filter, *new_filter;
+ int i = 0, j = 0;
+
+ damon_for_each_filter_safe(dst_filter, next, dst) {
+ src_filter = damon_nth_filter(i++, src);
+ if (src_filter)
+ damon_commit_filter(dst_filter, src_filter);
+ else
+ damon_destroy_filter(dst_filter);
+ }
+
+ damon_for_each_filter_safe(src_filter, next, src) {
+ if (j++ < i)
+ continue;
+
+ new_filter = damon_new_filter(src_filter->type,
+ src_filter->matching, src_filter->allow);
+ if (!new_filter)
+ return -ENOMEM;
+ damon_add_filter(dst, new_filter);
+ }
+ return 0;
+}
+
+static int damon_commit_probes(struct damon_ctx *dst, struct damon_ctx *src)
+{
+ struct damon_probe *dst_probe, *next, *src_probe, *new_probe;
+ int i = 0, j = 0, err;
+
+ damon_for_each_probe_safe(dst_probe, next, dst) {
+ src_probe = damon_nth_probe(i++, src);
+ if (src_probe) {
+ err = damon_commit_filters(dst_probe, src_probe);
+ if (err)
+ return err;
+ } else {
+ damon_destroy_probe(dst_probe);
+ }
+ }
+
+ damon_for_each_probe_safe(src_probe, next, src) {
+ if (j++ < i)
+ continue;
+
+ new_probe = damon_new_probe();
+ if (!new_probe)
+ return -ENOMEM;
+ damon_add_probe(dst, new_probe);
+ err = damon_commit_filters(new_probe, src_probe);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
/**
* damon_commit_ctx() - Commit parameters of a DAMON context to another.
* @dst: The commit destination DAMON context.
@@ -1418,6 +1519,9 @@ int damon_commit_ctx(struct damon_ctx *dst, struct damon_ctx *src)
return err;
}
dst->ops = src->ops;
+ err = damon_commit_probes(dst, src);
+ if (err)
+ return err;
dst->addr_unit = src->addr_unit;
dst->min_region_sz = src->min_region_sz;
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 05/28] mm/damon/core: introduce damon_region->probe_hits
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (3 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 04/28] mm/damon/core: commit probes SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:54 ` sashiko-bot
2026-05-16 18:36 ` [RFC PATCH v3 06/28] mm/damon/core: introduce damon_ops->apply_probes SeongJae Park
` (24 subsequent siblings)
29 siblings, 1 reply; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Add an array for the per-region per-probe positive samples count. For
simple and efficient implementation, add a limit to the number of data
probes and set the array to support only the limited number of counters.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/linux/damon.h | 4 ++++
mm/damon/core.c | 10 ++++++++++
2 files changed, 14 insertions(+)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 32005b8b1f8cd..9e70239e5305f 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -16,6 +16,8 @@
/* Minimal region size. Every damon_region is aligned by this. */
#define DAMON_MIN_REGION_SZ PAGE_SIZE
+/* Maximum number of monitoring probes. */
+#define DAMON_MAX_PROBES (4)
/* Max priority score for DAMON-based operation schemes */
#define DAMOS_MAX_SCORE (99)
@@ -52,6 +54,7 @@ struct damon_size_range {
* @nr_accesses: Access frequency of this region.
* @nr_accesses_bp: @nr_accesses in basis point (0.01%) that updated for
* each sampling interval.
+ * @probe_hits: Number of probe-positive region samples.
* @list: List head for siblings.
* @age: Age of this region.
*
@@ -80,6 +83,7 @@ struct damon_region {
unsigned long sampling_addr;
unsigned int nr_accesses;
unsigned int nr_accesses_bp;
+ unsigned char probe_hits[DAMON_MAX_PROBES];
struct list_head list;
unsigned int age;
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 15f2795a1156f..e5667660b4cd9 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -225,6 +225,7 @@ static void damon_verify_new_region(unsigned long start, unsigned long end)
struct damon_region *damon_new_region(unsigned long start, unsigned long end)
{
struct damon_region *region;
+ int i;
damon_verify_new_region(start, end);
region = kmem_cache_alloc(damon_region_cache, GFP_KERNEL);
@@ -235,6 +236,8 @@ struct damon_region *damon_new_region(unsigned long start, unsigned long end)
region->ar.end = end;
region->nr_accesses = 0;
region->nr_accesses_bp = 0;
+ for (i = 0; i < DAMON_MAX_PROBES; i++)
+ region->probe_hits[i] = 0;
INIT_LIST_HEAD(®ion->list);
region->age = 0;
@@ -2754,12 +2757,17 @@ static void damon_merge_two_regions(struct damon_target *t,
struct damon_region *l, struct damon_region *r)
{
unsigned long sz_l = damon_sz_region(l), sz_r = damon_sz_region(r);
+ int i;
l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) /
(sz_l + sz_r);
l->nr_accesses_bp = l->nr_accesses * 10000;
l->age = (l->age * sz_l + r->age * sz_r) / (sz_l + sz_r);
l->ar.end = r->ar.end;
+ /* todo: do this for only installed probes */
+ for (i = 0; i < DAMON_MAX_PROBES; i++)
+ l->probe_hits[i] = (l->probe_hits[i] * sz_l + r->probe_hits[i]
+ * sz_r) / (sz_l + sz_r);
damon_verify_merge_two_regions(l, r);
damon_destroy_region(r, t);
}
@@ -2882,6 +2890,8 @@ static void damon_split_region_at(struct damon_target *t,
new->last_nr_accesses = r->last_nr_accesses;
new->nr_accesses_bp = r->nr_accesses_bp;
new->nr_accesses = r->nr_accesses;
+ /* todo: do this for only installed probes */
+ memcpy(new->probe_hits, r->probe_hits, sizeof(r->probe_hits));
damon_insert_region(new, r, damon_next_region(r), t);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 06/28] mm/damon/core: introduce damon_ops->apply_probes
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (4 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 05/28] mm/damon/core: introduce damon_region->probe_hits SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 07/28] mm/damon/core: do data attributes monitoring SeongJae Park
` (23 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, damon, linux-kernel, linux-mm
Extend damon_operations struct with a new callback, namely apply_probes.
The callback will be invoked for data attributes monitoring. More
specifically, the callback will apply damon_probe objects to each region
and update the per-region per-probe counters for the number of
encountered probe-positive samples.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/linux/damon.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 9e70239e5305f..d3b6296700a08 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -621,6 +621,7 @@ enum damon_ops_id {
* @update: Update operations-related data structures.
* @prepare_access_checks: Prepare next access check of target regions.
* @check_accesses: Check the accesses to target regions.
+ * @apply_probes: Apply probes for each region.
* @get_scheme_score: Get the score of a region for a scheme.
* @apply_scheme: Apply a DAMON-based operation scheme.
* @target_valid: Determine if the target is valid.
@@ -647,6 +648,8 @@ enum damon_ops_id {
* last preparation and update the number of observed accesses of each region.
* 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.
* @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
@@ -664,6 +667,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);
int (*get_scheme_score)(struct damon_ctx *context,
struct damon_region *r, struct damos *scheme);
unsigned long (*apply_scheme)(struct damon_ctx *context,
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 07/28] mm/damon/core: do data attributes monitoring
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (5 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 06/28] mm/damon/core: introduce damon_ops->apply_probes SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 19:00 ` sashiko-bot
2026-05-16 18:36 ` [RFC PATCH v3 08/28] mm/damon/paddr: support " SeongJae Park
` (22 subsequent siblings)
29 siblings, 1 reply; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Implement the data attributes monitoring execution. Update kdamond to
invoke the probes application callback, and reset the aggregated number
of per-region per-probe positive samples for every aggregation interval.
Signed-off-by: SeongJae 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 e5667660b4cd9..dde3c8d8fef89 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1886,10 +1886,14 @@ static void kdamond_reset_aggregated(struct damon_ctx *c)
struct damon_region *r;
damon_for_each_region(r, t) {
+ int i;
+
trace_damon_aggregated(ti, r, damon_nr_regions(t));
damon_warn_fix_nr_accesses_corruption(r);
r->last_nr_accesses = r->nr_accesses;
r->nr_accesses = 0;
+ for (i = 0; i < DAMON_MAX_PROBES; i++)
+ r->probe_hits[i] = 0;
damon_verify_reset_aggregated(r, c);
}
ti++;
@@ -3179,6 +3183,8 @@ 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);
if (time_after_eq(ctx->passed_sample_intervals,
next_aggregation_sis)) {
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 08/28] mm/damon/paddr: support data attributes monitoring
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (6 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 07/28] mm/damon/core: do data attributes monitoring SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 19:05 ` sashiko-bot
2026-05-16 18:36 ` [RFC PATCH v3 09/28] mm/damon/sysfs: implement probes dir SeongJae Park
` (21 subsequent siblings)
29 siblings, 1 reply; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Implement and register damon_operations->apply_probes() callback to
support data attributes monitoring.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/paddr.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 62 insertions(+)
diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
index 5cdcc5037cbc1..81780b05c175e 100644
--- a/mm/damon/paddr.c
+++ b/mm/damon/paddr.c
@@ -120,6 +120,67 @@ static unsigned int damon_pa_check_accesses(struct damon_ctx *ctx)
return max_nr_accesses;
}
+static bool damon_pa_filter_match(struct damon_filter *filter,
+ struct folio *folio)
+{
+ bool matched = false;
+
+ switch (filter->type) {
+ case DAMON_FILTER_TYPE_ANON:
+ if (!folio) {
+ matched = false;
+ break;
+ }
+ matched = folio_test_anon(folio);
+ break;
+ default:
+ break;
+ }
+ return matched == filter->matching;
+}
+
+static bool damon_pa_filter_pass(phys_addr_t pa, struct folio *folio,
+ struct damon_probe *p)
+{
+ struct damon_filter *f;
+ bool pass = true;
+
+ damon_for_each_filter(f, p) {
+ if (damon_pa_filter_match(f, folio)) {
+ pass = f->allow;
+ break;
+ }
+ pass = !f->allow;
+ }
+ return pass;
+}
+
+static void damon_pa_apply_probes(struct damon_ctx *ctx)
+{
+ struct damon_target *t;
+ struct damon_region *r;
+ struct damon_probe *p;
+
+ damon_for_each_target(t, ctx) {
+ 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);
+ folio = damon_get_folio(PHYS_PFN(pa));
+ damon_for_each_probe(p, ctx) {
+ if (damon_pa_filter_pass(pa, folio, p))
+ r->probe_hits[i]++;
+ i++;
+ }
+ if (folio)
+ folio_put(folio);
+ }
+ }
+}
+
/*
* damos_pa_filter_out - Return true if the page should be filtered out.
*/
@@ -371,6 +432,7 @@ static int __init damon_pa_initcall(void)
.update = NULL,
.prepare_access_checks = damon_pa_prepare_access_checks,
.check_accesses = damon_pa_check_accesses,
+ .apply_probes = damon_pa_apply_probes,
.target_valid = NULL,
.apply_scheme = damon_pa_apply_scheme,
.get_scheme_score = damon_pa_scheme_score,
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 09/28] mm/damon/sysfs: implement probes dir
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (7 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 08/28] mm/damon/paddr: support " SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 10/28] mm/damon/sysfs: implement probe dir SeongJae Park
` (20 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Implement sysfs directory that can be used by the users to install data
probes.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index eefa959aa30ae..5f3b253f50ebf 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -747,6 +747,35 @@ static const struct kobj_type damon_sysfs_intervals_ktype = {
.default_groups = damon_sysfs_intervals_groups,
};
+/*
+ * probes directory
+ */
+
+struct damon_sysfs_probes {
+ struct kobject kobj;
+};
+
+static struct damon_sysfs_probes *damon_sysfs_probes_alloc(void)
+{
+ return kzalloc_obj(struct damon_sysfs_probes);
+}
+
+static void damon_sysfs_probes_release(struct kobject *kobj)
+{
+ kfree(container_of(kobj, struct damon_sysfs_probes, kobj));
+}
+
+static struct attribute *damon_sysfs_probes_attrs[] = {
+ NULL,
+};
+ATTRIBUTE_GROUPS(damon_sysfs_probes);
+
+static const struct kobj_type damon_sysfs_probes_ktype = {
+ .release = damon_sysfs_probes_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = damon_sysfs_probes_groups,
+};
+
/*
* monitoring_attrs directory
*/
@@ -755,6 +784,7 @@ struct damon_sysfs_attrs {
struct kobject kobj;
struct damon_sysfs_intervals *intervals;
struct damon_sysfs_ul_range *nr_regions_range;
+ struct damon_sysfs_probes *probes;
};
static struct damon_sysfs_attrs *damon_sysfs_attrs_alloc(void)
@@ -771,6 +801,7 @@ static int damon_sysfs_attrs_add_dirs(struct damon_sysfs_attrs *attrs)
{
struct damon_sysfs_intervals *intervals;
struct damon_sysfs_ul_range *nr_regions_range;
+ struct damon_sysfs_probes *probes;
int err;
intervals = damon_sysfs_intervals_alloc(5000, 100000, 60000000);
@@ -799,8 +830,22 @@ static int damon_sysfs_attrs_add_dirs(struct damon_sysfs_attrs *attrs)
if (err)
goto put_nr_regions_intervals_out;
attrs->nr_regions_range = nr_regions_range;
+
+ probes = damon_sysfs_probes_alloc();
+ if (!probes) {
+ err = -ENOMEM;
+ goto put_nr_regions_intervals_out;
+ }
+ err = kobject_init_and_add(&probes->kobj,
+ &damon_sysfs_probes_ktype, &attrs->kobj, "probes");
+ if (err)
+ goto put_probes_out;
+ attrs->probes = probes;
return 0;
+put_probes_out:
+ kobject_put(&probes->kobj);
+ attrs->probes = NULL;
put_nr_regions_intervals_out:
kobject_put(&nr_regions_range->kobj);
attrs->nr_regions_range = NULL;
@@ -817,6 +862,7 @@ static void damon_sysfs_attrs_rm_dirs(struct damon_sysfs_attrs *attrs)
kobject_put(&attrs->nr_regions_range->kobj);
damon_sysfs_intervals_rm_dirs(attrs->intervals);
kobject_put(&attrs->intervals->kobj);
+ kobject_put(&attrs->probes->kobj);
}
static void damon_sysfs_attrs_release(struct kobject *kobj)
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 10/28] mm/damon/sysfs: implement probe dir
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (8 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 09/28] mm/damon/sysfs: implement probes dir SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 11/28] mm/damon/sysfs: implement filters directory SeongJae Park
` (19 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Implement sysfs directory for letting users install each data probe.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 119 insertions(+)
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index 5f3b253f50ebf..162d2d55be08e 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -747,12 +747,43 @@ static const struct kobj_type damon_sysfs_intervals_ktype = {
.default_groups = damon_sysfs_intervals_groups,
};
+/*
+ * probe directory
+ */
+
+struct damon_sysfs_probe {
+ struct kobject kobj;
+};
+
+static struct damon_sysfs_probe *damon_sysfs_probe_alloc(void)
+{
+ return kzalloc_obj(struct damon_sysfs_probe);
+}
+
+static void damon_sysfs_probe_release(struct kobject *kobj)
+{
+ kfree(container_of(kobj, struct damon_sysfs_probe, kobj));
+}
+
+static struct attribute *damon_sysfs_probe_attrs[] = {
+ NULL,
+};
+ATTRIBUTE_GROUPS(damon_sysfs_probe);
+
+static const struct kobj_type damon_sysfs_probe_ktype = {
+ .release = damon_sysfs_probe_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = damon_sysfs_probe_groups,
+};
+
/*
* probes directory
*/
struct damon_sysfs_probes {
struct kobject kobj;
+ struct damon_sysfs_probe **probes_arr;
+ int nr;
};
static struct damon_sysfs_probes *damon_sysfs_probes_alloc(void)
@@ -760,12 +791,99 @@ static struct damon_sysfs_probes *damon_sysfs_probes_alloc(void)
return kzalloc_obj(struct damon_sysfs_probes);
}
+static void damon_sysfs_probes_rm_dirs(
+ struct damon_sysfs_probes *probes)
+{
+ struct damon_sysfs_probe **probes_arr = probes->probes_arr;
+ int i;
+
+ for (i = 0; i < probes->nr; i++)
+ kobject_put(&probes_arr[i]->kobj);
+ probes->nr = 0;
+ kfree(probes_arr);
+ probes->probes_arr = NULL;
+}
+
+static int damon_sysfs_probes_add_dirs(
+ struct damon_sysfs_probes *probes, int nr_probes)
+{
+ struct damon_sysfs_probe **probes_arr, *probe;
+ int err, i;
+
+ damon_sysfs_probes_rm_dirs(probes);
+ if (!nr_probes)
+ return 0;
+
+ probes_arr = kmalloc_objs(*probes_arr, nr_probes,
+ GFP_KERNEL | __GFP_NOWARN);
+ if (!probes_arr)
+ return -ENOMEM;
+ probes->probes_arr = probes_arr;
+
+ for (i = 0; i < nr_probes; i++) {
+ probe = damon_sysfs_probe_alloc();
+ if (!probe) {
+ damon_sysfs_probes_rm_dirs(probes);
+ return -ENOMEM;
+ }
+
+ err = kobject_init_and_add(&probe->kobj,
+ &damon_sysfs_probe_ktype, &probes->kobj,
+ "%d", i);
+ if (err) {
+ kobject_put(&probe->kobj);
+ damon_sysfs_probes_rm_dirs(probes);
+ return err;
+ }
+
+ probes_arr[i] = probe;
+ probes->nr++;
+ }
+ return 0;
+}
+
+static ssize_t nr_probes_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_probes *probes = container_of(kobj,
+ struct damon_sysfs_probes, kobj);
+
+ return sysfs_emit(buf, "%d\n", probes->nr);
+}
+
+static ssize_t nr_probes_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_probes *probes;
+ int nr, err = kstrtoint(buf, 0, &nr);
+
+ if (err)
+ return err;
+ if (nr < 0 || nr > DAMON_MAX_PROBES)
+ return -EINVAL;
+
+ probes = container_of(kobj, struct damon_sysfs_probes, kobj);
+
+ if (!mutex_trylock(&damon_sysfs_lock))
+ return -EBUSY;
+ err = damon_sysfs_probes_add_dirs(probes, nr);
+ mutex_unlock(&damon_sysfs_lock);
+ if (err)
+ return err;
+
+ return count;
+}
+
static void damon_sysfs_probes_release(struct kobject *kobj)
{
kfree(container_of(kobj, struct damon_sysfs_probes, kobj));
}
+static struct kobj_attribute damon_sysfs_probes_nr_probes =
+ __ATTR_RW_MODE(nr_probes, 0600);
+
static struct attribute *damon_sysfs_probes_attrs[] = {
+ &damon_sysfs_probes_nr_probes.attr,
NULL,
};
ATTRIBUTE_GROUPS(damon_sysfs_probes);
@@ -862,6 +980,7 @@ static void damon_sysfs_attrs_rm_dirs(struct damon_sysfs_attrs *attrs)
kobject_put(&attrs->nr_regions_range->kobj);
damon_sysfs_intervals_rm_dirs(attrs->intervals);
kobject_put(&attrs->intervals->kobj);
+ damon_sysfs_probes_rm_dirs(attrs->probes);
kobject_put(&attrs->probes->kobj);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 11/28] mm/damon/sysfs: implement filters directory
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (9 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 10/28] mm/damon/sysfs: implement probe dir SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 12/28] mm/damon/sysfs: implement filter dir SeongJae Park
` (18 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Implement a directory for letting users to install data probe filters.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 64 insertions(+), 1 deletion(-)
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index 162d2d55be08e..184613538d3aa 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -747,12 +747,42 @@ static const struct kobj_type damon_sysfs_intervals_ktype = {
.default_groups = damon_sysfs_intervals_groups,
};
+/*
+ * filters directory
+ */
+
+struct damon_sysfs_filters {
+ struct kobject kobj;
+};
+
+static struct damon_sysfs_filters *damon_sysfs_filters_alloc(void)
+{
+ return kzalloc_obj(struct damon_sysfs_filters);
+}
+
+static void damon_sysfs_filters_release(struct kobject *kobj)
+{
+ kfree(container_of(kobj, struct damon_sysfs_filters, kobj));
+}
+
+static struct attribute *damon_sysfs_filters_attrs[] = {
+ NULL,
+};
+ATTRIBUTE_GROUPS(damon_sysfs_filters);
+
+static const struct kobj_type damon_sysfs_filters_ktype = {
+ .release = damon_sysfs_filters_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = damon_sysfs_filters_groups,
+};
+
/*
* probe directory
*/
struct damon_sysfs_probe {
struct kobject kobj;
+ struct damon_sysfs_filters *filters;
};
static struct damon_sysfs_probe *damon_sysfs_probe_alloc(void)
@@ -760,6 +790,30 @@ static struct damon_sysfs_probe *damon_sysfs_probe_alloc(void)
return kzalloc_obj(struct damon_sysfs_probe);
}
+static int damon_sysfs_probe_add_dirs(struct damon_sysfs_probe *attr)
+{
+ struct damon_sysfs_filters *filters;
+ int err;
+
+ filters = damon_sysfs_filters_alloc();
+ if (!filters)
+ return -ENOMEM;
+ attr->filters = filters;
+
+ err = kobject_init_and_add(&filters->kobj, &damon_sysfs_filters_ktype,
+ &attr->kobj, "filters");
+ if (err) {
+ kobject_put(&filters->kobj);
+ attr->filters = NULL;
+ }
+ return err;
+}
+
+static void damon_sysfs_probe_rm_dirs(struct damon_sysfs_probe *attr)
+{
+ kobject_put(&attr->filters->kobj);
+}
+
static void damon_sysfs_probe_release(struct kobject *kobj)
{
kfree(container_of(kobj, struct damon_sysfs_probe, kobj));
@@ -797,8 +851,10 @@ static void damon_sysfs_probes_rm_dirs(
struct damon_sysfs_probe **probes_arr = probes->probes_arr;
int i;
- for (i = 0; i < probes->nr; i++)
+ for (i = 0; i < probes->nr; i++) {
+ damon_sysfs_probe_rm_dirs(probes_arr[i]);
kobject_put(&probes_arr[i]->kobj);
+ }
probes->nr = 0;
kfree(probes_arr);
probes->probes_arr = NULL;
@@ -836,6 +892,13 @@ static int damon_sysfs_probes_add_dirs(
return err;
}
+ err = damon_sysfs_probe_add_dirs(probe);
+ if (err) {
+ kobject_put(&probe->kobj);
+ damon_sysfs_probes_rm_dirs(probes);
+ return err;
+ }
+
probes_arr[i] = probe;
probes->nr++;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 12/28] mm/damon/sysfs: implement filter dir
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (10 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 11/28] mm/damon/sysfs: implement filters directory SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 13/28] mm/damon/sysfs: implement filter dir files SeongJae Park
` (17 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Implement a sysfs directory for letting the users to configure each data
probe filter.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 124 insertions(+), 1 deletion(-)
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index 184613538d3aa..18c669ce6f81f 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -747,12 +747,46 @@ static const struct kobj_type damon_sysfs_intervals_ktype = {
.default_groups = damon_sysfs_intervals_groups,
};
+/*
+ * filter directory
+ */
+
+struct damon_sysfs_filter {
+ struct kobject kobj;
+};
+
+static struct damon_sysfs_filter *damon_sysfs_filter_alloc(void)
+{
+ return kzalloc_obj(struct damon_sysfs_filter);
+}
+
+static void damon_sysfs_filter_release(struct kobject *kobj)
+{
+ struct damon_sysfs_filter *filter = container_of(kobj,
+ struct damon_sysfs_filter, kobj);
+
+ kfree(filter);
+}
+
+static struct attribute *damon_sysfs_filter_attrs[] = {
+ NULL,
+};
+ATTRIBUTE_GROUPS(damon_sysfs_filter);
+
+static const struct kobj_type damon_sysfs_filter_ktype = {
+ .release = damon_sysfs_filter_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = damon_sysfs_filter_groups,
+};
+
/*
* filters directory
*/
struct damon_sysfs_filters {
struct kobject kobj;
+ struct damon_sysfs_filter **filters_arr;
+ int nr;
};
static struct damon_sysfs_filters *damon_sysfs_filters_alloc(void)
@@ -760,12 +794,98 @@ static struct damon_sysfs_filters *damon_sysfs_filters_alloc(void)
return kzalloc_obj(struct damon_sysfs_filters);
}
+static void damon_sysfs_filters_rm_dirs(struct damon_sysfs_filters *filters)
+{
+ struct damon_sysfs_filter **filters_arr = filters->filters_arr;
+ int i;
+
+ for (i = 0; i < filters->nr; i++)
+ kobject_put(&filters_arr[i]->kobj);
+ filters->nr = 0;
+ kfree(filters_arr);
+ filters->filters_arr = NULL;
+}
+
+static int damon_sysfs_filters_add_dirs(
+ struct damon_sysfs_filters *filters, int nr_filters)
+{
+ struct damon_sysfs_filter **filters_arr, *filter;
+ int err, i;
+
+ damon_sysfs_filters_rm_dirs(filters);
+ if (!nr_filters)
+ return 0;
+
+ filters_arr = kmalloc_objs(*filters_arr, nr_filters,
+ GFP_KERNEL | __GFP_NOWARN);
+ if (!filters_arr)
+ return -ENOMEM;
+ filters->filters_arr = filters_arr;
+
+ for (i = 0; i < nr_filters; i++) {
+ filter = damon_sysfs_filter_alloc();
+ if (!filter) {
+ damon_sysfs_filters_rm_dirs(filters);
+ return -ENOMEM;
+ }
+
+ err = kobject_init_and_add(&filter->kobj,
+ &damon_sysfs_filter_ktype, &filters->kobj,
+ "%d", i);
+ if (err) {
+ kobject_put(&filter->kobj);
+ damon_sysfs_filters_rm_dirs(filters);
+ return err;
+ }
+
+ filters_arr[i] = filter;
+ filters->nr++;
+ }
+ return 0;
+}
+
+static ssize_t nr_filters_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_filters *filters = container_of(kobj,
+ struct damon_sysfs_filters, kobj);
+
+ return sysfs_emit(buf, "%d\n", filters->nr);
+}
+
+static ssize_t nr_filters_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_filters *filters;
+ int nr, err = kstrtoint(buf, 0, &nr);
+
+ if (err)
+ return err;
+ if (nr < 0)
+ return -EINVAL;
+
+ filters = container_of(kobj, struct damon_sysfs_filters, kobj);
+
+ if (!mutex_trylock(&damon_sysfs_lock))
+ return -EBUSY;
+ err = damon_sysfs_filters_add_dirs(filters, nr);
+ mutex_unlock(&damon_sysfs_lock);
+ if (err)
+ return err;
+
+ return count;
+}
+
static void damon_sysfs_filters_release(struct kobject *kobj)
{
kfree(container_of(kobj, struct damon_sysfs_filters, kobj));
}
+static struct kobj_attribute damon_sysfs_filters_nr_attr =
+ __ATTR_RW_MODE(nr_filters, 0600);
+
static struct attribute *damon_sysfs_filters_attrs[] = {
+ &damon_sysfs_filters_nr_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(damon_sysfs_filters);
@@ -811,7 +931,10 @@ static int damon_sysfs_probe_add_dirs(struct damon_sysfs_probe *attr)
static void damon_sysfs_probe_rm_dirs(struct damon_sysfs_probe *attr)
{
- kobject_put(&attr->filters->kobj);
+ if (attr->filters) {
+ damon_sysfs_filters_rm_dirs(attr->filters);
+ kobject_put(&attr->filters->kobj);
+ }
}
static void damon_sysfs_probe_release(struct kobject *kobj)
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 13/28] mm/damon/sysfs: implement filter dir files
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (11 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 12/28] mm/damon/sysfs: implement filter dir SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 14/28] mm/damon/sysfs: setup probes on DAMON core API parameters SeongJae Park
` (16 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Implement sysfs files under the data probe filter directory for letting
users to configure each filter.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 114 insertions(+)
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index 18c669ce6f81f..35a4fa5c530f5 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -753,6 +753,9 @@ static const struct kobj_type damon_sysfs_intervals_ktype = {
struct damon_sysfs_filter {
struct kobject kobj;
+ enum damon_filter_type type;
+ bool matching;
+ bool allow;
};
static struct damon_sysfs_filter *damon_sysfs_filter_alloc(void)
@@ -760,6 +763,105 @@ static struct damon_sysfs_filter *damon_sysfs_filter_alloc(void)
return kzalloc_obj(struct damon_sysfs_filter);
}
+struct damon_sysfs_filter_type_name {
+ enum damon_filter_type type;
+ char *name;
+};
+
+static const struct damon_sysfs_filter_type_name
+damon_sysfs_filter_type_names[] = {
+ {
+ .type = DAMON_FILTER_TYPE_ANON,
+ .name = "anon",
+ },
+};
+
+static ssize_t type_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_filter *filter = container_of(kobj,
+ struct damon_sysfs_filter, kobj);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(damon_sysfs_filter_type_names); i++) {
+ const struct damon_sysfs_filter_type_name *type_name;
+
+ type_name = &damon_sysfs_filter_type_names[i];
+ if (type_name->type == filter->type)
+ return sysfs_emit(buf, "%s\n", type_name->name);
+ }
+ return -EINVAL;
+}
+
+static ssize_t type_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_filter *filter = container_of(kobj,
+ struct damon_sysfs_filter, kobj);
+ ssize_t ret = -EINVAL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(damon_sysfs_filter_type_names); i++) {
+ const struct damon_sysfs_filter_type_name *type_name;
+
+ type_name = &damon_sysfs_filter_type_names[i];
+ if (sysfs_streq(buf, type_name->name)) {
+ filter->type = type_name->type;
+ ret = count;
+ break;
+ }
+ }
+ return ret;
+}
+
+static ssize_t matching_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_filter *filter = container_of(kobj,
+ struct damon_sysfs_filter, kobj);
+
+ return sysfs_emit(buf, "%c\n", filter->matching ? 'Y' : 'N');
+}
+
+static ssize_t matching_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_filter *filter = container_of(kobj,
+ struct damon_sysfs_filter, kobj);
+ bool matching;
+ int err = kstrtobool(buf, &matching);
+
+ if (err)
+ return err;
+
+ filter->matching = matching;
+ return count;
+}
+
+static ssize_t allow_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_filter *filter = container_of(kobj,
+ struct damon_sysfs_filter, kobj);
+
+ return sysfs_emit(buf, "%c\n", filter->allow ? 'Y' : 'N');
+}
+
+static ssize_t allow_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_filter *filter = container_of(kobj,
+ struct damon_sysfs_filter, kobj);
+ bool allow;
+ int err = kstrtobool(buf, &allow);
+
+ if (err)
+ return err;
+
+ filter->allow = allow;
+ return count;
+}
+
static void damon_sysfs_filter_release(struct kobject *kobj)
{
struct damon_sysfs_filter *filter = container_of(kobj,
@@ -768,7 +870,19 @@ static void damon_sysfs_filter_release(struct kobject *kobj)
kfree(filter);
}
+static struct kobj_attribute damon_sysfs_filter_type_attr =
+ __ATTR_RW_MODE(type, 0600);
+
+static struct kobj_attribute damon_sysfs_filter_matching_attr =
+ __ATTR_RW_MODE(matching, 0600);
+
+static struct kobj_attribute damon_sysfs_filter_allow_attr =
+ __ATTR_RW_MODE(allow, 0600);
+
static struct attribute *damon_sysfs_filter_attrs[] = {
+ &damon_sysfs_filter_type_attr.attr,
+ &damon_sysfs_filter_matching_attr.attr,
+ &damon_sysfs_filter_allow_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(damon_sysfs_filter);
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 14/28] mm/damon/sysfs: setup probes on DAMON core API parameters
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (12 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 13/28] mm/damon/sysfs: implement filter dir files SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 15/28] mm/damon/sysfs-schemes: implement tried_regions/<r>/probes/ SeongJae Park
` (15 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Add user-installed data probes to DAMON core API parameters, so that
user inputs for data probes are passed to DAMON core.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index 35a4fa5c530f5..f1b7d79386866 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -1825,6 +1825,40 @@ static int damon_sysfs_set_attrs(struct damon_ctx *ctx,
return damon_set_attrs(ctx, &attrs);
}
+static int damon_sysfs_set_probes(struct damon_ctx *ctx,
+ struct damon_sysfs_probes *sys_probes)
+{
+ int i;
+
+ for (i = 0; i < sys_probes->nr; i++) {
+ struct damon_sysfs_filters *sys_filters =
+ sys_probes->probes_arr[i]->filters;
+ struct damon_probe *c;
+ int j;
+
+ if (!sys_filters)
+ continue;
+ c = damon_new_probe();
+ if (!c)
+ return -ENOMEM;
+ damon_add_probe(ctx, c);
+
+ for (j = 0; j < sys_filters->nr; j++) {
+ struct damon_sysfs_filter *sys_filter =
+ sys_filters->filters_arr[j];
+ struct damon_filter *filter;
+
+ filter = damon_new_filter(sys_filter->type,
+ sys_filter->matching,
+ sys_filter->allow);
+ if (!filter)
+ return -ENOMEM;
+ damon_add_filter(c, filter);
+ }
+ }
+ return 0;
+}
+
static int damon_sysfs_set_regions(struct damon_target *t,
struct damon_sysfs_regions *sysfs_regions,
unsigned long min_region_sz)
@@ -1936,6 +1970,9 @@ static int damon_sysfs_apply_inputs(struct damon_ctx *ctx,
ctx->min_region_sz = max(
DAMON_MIN_REGION_SZ / sys_ctx->addr_unit, 1);
err = damon_sysfs_set_attrs(ctx, sys_ctx->attrs);
+ if (err)
+ return err;
+ err = damon_sysfs_set_probes(ctx, sys_ctx->attrs->probes);
if (err)
return err;
err = damon_sysfs_add_targets(ctx, sys_ctx->targets);
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 15/28] mm/damon/sysfs-schemes: implement tried_regions/<r>/probes/
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (13 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 14/28] mm/damon/sysfs: setup probes on DAMON core API parameters SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 16/28] mm/damon/sysfs-schemes: implement probe dir SeongJae Park
` (14 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Implement a sysfs directory for showing the per-region probe hit counts.
It is named 'probes/' and located under the DAMOS tried region
directory.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs-schemes.c | 70 +++++++++++++++++++++++++++++++++++++---
1 file changed, 65 insertions(+), 5 deletions(-)
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index 245d63808411a..8998df5bdc5c8 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -10,6 +10,32 @@
#include "sysfs-common.h"
+/*
+ * probes directory
+ */
+
+struct damos_sysfs_probes {
+ struct kobject kobj;
+};
+
+static struct damos_sysfs_probes *damos_sysfs_probes_alloc(void)
+{
+ return kzalloc_obj(struct damos_sysfs_probes);
+}
+
+static void damos_sysfs_probes_release(struct kobject *kobj)
+{
+ struct damos_sysfs_probes *probes = container_of(kobj,
+ struct damos_sysfs_probes, kobj);
+
+ kfree(probes);
+}
+
+static const struct kobj_type damos_sysfs_probes_ktype = {
+ .release = damos_sysfs_probes_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+};
+
/*
* scheme region directory
*/
@@ -20,6 +46,7 @@ struct damon_sysfs_scheme_region {
unsigned int nr_accesses;
unsigned int age;
unsigned long sz_filter_passed;
+ struct damos_sysfs_probes *probes;
struct list_head list;
};
@@ -34,10 +61,36 @@ static struct damon_sysfs_scheme_region *damon_sysfs_scheme_region_alloc(
sysfs_region->ar = region->ar;
sysfs_region->nr_accesses = region->nr_accesses_bp / 10000;
sysfs_region->age = region->age;
+ sysfs_region->probes = NULL;
INIT_LIST_HEAD(&sysfs_region->list);
return sysfs_region;
}
+static int damos_sysfs_region_add_dirs(
+ struct damon_sysfs_scheme_region *region)
+{
+ struct damos_sysfs_probes *probes = damos_sysfs_probes_alloc();
+ int err;
+
+ if (!probes)
+ return -ENOMEM;
+ err = kobject_init_and_add(&probes->kobj, &damos_sysfs_probes_ktype,
+ ®ion->kobj, "probes");
+ if (err) {
+ kobject_put(&probes->kobj);
+ return err;
+ }
+
+ region->probes = probes;
+ return 0;
+}
+
+static void damos_sysfs_region_rm_dirs(
+ struct damon_sysfs_scheme_region *region)
+{
+ kobject_put(®ion->probes->kobj);
+}
+
static ssize_t start_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
@@ -165,6 +218,7 @@ static void damon_sysfs_scheme_regions_rm_dirs(
list_for_each_entry_safe(r, next, ®ions->regions_list, list) {
/* release function deletes it from the list */
+ damos_sysfs_region_rm_dirs(r);
kobject_put(&r->kobj);
regions->nr_regions--;
}
@@ -2927,14 +2981,20 @@ void damos_sysfs_populate_region_dir(struct damon_sysfs_schemes *sysfs_schemes,
if (!region)
return;
region->sz_filter_passed = sz_filter_passed;
- list_add_tail(®ion->list, &sysfs_regions->regions_list);
- sysfs_regions->nr_regions++;
if (kobject_init_and_add(®ion->kobj,
&damon_sysfs_scheme_region_ktype,
&sysfs_regions->kobj, "%d",
- sysfs_regions->nr_regions++)) {
- kobject_put(®ion->kobj);
- }
+ sysfs_regions->nr_regions++))
+ goto out;
+ if (damos_sysfs_region_add_dirs(region))
+ goto out;
+
+ list_add_tail(®ion->list, &sysfs_regions->regions_list);
+ sysfs_regions->nr_regions++;
+ return;
+
+out:
+ kobject_put(®ion->kobj);
}
int damon_sysfs_schemes_clear_regions(
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 16/28] mm/damon/sysfs-schemes: implement probe dir
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (14 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 15/28] mm/damon/sysfs-schemes: implement tried_regions/<r>/probes/ SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 17/28] mm/damon/sysfs-schemes: implement probe/hits file SeongJae Park
` (13 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Implement sysfs directory for showing per-probe hits count of each
region.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs-schemes.c | 101 ++++++++++++++++++++++++++++++++++++---
1 file changed, 95 insertions(+), 6 deletions(-)
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index 8998df5bdc5c8..c8123c62bbd48 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -10,12 +10,40 @@
#include "sysfs-common.h"
+/*
+ * probe directory
+ */
+
+struct damos_sysfs_probe {
+ struct kobject kobj;
+};
+
+static struct damos_sysfs_probe *damos_sysfs_probe_alloc(void)
+{
+ return kzalloc_obj(struct damos_sysfs_probe);
+}
+
+static void damos_sysfs_probe_release(struct kobject *kobj)
+{
+ struct damos_sysfs_probe *probe = container_of(kobj,
+ struct damos_sysfs_probe, kobj);
+
+ kfree(probe);
+}
+
+static const struct kobj_type damos_sysfs_probe_ktype = {
+ .release = damos_sysfs_probe_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+};
+
/*
* probes directory
*/
struct damos_sysfs_probes {
struct kobject kobj;
+ struct damos_sysfs_probe **probes_arr;
+ int nr;
};
static struct damos_sysfs_probes *damos_sysfs_probes_alloc(void)
@@ -23,6 +51,60 @@ static struct damos_sysfs_probes *damos_sysfs_probes_alloc(void)
return kzalloc_obj(struct damos_sysfs_probes);
}
+static void damos_sysfs_probes_rm_dirs(struct damos_sysfs_probes *probes)
+{
+ struct damos_sysfs_probe **probes_arr = probes->probes_arr;
+ int i;
+
+ for (i = 0; i < probes->nr; i++)
+ kobject_put(&probes_arr[i]->kobj);
+ probes->nr = 0;
+ kfree(probes_arr);
+ probes->probes_arr = NULL;
+}
+
+static int damos_sysfs_probes_add_dirs(struct damos_sysfs_probes *probes,
+ struct damon_ctx *ctx)
+{
+ struct damon_probe *probe;
+ struct damos_sysfs_probe **probes_arr;
+ int i = 0;
+
+ damon_for_each_probe(probe, ctx)
+ i++;
+
+ if (!i)
+ return 0;
+
+ probes_arr = kmalloc_objs(*probes_arr, i);
+ if (!probes_arr)
+ return -ENOMEM;
+ probes->probes_arr = probes_arr;
+
+ i = 0;
+ damon_for_each_probe(probe, ctx) {
+ struct damos_sysfs_probe *sys_probe;
+ int err;
+
+ sys_probe = damos_sysfs_probe_alloc();
+ if (!sys_probe) {
+ damos_sysfs_probes_rm_dirs(probes);
+ return -ENOMEM;
+ }
+ err = kobject_init_and_add(&sys_probe->kobj,
+ &damos_sysfs_probe_ktype, &probes->kobj, "%d",
+ i);
+ if (err) {
+ kobject_put(&sys_probe->kobj);
+ damos_sysfs_probes_rm_dirs(probes);
+ return err;
+ }
+ probes_arr[i++] = sys_probe;
+ probes->nr++;
+ }
+ return 0;
+}
+
static void damos_sysfs_probes_release(struct kobject *kobj)
{
struct damos_sysfs_probes *probes = container_of(kobj,
@@ -67,7 +149,8 @@ static struct damon_sysfs_scheme_region *damon_sysfs_scheme_region_alloc(
}
static int damos_sysfs_region_add_dirs(
- struct damon_sysfs_scheme_region *region)
+ struct damon_sysfs_scheme_region *region,
+ struct damon_ctx *ctx)
{
struct damos_sysfs_probes *probes = damos_sysfs_probes_alloc();
int err;
@@ -76,18 +159,24 @@ static int damos_sysfs_region_add_dirs(
return -ENOMEM;
err = kobject_init_and_add(&probes->kobj, &damos_sysfs_probes_ktype,
®ion->kobj, "probes");
- if (err) {
- kobject_put(&probes->kobj);
- return err;
- }
+ if (err)
+ goto fail;
+ err = damos_sysfs_probes_add_dirs(probes, ctx);
+ if (err)
+ goto fail;
region->probes = probes;
return 0;
+
+fail:
+ kobject_put(&probes->kobj);
+ return err;
}
static void damos_sysfs_region_rm_dirs(
struct damon_sysfs_scheme_region *region)
{
+ damos_sysfs_probes_rm_dirs(region->probes);
kobject_put(®ion->probes->kobj);
}
@@ -2986,7 +3075,7 @@ void damos_sysfs_populate_region_dir(struct damon_sysfs_schemes *sysfs_schemes,
&sysfs_regions->kobj, "%d",
sysfs_regions->nr_regions++))
goto out;
- if (damos_sysfs_region_add_dirs(region))
+ if (damos_sysfs_region_add_dirs(region, ctx))
goto out;
list_add_tail(®ion->list, &sysfs_regions->regions_list);
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 17/28] mm/damon/sysfs-schemes: implement probe/hits file
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (15 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 16/28] mm/damon/sysfs-schemes: implement probe dir SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 18/28] mm/damon: trace probe_hits SeongJae Park
` (12 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Implement sysfs file for showing the per-region per-probe hits count.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs-schemes.c | 41 +++++++++++++++++++++++++++++++++-------
1 file changed, 34 insertions(+), 7 deletions(-)
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index c8123c62bbd48..d680c785770a9 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -16,11 +16,27 @@
struct damos_sysfs_probe {
struct kobject kobj;
+ unsigned char hits;
};
-static struct damos_sysfs_probe *damos_sysfs_probe_alloc(void)
+static struct damos_sysfs_probe *damos_sysfs_probe_alloc(unsigned char hits)
{
- return kzalloc_obj(struct damos_sysfs_probe);
+ struct damos_sysfs_probe *probe;
+
+ probe = kzalloc_obj(*probe);
+ if (!probe)
+ return NULL;
+ probe->hits = hits;
+ return probe;
+}
+
+static ssize_t hits_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct damos_sysfs_probe *probe = container_of(kobj,
+ struct damos_sysfs_probe, kobj);
+
+ return sysfs_emit(buf, "%hhu\n", probe->hits);
}
static void damos_sysfs_probe_release(struct kobject *kobj)
@@ -31,9 +47,19 @@ static void damos_sysfs_probe_release(struct kobject *kobj)
kfree(probe);
}
+static struct kobj_attribute damos_sysfs_probe_hits_attr =
+ __ATTR_RO_MODE(hits, 0400);
+
+static struct attribute *damos_sysfs_probe_attrs[] = {
+ &damos_sysfs_probe_hits_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(damos_sysfs_probe);
+
static const struct kobj_type damos_sysfs_probe_ktype = {
.release = damos_sysfs_probe_release,
.sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = damos_sysfs_probe_groups,
};
/*
@@ -64,7 +90,7 @@ static void damos_sysfs_probes_rm_dirs(struct damos_sysfs_probes *probes)
}
static int damos_sysfs_probes_add_dirs(struct damos_sysfs_probes *probes,
- struct damon_ctx *ctx)
+ struct damon_ctx *ctx, struct damon_region *region)
{
struct damon_probe *probe;
struct damos_sysfs_probe **probes_arr;
@@ -86,7 +112,7 @@ static int damos_sysfs_probes_add_dirs(struct damos_sysfs_probes *probes,
struct damos_sysfs_probe *sys_probe;
int err;
- sys_probe = damos_sysfs_probe_alloc();
+ sys_probe = damos_sysfs_probe_alloc(region->probe_hits[i]);
if (!sys_probe) {
damos_sysfs_probes_rm_dirs(probes);
return -ENOMEM;
@@ -150,7 +176,8 @@ static struct damon_sysfs_scheme_region *damon_sysfs_scheme_region_alloc(
static int damos_sysfs_region_add_dirs(
struct damon_sysfs_scheme_region *region,
- struct damon_ctx *ctx)
+ struct damon_ctx *ctx,
+ struct damon_region *dregion)
{
struct damos_sysfs_probes *probes = damos_sysfs_probes_alloc();
int err;
@@ -161,7 +188,7 @@ static int damos_sysfs_region_add_dirs(
®ion->kobj, "probes");
if (err)
goto fail;
- err = damos_sysfs_probes_add_dirs(probes, ctx);
+ err = damos_sysfs_probes_add_dirs(probes, ctx, dregion);
if (err)
goto fail;
@@ -3075,7 +3102,7 @@ void damos_sysfs_populate_region_dir(struct damon_sysfs_schemes *sysfs_schemes,
&sysfs_regions->kobj, "%d",
sysfs_regions->nr_regions++))
goto out;
- if (damos_sysfs_region_add_dirs(region, ctx))
+ if (damos_sysfs_region_add_dirs(region, ctx, r))
goto out;
list_add_tail(®ion->list, &sysfs_regions->regions_list);
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 18/28] mm/damon: trace probe_hits
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (16 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 17/28] mm/damon/sysfs-schemes: implement probe/hits file SeongJae Park
@ 2026-05-16 18:36 ` SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 19/28] selftests/damon/sysfs.sh: test probes dir SeongJae Park
` (11 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, Masami Hiramatsu, Mathieu Desnoyers,
Steven Rostedt, damon, linux-kernel, linux-mm, linux-trace-kernel
Introduce a new tracepoint for exposing the per-region per-probe
positive sample count via tracefs.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/trace/events/damon.h | 38 ++++++++++++++++++++++++++++++++++++
mm/damon/core.c | 9 +++++++++
2 files changed, 47 insertions(+)
diff --git a/include/trace/events/damon.h b/include/trace/events/damon.h
index 24fc402ab3c85..2fd914895c405 100644
--- a/include/trace/events/damon.h
+++ b/include/trace/events/damon.h
@@ -130,6 +130,44 @@ TRACE_EVENT(damon_monitor_intervals_tune,
TP_printk("sample_us=%lu", __entry->sample_us)
);
+TRACE_EVENT_CONDITION(damon_region_aggregated,
+
+ TP_PROTO(unsigned int target_id, struct damon_region *r,
+ unsigned int nr_regions, unsigned int nr_probes),
+
+ TP_ARGS(target_id, r, nr_regions, nr_probes),
+
+ TP_CONDITION(nr_probes > 0),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, target_id)
+ __field(unsigned long, start)
+ __field(unsigned long, end)
+ __field(unsigned int, nr_regions)
+ __field(unsigned int, nr_accesses)
+ __field(unsigned int, age)
+ __dynamic_array(unsigned char, probe_hits, nr_probes)
+ ),
+
+ TP_fast_assign(
+ __entry->target_id = target_id;
+ __entry->start = r->ar.start;
+ __entry->end = r->ar.end;
+ __entry->nr_regions = nr_regions;
+ __entry->nr_accesses = r->nr_accesses;
+ __entry->age = r->age;
+ memcpy(__get_dynamic_array(probe_hits), r->probe_hits,
+ sizeof(*r->probe_hits) * nr_probes);
+ ),
+
+ TP_printk("target_id=%lu nr_regions=%u %lu-%lu: %u %u probe_hits=%s",
+ __entry->target_id, __entry->nr_regions,
+ __entry->start, __entry->end,
+ __entry->nr_accesses, __entry->age,
+ __print_hex(__get_dynamic_array(probe_hits),
+ __get_dynamic_array_len(probe_hits)))
+);
+
TRACE_EVENT(damon_aggregated,
TP_PROTO(unsigned int target_id, struct damon_region *r,
diff --git a/mm/damon/core.c b/mm/damon/core.c
index dde3c8d8fef89..11b513eb077fe 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1881,6 +1881,13 @@ static void kdamond_reset_aggregated(struct damon_ctx *c)
{
struct damon_target *t;
unsigned int ti = 0; /* target's index */
+ unsigned int nr_probes = 0;
+ struct damon_probe *probe;
+
+ if (trace_damon_region_aggregated_enabled()) {
+ damon_for_each_probe(probe, c)
+ nr_probes++;
+ }
damon_for_each_target(t, c) {
struct damon_region *r;
@@ -1889,6 +1896,8 @@ static void kdamond_reset_aggregated(struct damon_ctx *c)
int i;
trace_damon_aggregated(ti, r, damon_nr_regions(t));
+ trace_damon_region_aggregated(ti, r,
+ damon_nr_regions(t), nr_probes);
damon_warn_fix_nr_accesses_corruption(r);
r->last_nr_accesses = r->nr_accesses;
r->nr_accesses = 0;
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 19/28] selftests/damon/sysfs.sh: test probes dir
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (17 preceding siblings ...)
2026-05-16 18:36 ` [RFC PATCH v3 18/28] mm/damon: trace probe_hits SeongJae Park
@ 2026-05-16 18:37 ` SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 20/28] Docs/mm/damon/design: document data attributes monitoring SeongJae Park
` (10 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:37 UTC (permalink / raw)
Cc: SeongJae Park, Shuah Khan, damon, linux-kernel, linux-kselftest,
linux-mm
Add simple existence tests for data probes sysfs directories and files.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
tools/testing/selftests/damon/sysfs.sh | 48 ++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/tools/testing/selftests/damon/sysfs.sh b/tools/testing/selftests/damon/sysfs.sh
index 83e3b7f63d81c..1ac3e2ce8e448 100755
--- a/tools/testing/selftests/damon/sysfs.sh
+++ b/tools/testing/selftests/damon/sysfs.sh
@@ -291,11 +291,59 @@ test_intervals()
ensure_file "$intervals_dir/update_us" "exist" "600"
}
+test_damon_filter()
+{
+ damon_filter_dir=$1
+ ensure_file "$damon_filter_dir/type" "exist" "600"
+ ensure_write_succ "$damon_filter_dir/type" "anon" "valid input"
+ ensure_write_fail "$damon_filter_dir/type" "foo" "invalid input"
+ ensure_file "$damon_filter_dir/matching" "exist" "600"
+ ensure_file "$damon_filter_dir/allow" "exist" "600"
+}
+
+test_damon_filters()
+{
+ filters_dir=$1
+ ensure_dir "$filters_dir" "exist"
+ ensure_file "$filters_dir/nr_filters" "exist" "600"
+ ensure_write_succ "$filters_dir/nr_filters" "1" "valid input"
+ test_damon_filter "$filters_dir/0"
+
+ ensure_write_succ "$filters_dir/nr_filters" "2" "valid input"
+ test_damon_filter "$filters_dir/0"
+ test_damon_filter "$filters_dir/1"
+
+ ensure_write_succ "$filters_dir/nr_filters" "0" "valid input"
+ ensure_dir "$filters_dir/0" "not_exist"
+ ensure_dir "$filters_dir/1" "not_exist"
+}
+
+test_probe()
+{
+ probe_dir=$1
+ ensure_dir "$probe_dir" "exist"
+ test_damon_filters "$probe_dir/filters"
+}
+
+test_probes()
+{
+ probes_dir=$1
+ ensure_dir "$probes_dir" "exist"
+ ensure_file "$probes_dir/nr_probes" "exist" "600"
+
+ ensure_write_succ "$probes_dir/nr_probes" "1" "valid input"
+ test_probe "$probes_dir/0"
+
+ ensure_write_succ "$probes_dir/nr_probes" "0" "valid input"
+ ensure_dir "$probes_dir/0" "not_exist"
+}
+
test_monitoring_attrs()
{
monitoring_attrs_dir=$1
ensure_dir "$monitoring_attrs_dir" "exist"
test_intervals "$monitoring_attrs_dir/intervals"
+ test_probes "$monitoring_attrs_dir/probes"
test_range "$monitoring_attrs_dir/nr_regions"
}
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 20/28] Docs/mm/damon/design: document data attributes monitoring
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (18 preceding siblings ...)
2026-05-16 18:37 ` [RFC PATCH v3 19/28] selftests/damon/sysfs.sh: test probes dir SeongJae Park
@ 2026-05-16 18:37 ` SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 21/28] Docs/admin-guide/mm/damon/usage: " SeongJae Park
` (9 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:37 UTC (permalink / raw)
Cc: SeongJae Park, Liam R. Howlett, Andrew Morton, 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 newly added data attributes monitoring
feature.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
Documentation/mm/damon/design.rst | 37 +++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst
index afc7d52bda2f7..aa08c899a3e5b 100644
--- a/Documentation/mm/damon/design.rst
+++ b/Documentation/mm/damon/design.rst
@@ -269,6 +269,43 @@ interval``, DAMON checks if the region's size and access frequency
(``nr_accesses``) has significantly changed. If so, the counter is reset to
zero. Otherwise, the counter is increased.
+Data Attributes Monitoring
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Data access pattern is only one type of data attributes. In some use cases,
+users need to know more data attributes information. For example, users may
+need to know how much of a given hot or cold memory region is backed by
+anonymous pages, or belong to a specific cgroup. For such use case, data
+attributes monitoring feature is provided.
+
+Using the feature, users can register data attributes of their interest to the
+DAMON :ref:`context <damon_design_execution_model_and_data_structures>`. The
+registration is made by specifying a probe per attribute. Each of the probe
+specifies a rule to determine if a given memory region has the related
+attribute. The rule is constructed with multiple filters. The filters work
+same to :ref:`DAMOS filters <damon_design_damos_filters>` except the supported
+filter types. Currently only ``anon`` filter type is supported for data
+attributes monitoring.
+
+If such probes are registered, DAMON executes the probes for each region's
+sampling memory when it does the access :ref:`sampling
+<damon_design_region_based_sampling>`. The number of samples that identified
+as having the data attribute (hitting the probe) per :ref:`aggregation interval
+<damon_design_monitoring>` is accounted in a per-region per-probe counter.
+Users can therefore know how much of a given DAMON region has a specific data
+attribute by reading the per-region per-probe probe hits counter after each
+aggregation interval.
+
+This is a sampling based mechanism. Hence, it is lightweight but the output
+may include some measurement errors. The output should be used with good
+understanding of statistics.
+
+Another way to do this for higher accuracy is using :ref:`DAMOS filter
+<damon_design_damos_filters>` with ``stat`` :ref:`action
+<damon_design_damos_action>` and ``sz_ops_filter_passed`` :ref:`stat
+<damon_design_damos_stat>`. This approach provides the data attributes
+information in page level. But, because it is operated in page level, the
+overhead is proportional to the size of the memory.
Dynamic Target Space Updates Handling
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 21/28] Docs/admin-guide/mm/damon/usage: document data attributes monitoring
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (19 preceding siblings ...)
2026-05-16 18:37 ` [RFC PATCH v3 20/28] Docs/mm/damon/design: document data attributes monitoring SeongJae Park
@ 2026-05-16 18:37 ` SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 22/28] mm/damon/core: introduce DAMON_FILTER_TYPE_MEMCG SeongJae Park
` (8 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:37 UTC (permalink / raw)
Cc: SeongJae Park, Liam R. Howlett, Andrew Morton, 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 the newly added data attributes
monitoring feature.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
Documentation/admin-guide/mm/damon/usage.rst | 44 ++++++++++++++++++--
Documentation/mm/damon/design.rst | 2 +
2 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst
index 534e1199cf091..7b6074a1666f3 100644
--- a/Documentation/admin-guide/mm/damon/usage.rst
+++ b/Documentation/admin-guide/mm/damon/usage.rst
@@ -71,6 +71,11 @@ comma (",").
│ │ │ │ │ │ intervals/sample_us,aggr_us,update_us
│ │ │ │ │ │ │ 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
+ │ │ │ │ │ │ │ │ ...
+ │ │ │ │ │ │ │ ...
│ │ │ │ │ :ref:`targets <sysfs_targets>`/nr_targets
│ │ │ │ │ │ :ref:`0 <sysfs_target>`/pid_target,obsolete_target
│ │ │ │ │ │ │ :ref:`regions <sysfs_regions>`/nr_regions
@@ -95,6 +100,9 @@ comma (",").
│ │ │ │ │ │ │ :ref:`stats <sysfs_schemes_stats>`/nr_tried,sz_tried,nr_applied,sz_applied,sz_ops_filter_passed,qt_exceeds,nr_snapshots,max_nr_snapshots
│ │ │ │ │ │ │ :ref:`tried_regions <sysfs_schemes_tried_regions>`/total_bytes
│ │ │ │ │ │ │ │ 0/start,end,nr_accesses,age,sz_filter_passed
+ │ │ │ │ │ │ │ │ │ probes
+ │ │ │ │ │ │ │ │ │ │ 0/hits
+ │ │ │ │ │ │ │ │ │ │ ...
│ │ │ │ │ │ │ │ ...
│ │ │ │ │ │ ...
│ │ │ │ ...
@@ -221,8 +229,8 @@ contexts/<N>/monitoring_attrs/
Files for specifying attributes of the monitoring including required quality
and efficiency of the monitoring are in ``monitoring_attrs`` directory.
-Specifically, two directories, ``intervals`` and ``nr_regions`` exist in this
-directory.
+Specifically, three directories, ``intervals``, ``nr_regions`` and ``probes``
+exist in this directory.
Under ``intervals`` directory, three files for DAMON's sampling interval
(``sample_us``), aggregation interval (``aggr_us``), and update interval
@@ -256,6 +264,27 @@ tuning-applied current values of the two intervals can be read from the
``sample_us`` and ``aggr_us`` files after writing ``update_tuned_intervals`` to
the ``state`` file.
+.. _damon_usage_sysfs_probes:
+
+contexts/<N>/monitoring_attrs/probes/
+-------------------------------------
+
+A directory for registering :ref:`data attributes monitoring
+<damon_design_data_attrs_monitoring>` probes.
+
+In the beginning, this directory has only one file, ``nr_probes``. Writing a
+number (``N``) to the file creates the number of child directories named ``0``
+to ``N-1``. Each directory represents each monitoring probe.
+
+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.
+
+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
+way similar to that for :ref:`DAMOS filter <sysfs_filters>`.
+
.. _sysfs_targets:
contexts/<N>/targets/
@@ -601,10 +630,19 @@ tried_regions/<N>/
------------------
In each region directory, you will find five files (``start``, ``end``,
-``nr_accesses``, ``age``, and ``sz_filter_passed``). Reading the files will
+``nr_accesses``, ``age`` and ``sz_filter_passed``). Reading the files will
show the properties of the region that corresponding DAMON-based operation
scheme ``action`` has tried to be applied.
+tried_regions/<N>/probes/
+-------------------------
+
+In each region directory, one directory (``probes``) also exists. In the
+directory, subdirectories named ``0`` to ``N-1`` exists. ``N`` is the number
+of installed probes. In each number-named directory, a file (``hits``) exist.
+Reading the file shows the number of data attributes monitoring probe-hit
+positive samples of the region.
+
Example
~~~~~~~
diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst
index aa08c899a3e5b..85d668e929194 100644
--- a/Documentation/mm/damon/design.rst
+++ b/Documentation/mm/damon/design.rst
@@ -269,6 +269,8 @@ interval``, DAMON checks if the region's size and access frequency
(``nr_accesses``) has significantly changed. If so, the counter is reset to
zero. Otherwise, the counter is increased.
+.. _damon_design_data_attrs_monitoring:
+
Data Attributes Monitoring
~~~~~~~~~~~~~~~~~~~~~~~~~~
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 22/28] mm/damon/core: introduce DAMON_FILTER_TYPE_MEMCG
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (20 preceding siblings ...)
2026-05-16 18:37 ` [RFC PATCH v3 21/28] Docs/admin-guide/mm/damon/usage: " SeongJae Park
@ 2026-05-16 18:37 ` SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 23/28] mm/damon/paddr: support DAMON_FILTER_TYPE_MEMCG SeongJae Park
` (7 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:37 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Belonging memory cgoup is another data attribute that can be useful to
monitor. Introduce a new DAMON filter type, namely
DAMON_FILTER_TYPE_MEMCG, for monitoring of this attribute.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/linux/damon.h | 6 ++++++
mm/damon/core.c | 14 ++++++++++++++
2 files changed, 20 insertions(+)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index d3b6296700a08..56a76781fde22 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -733,9 +733,11 @@ struct damon_intervals_goal {
* enum damon_filter_type - Type of &struct damon_filter
*
* @DAMON_FILTER_TYPE_ANON: Anonymous pages.
+ * @DAMON_FILTER_TYPE_MEMCG: Specific memcg's pages.
*/
enum damon_filter_type {
DAMON_FILTER_TYPE_ANON,
+ DAMON_FILTER_TYPE_MEMCG,
};
/**
@@ -744,12 +746,16 @@ enum damon_filter_type {
* @type: Type of the region.
* @matching: Whether this filter is for the type-matching ones.
* @allow: Whether the @type-@matching ones should pass this filter.
+ * @memcg_id: Memcg id of the question if @type is DAMON_FILTER_MEMCG.
* @list: Siblings list.
*/
struct damon_filter {
enum damon_filter_type type;
bool matching;
bool allow;
+ union {
+ u64 memcg_id;
+ };
struct list_head list;
};
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 11b513eb077fe..332d13d9f8603 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1422,6 +1422,13 @@ static void damon_commit_filter(struct damon_filter *dst,
dst->type = src->type;
dst->matching = src->matching;
dst->allow = src->allow;
+ switch (dst->type) {
+ case DAMON_FILTER_TYPE_MEMCG:
+ dst->memcg_id = src->memcg_id;
+ break;
+ default:
+ break;
+ }
}
static int damon_commit_filters(struct damon_probe *dst,
@@ -1446,6 +1453,13 @@ static int damon_commit_filters(struct damon_probe *dst,
src_filter->matching, src_filter->allow);
if (!new_filter)
return -ENOMEM;
+ switch (src_filter->type) {
+ case DAMON_FILTER_TYPE_MEMCG:
+ new_filter->memcg_id = src_filter->memcg_id;
+ break;
+ default:
+ break;
+ }
damon_add_filter(dst, new_filter);
}
return 0;
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 23/28] mm/damon/paddr: support DAMON_FILTER_TYPE_MEMCG
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (21 preceding siblings ...)
2026-05-16 18:37 ` [RFC PATCH v3 22/28] mm/damon/core: introduce DAMON_FILTER_TYPE_MEMCG SeongJae Park
@ 2026-05-16 18:37 ` SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 24/28] mm/damon/sysfs: add filters/<F>/path file SeongJae Park
` (6 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:37 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Implement the support of DAMON_FILTER_TYPE_MEMCG on the DAMON operation
set implementation for the physical address space.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/paddr.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
index 81780b05c175e..ad5a65f2398f0 100644
--- a/mm/damon/paddr.c
+++ b/mm/damon/paddr.c
@@ -124,6 +124,7 @@ static bool damon_pa_filter_match(struct damon_filter *filter,
struct folio *folio)
{
bool matched = false;
+ struct mem_cgroup *memcg;
switch (filter->type) {
case DAMON_FILTER_TYPE_ANON:
@@ -133,6 +134,19 @@ static bool damon_pa_filter_match(struct damon_filter *filter,
}
matched = folio_test_anon(folio);
break;
+ case DAMON_FILTER_TYPE_MEMCG:
+ if (!folio) {
+ matched = false;
+ break;
+ }
+ rcu_read_lock();
+ memcg = folio_memcg_check(folio);
+ if (!memcg)
+ matched = false;
+ else
+ matched = filter->memcg_id == mem_cgroup_id(memcg);
+ rcu_read_unlock();
+ break;
default:
break;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 24/28] mm/damon/sysfs: add filters/<F>/path file
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (22 preceding siblings ...)
2026-05-16 18:37 ` [RFC PATCH v3 23/28] mm/damon/paddr: support DAMON_FILTER_TYPE_MEMCG SeongJae Park
@ 2026-05-16 18:37 ` SeongJae Park
2026-05-16 19:29 ` sashiko-bot
2026-05-16 18:37 ` [RFC PATCH v3 25/28] mm/damon/sysfs-schemes: move memcg_path_to_id() to sysfs-common SeongJae Park
` (5 subsequent siblings)
29 siblings, 1 reply; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:37 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Introduce a new DAMON sysfs file for letting users setup the target
memory cgroup of the belonging memory cgroup attribute monitoring. The
file is named 'path', located under the probe filter directory. Users
can set the target memory cgroup by writing the path to the memory
cgroup from the cgroup mount point to the file.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index f1b7d79386866..2df1d670ee77d 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -756,6 +756,7 @@ struct damon_sysfs_filter {
enum damon_filter_type type;
bool matching;
bool allow;
+ char *path;
};
static struct damon_sysfs_filter *damon_sysfs_filter_alloc(void)
@@ -774,6 +775,10 @@ damon_sysfs_filter_type_names[] = {
.type = DAMON_FILTER_TYPE_ANON,
.name = "anon",
},
+ {
+ .type = DAMON_FILTER_TYPE_MEMCG,
+ .name = "memcg",
+ },
};
static ssize_t type_show(struct kobject *kobj,
@@ -862,11 +867,46 @@ static ssize_t allow_store(struct kobject *kobj,
return count;
}
+static ssize_t path_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_filter *filter = container_of(kobj,
+ struct damon_sysfs_filter, kobj);
+ int len;
+
+ if (!mutex_trylock(&damon_sysfs_lock))
+ return -EBUSY;
+ len = sysfs_emit(buf, "%s\n", filter->path ? filter->path : "");
+ mutex_unlock(&damon_sysfs_lock);
+ return len;
+}
+
+static ssize_t path_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_filter *filter = container_of(kobj,
+ struct damon_sysfs_filter, kobj);
+ char *path = kmalloc_objs(*path, size_add(count, 1));
+
+ if (!path)
+ return -ENOMEM;
+ strscpy(path, buf, size_add(count, 1));
+ if (!mutex_trylock(&damon_sysfs_lock)) {
+ kfree(path);
+ return -EBUSY;
+ }
+ kfree(filter->path);
+ filter->path = path;
+ mutex_unlock(&damon_sysfs_lock);
+ return count;
+}
+
static void damon_sysfs_filter_release(struct kobject *kobj)
{
struct damon_sysfs_filter *filter = container_of(kobj,
struct damon_sysfs_filter, kobj);
+ kfree(filter->path);
kfree(filter);
}
@@ -879,10 +919,14 @@ static struct kobj_attribute damon_sysfs_filter_matching_attr =
static struct kobj_attribute damon_sysfs_filter_allow_attr =
__ATTR_RW_MODE(allow, 0600);
+static struct kobj_attribute damon_sysfs_filter_path_attr =
+ __ATTR_RW_MODE(path, 0600);
+
static struct attribute *damon_sysfs_filter_attrs[] = {
&damon_sysfs_filter_type_attr.attr,
&damon_sysfs_filter_matching_attr.attr,
&damon_sysfs_filter_allow_attr.attr,
+ &damon_sysfs_filter_path_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(damon_sysfs_filter);
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 25/28] mm/damon/sysfs-schemes: move memcg_path_to_id() to sysfs-common
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (23 preceding siblings ...)
2026-05-16 18:37 ` [RFC PATCH v3 24/28] mm/damon/sysfs: add filters/<F>/path file SeongJae Park
@ 2026-05-16 18:37 ` SeongJae Park
2026-05-16 19:16 ` sashiko-bot
2026-05-16 18:37 ` [RFC PATCH v3 26/28] mm/damon/sysfs: setup damon_filter->memcg_id from path SeongJae Park
` (4 subsequent siblings)
29 siblings, 1 reply; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:37 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
The next commit will need to find the memcg id from the user-passed path
to the memory cgroup, from sysfs.c. memcg_path_to_id() is doing that,
but defined in sysfs-schemes.c as a static function. Move the function
to sysfs-common.c and mark it as non-static, so that the next commit can
reuse the function.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs-common.c | 41 ++++++++++++++++++++++++++++++++++++++++
mm/damon/sysfs-common.h | 2 ++
mm/damon/sysfs-schemes.c | 40 ---------------------------------------
3 files changed, 43 insertions(+), 40 deletions(-)
diff --git a/mm/damon/sysfs-common.c b/mm/damon/sysfs-common.c
index 83e24a9b5a0db..bdc6ae2639e4f 100644
--- a/mm/damon/sysfs-common.c
+++ b/mm/damon/sysfs-common.c
@@ -104,3 +104,44 @@ const struct kobj_type damon_sysfs_ul_range_ktype = {
.default_groups = damon_sysfs_ul_range_groups,
};
+
+static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg,
+ char *memcg_path_buf, char *path)
+{
+#ifdef CONFIG_MEMCG
+ cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX);
+ if (sysfs_streq(memcg_path_buf, path))
+ return true;
+#endif /* CONFIG_MEMCG */
+ return false;
+}
+
+int damon_sysfs_memcg_path_to_id(char *memcg_path, u64 *id)
+{
+ struct mem_cgroup *memcg;
+ char *path;
+ bool found = false;
+
+ if (!memcg_path)
+ return -EINVAL;
+
+ path = kmalloc_array(PATH_MAX, sizeof(*path), GFP_KERNEL);
+ if (!path)
+ return -ENOMEM;
+
+ for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg;
+ memcg = mem_cgroup_iter(NULL, memcg, NULL)) {
+ /* skip offlined memcg */
+ if (!mem_cgroup_online(memcg))
+ continue;
+ if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) {
+ *id = mem_cgroup_id(memcg);
+ found = true;
+ mem_cgroup_iter_break(NULL, memcg);
+ break;
+ }
+ }
+
+ kfree(path);
+ return found ? 0 : -EINVAL;
+}
diff --git a/mm/damon/sysfs-common.h b/mm/damon/sysfs-common.h
index 2099adee11d05..3079306966a91 100644
--- a/mm/damon/sysfs-common.h
+++ b/mm/damon/sysfs-common.h
@@ -59,3 +59,5 @@ int damos_sysfs_set_quota_scores(struct damon_sysfs_schemes *sysfs_schemes,
void damos_sysfs_update_effective_quotas(
struct damon_sysfs_schemes *sysfs_schemes,
struct damon_ctx *ctx);
+
+int damon_sysfs_memcg_path_to_id(char *memcg_path, u64 *id);
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index d680c785770a9..9462aba9c6cbc 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -2732,46 +2732,6 @@ const struct kobj_type damon_sysfs_schemes_ktype = {
.default_groups = damon_sysfs_schemes_groups,
};
-static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg,
- char *memcg_path_buf, char *path)
-{
-#ifdef CONFIG_MEMCG
- cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX);
- if (sysfs_streq(memcg_path_buf, path))
- return true;
-#endif /* CONFIG_MEMCG */
- return false;
-}
-
-static int damon_sysfs_memcg_path_to_id(char *memcg_path, u64 *id)
-{
- struct mem_cgroup *memcg;
- char *path;
- bool found = false;
-
- if (!memcg_path)
- return -EINVAL;
-
- path = kmalloc_array(PATH_MAX, sizeof(*path), GFP_KERNEL);
- if (!path)
- return -ENOMEM;
-
- for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg;
- memcg = mem_cgroup_iter(NULL, memcg, NULL)) {
- /* skip offlined memcg */
- if (!mem_cgroup_online(memcg))
- continue;
- if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) {
- *id = mem_cgroup_id(memcg);
- found = true;
- break;
- }
- }
-
- kfree(path);
- return found ? 0 : -EINVAL;
-}
-
static int damon_sysfs_add_scheme_filters(struct damos *scheme,
struct damon_sysfs_scheme_filters *sysfs_filters)
{
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 26/28] mm/damon/sysfs: setup damon_filter->memcg_id from path
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (24 preceding siblings ...)
2026-05-16 18:37 ` [RFC PATCH v3 25/28] mm/damon/sysfs-schemes: move memcg_path_to_id() to sysfs-common SeongJae Park
@ 2026-05-16 18:37 ` SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 27/28] Docs/mm/damon/design: update for memcg damon filter SeongJae Park
` (3 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:37 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, damon, linux-kernel, linux-mm
Find and set the memcg_id for damon_filter from the user-passed memory
cgroup path when updating the DAMON input parameters.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/linux/damon.h | 1 +
mm/damon/core.c | 2 +-
mm/damon/sysfs.c | 11 +++++++++++
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 56a76781fde22..cd0c352a777dc 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -976,6 +976,7 @@ static inline unsigned long damon_sz_region(struct damon_region *r)
struct damon_filter *damon_new_filter(enum damon_filter_type type,
bool matching, bool allow);
void damon_add_filter(struct damon_probe *probe, struct damon_filter *f);
+void damon_destroy_filter(struct damon_filter *f);
struct damon_probe *damon_new_probe(void);
void damon_add_probe(struct damon_ctx *ctx, struct damon_probe *probe);
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 332d13d9f8603..b8fe4320c3da8 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -139,7 +139,7 @@ static void damon_free_filter(struct damon_filter *f)
kfree(f);
}
-static void damon_destroy_filter(struct damon_filter *f)
+void damon_destroy_filter(struct damon_filter *f)
{
damon_del_filter(f);
damon_free_filter(f);
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index 2df1d670ee77d..8f927e3dba827 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -1897,6 +1897,17 @@ static int damon_sysfs_set_probes(struct damon_ctx *ctx,
sys_filter->allow);
if (!filter)
return -ENOMEM;
+ if (filter->type == DAMON_FILTER_TYPE_MEMCG) {
+ int err;
+
+ err = damon_sysfs_memcg_path_to_id(
+ sys_filter->path,
+ &filter->memcg_id);
+ if (err) {
+ damon_destroy_filter(filter);
+ return err;
+ }
+ }
damon_add_filter(c, filter);
}
}
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 27/28] Docs/mm/damon/design: update for memcg damon filter
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (25 preceding siblings ...)
2026-05-16 18:37 ` [RFC PATCH v3 26/28] mm/damon/sysfs: setup damon_filter->memcg_id from path SeongJae Park
@ 2026-05-16 18:37 ` SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 28/28] Docs/admin-guide/mm/damon/usage: " SeongJae Park
` (2 subsequent siblings)
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:37 UTC (permalink / raw)
Cc: SeongJae Park, Liam R. Howlett, Andrew Morton, 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 newly added belonging memory cgroup
attribute monitoring feature.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
Documentation/mm/damon/design.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst
index 85d668e929194..8a2d68cbcefca 100644
--- a/Documentation/mm/damon/design.rst
+++ b/Documentation/mm/damon/design.rst
@@ -286,8 +286,8 @@ registration is made by specifying a probe per attribute. Each of the probe
specifies a rule to determine if a given memory region has the related
attribute. The rule is constructed with multiple filters. The filters work
same to :ref:`DAMOS filters <damon_design_damos_filters>` except the supported
-filter types. Currently only ``anon`` filter type is supported for data
-attributes monitoring.
+filter types. Currently only ``anon`` and ``memcg`` filter types are supported
+for data attributes monitoring.
If such probes are registered, DAMON executes the probes for each region's
sampling memory when it does the access :ref:`sampling
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [RFC PATCH v3 28/28] Docs/admin-guide/mm/damon/usage: update for memcg damon filter
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (26 preceding siblings ...)
2026-05-16 18:37 ` [RFC PATCH v3 27/28] Docs/mm/damon/design: update for memcg damon filter SeongJae Park
@ 2026-05-16 18:37 ` SeongJae Park
2026-05-16 19:09 ` sashiko-bot
2026-05-16 18:50 ` [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
2026-05-16 22:03 ` SeongJae Park
29 siblings, 1 reply; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:37 UTC (permalink / raw)
Cc: SeongJae Park, Liam R. Howlett, Andrew Morton, 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 the newly added belonging memory cgroup
attribute monitoring feature.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
Documentation/admin-guide/mm/damon/usage.rst | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst
index 7b6074a1666f3..b4584c0e4cd72 100644
--- a/Documentation/admin-guide/mm/damon/usage.rst
+++ b/Documentation/admin-guide/mm/damon/usage.rst
@@ -73,7 +73,7 @@ comma (",").
│ │ │ │ │ │ nr_regions/min,max
│ │ │ │ │ │ :ref:`probes <damon_usage_sysfs_probes>`/nr_probes
│ │ │ │ │ │ │ 0/filters/nr_filters
- │ │ │ │ │ │ │ │ 0/type,matching,allow
+ │ │ │ │ │ │ │ │ 0/type,matching,allow,path
│ │ │ │ │ │ │ │ ...
│ │ │ │ │ │ │ ...
│ │ │ │ │ :ref:`targets <sysfs_targets>`/nr_targets
@@ -283,7 +283,9 @@ the data attribute for 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
-way similar to that for :ref:`DAMOS filter <sysfs_filters>`.
+way similar to that for :ref:`DAMOS filter <sysfs_filters>`. When the filter
+``type`` is ``memcg``, ``path`` file works the role of ``memcg_path`` for
+:ref:`DAMOS filter <sysfs_filters>`.
.. _sysfs_targets:
--
2.47.3
^ permalink raw reply related [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (27 preceding siblings ...)
2026-05-16 18:37 ` [RFC PATCH v3 28/28] Docs/admin-guide/mm/damon/usage: " SeongJae Park
@ 2026-05-16 18:50 ` SeongJae Park
2026-05-16 22:03 ` SeongJae Park
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 18:50 UTC (permalink / raw)
To: SeongJae Park
Cc: Liam R. Howlett, Andrew Morton, David Hildenbrand,
Jonathan Corbet, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Mike Rapoport, Shuah Khan,
Shuah Khan, Steven Rostedt, Suren Baghdasaryan, Vlastimil Babka,
damon, linux-doc, linux-kernel, linux-kselftest, linux-mm,
linux-trace-kernel
On Sat, 16 May 2026 11:36:41 -0700 SeongJae Park <sj@kernel.org> wrote:
> TL; DR
> ======
>
> Extend DAMON for monitoring general data attributes other than accesses.
> The short term motivation is lightweight page type (e.g., belonging
> cgroup) aware monitoring. In long term, this will help extending DAMON
> for multiple access events capture primitives (e.g., page faults and
> PMU) and eventually pivotting DAMON to a "Data Attributes Monitoring and
> Operations eNgine" in long term.
[...]
> Changes from RFC v2.1
> - rfc v2.1: https://lore.kernel.org/20260514140904.119781-1-sj@kernel.org
> - Rebase to mm-stable (7.1-rc3) to avoid Sashiko patch apply failure.
Still this seires is based on mm-stable (7.1-rc3) for the same reason. The
patches that based on mm-new is available at damon/next tree [1].
[1] https://origin.kernel.org/doc/html/latest/mm/damon/maintainer-profile.html#scm-trees
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 05/28] mm/damon/core: introduce damon_region->probe_hits
2026-05-16 18:36 ` [RFC PATCH v3 05/28] mm/damon/core: introduce damon_region->probe_hits SeongJae Park
@ 2026-05-16 18:54 ` sashiko-bot
2026-05-16 21:26 ` SeongJae Park
0 siblings, 1 reply; 43+ messages in thread
From: sashiko-bot @ 2026-05-16 18:54 UTC (permalink / raw)
To: SeongJae Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Data type overflow of `probe_hits` array due to 8-bit `unsigned char` limit.
- [High] Integer overflow in `probe_hits` weighted average calculation on 32-bit systems.
--
commit b34f3f1254d83e9491235fb4e8e097729be04e60
Author: SeongJae Park <sj@kernel.org>
mm/damon/core: introduce damon_region->probe_hits
This commit adds a probe_hits array to the damon_region structure to track
the number of positive samples per region for each probe. It limits the
number of probes to a fixed maximum for a simpler implementation.
> diff --git a/include/linux/damon.h b/include/linux/damon.h
> index 32005b8b1f8cd..9e70239e5305f 100644
> --- a/include/linux/damon.h
> +++ b/include/linux/damon.h
[ ... ]
> @@ -80,6 +83,7 @@ struct damon_region {
> unsigned long sampling_addr;
> unsigned int nr_accesses;
> unsigned int nr_accesses_bp;
> + unsigned char probe_hits[DAMON_MAX_PROBES];
Does probe_hits need a wider type to prevent wrapping around?
Since the number of samples in an aggregation interval is determined by
aggr_interval / sample_interval, user-configurable values could cause the
sample count to exceed the 8-bit limit of unsigned char (255). This might
lead to silently wrapped monitoring statistics.
> struct list_head list;
>
> unsigned int age;
[ ... ]
> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index 15f2795a1156f..e5667660b4cd9 100644
> --- a/mm/damon/core.c
> +++ b/mm/damon/core.c
[ ... ]
> @@ -2754,12 +2757,17 @@ static void damon_merge_two_regions(struct damon_target *t,
> struct damon_region *l, struct damon_region *r)
> {
> unsigned long sz_l = damon_sz_region(l), sz_r = damon_sz_region(r);
> + int i;
>
> l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) /
> (sz_l + sz_r);
> l->nr_accesses_bp = l->nr_accesses * 10000;
> l->age = (l->age * sz_l + r->age * sz_r) / (sz_l + sz_r);
> l->ar.end = r->ar.end;
> + /* todo: do this for only installed probes */
> + for (i = 0; i < DAMON_MAX_PROBES; i++)
> + l->probe_hits[i] = (l->probe_hits[i] * sz_l + r->probe_hits[i]
> + * sz_r) / (sz_l + sz_r);
Could this weighted average calculation overflow on 32-bit architectures?
Both sz_l and sz_r are unsigned long, which is 32 bits on 32-bit systems.
If a region size is large (e.g., > 16.8MB) and probe_hits is up to 255,
multiplying them can exceed the 32-bit limit and wrap around, corrupting
the monitoring statistics.
It appears the nr_accesses calculation just above this has the exact same
flaw, and this patch propagates it to the new probe_hits array.
> damon_verify_merge_two_regions(l, r);
> damon_destroy_region(r, t);
> }
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260516183712.81393-1-sj@kernel.org?part=5
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 07/28] mm/damon/core: do data attributes monitoring
2026-05-16 18:36 ` [RFC PATCH v3 07/28] mm/damon/core: do data attributes monitoring SeongJae Park
@ 2026-05-16 19:00 ` sashiko-bot
2026-05-16 21:33 ` SeongJae Park
0 siblings, 1 reply; 43+ messages in thread
From: sashiko-bot @ 2026-05-16 19:00 UTC (permalink / raw)
To: SeongJae Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] The `probe_hits` array counters can silently overflow, yielding corrupted monitoring results.
- [High] DAMON dynamically merges regions based strictly on `nr_accesses`, which corrupts the spatial granularity of `probe_hits`.
- [High] If DAMON is run without `check_accesses`, all regions will be aggressively merged up to `sz_limit`, neutralizing data attribute monitoring.
- [High] Size-weighted average calculations for `probe_hits` overflow `unsigned long` on 32-bit systems.
--
commit 55dcc5294b4ee96c9d7e5a24e9dcdb0d798c401d
Author: SeongJae Park <sj@kernel.org>
mm/damon/core: do data attributes monitoring
Implement the data attributes monitoring execution. Update kdamond to
invoke the probes application callback, and reset the aggregated number
of per-region per-probe positive samples for every aggregation interval.
> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index e5667660b4cd9..dde3c8d8fef89 100644
> --- a/mm/damon/core.c
> +++ b/mm/damon/core.c
> @@ -1886,10 +1886,14 @@ static void kdamond_reset_aggregated(struct damon_ctx *c)
> struct damon_region *r;
>
> damon_for_each_region(r, t) {
> + int i;
> +
> trace_damon_aggregated(ti, r, damon_nr_regions(t));
> damon_warn_fix_nr_accesses_corruption(r);
> r->last_nr_accesses = r->nr_accesses;
> r->nr_accesses = 0;
> + for (i = 0; i < DAMON_MAX_PROBES; i++)
> + r->probe_hits[i] = 0;
Can probe_hits overflow here?
The probe_hits array is defined as unsigned char, which has a maximum value
of 255.
The number of samples per interval is user-configurable and can legitimately
exceed 255 (e.g., a 1000ms aggregation with a 1ms sample interval yields 1000
samples).
If a probe matches continuously under such configurations, could the counter
silently overflow and wrap around, corrupting the monitoring results?
> damon_verify_reset_aggregated(r, c);
> }
> ti++;
> @@ -3179,6 +3183,8 @@ 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);
If DAMON is configured strictly for data attribute monitoring where
check_accesses is NULL but apply_probes is set, max_nr_accesses and all
regional nr_accesses persistently evaluate to 0.
Will this cause all adjacent regions to have a calculated difference
threshold of 0, resulting in all regions merging indiscriminately up to
sz_limit during the subsequent kdamond_merge_regions() call?
Additionally, damon_merge_regions_of() merges adjacent regions by evaluating
only nr_accesses:
abs(prev->nr_accesses - r->nr_accesses) <= thres
Since this merge condition ignores probe_hits, could two contiguous regions
with identical access frequencies but vastly different data attributes be
incorrectly merged?
Does calculating the size-weighted average for probe_hits risk overflowing on
32-bit systems?
When damon_merge_two_regions() calculates averages using:
(metric * sz_l + metric * sz_r) / (sz_l + sz_r)
Both sz_l and sz_r are evaluated in bytes as unsigned long. On 32-bit
systems where ULONG_MAX is roughly 4 GB, a 200 MB region with 25 probe_hits
yields an intermediate product of 5,000,000,000.
Does this silently overflow the 32-bit unsigned long and corrupt the region
metrics?
>
> if (time_after_eq(ctx->passed_sample_intervals,
> next_aggregation_sis)) {
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260516183712.81393-1-sj@kernel.org?part=7
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 08/28] mm/damon/paddr: support data attributes monitoring
2026-05-16 18:36 ` [RFC PATCH v3 08/28] mm/damon/paddr: support " SeongJae Park
@ 2026-05-16 19:05 ` sashiko-bot
2026-05-16 21:46 ` SeongJae Park
0 siblings, 1 reply; 43+ messages in thread
From: sashiko-bot @ 2026-05-16 19:05 UTC (permalink / raw)
To: SeongJae Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Brittle filter evaluation logic in `damon_pa_filter_pass()` causes unpredictable default fallback behavior.
- [High] Silent integer overflow of `r->probe_hits[i]` due to an 8-bit limit.
- [High] Costly page lookups and folio refcount operations are unconditionally performed even when no probes are configured.
--
commit 3ac6d88b44843f7304cd50448ef416c14428371c
Author: SeongJae Park <sj@kernel.org>
mm/damon/paddr: support data attributes monitoring
This commit implements the apply_probes() callback for physical address
space monitoring in DAMON. It introduces filter evaluation and applies
probe hits to region statistics.
diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
--- a/mm/damon/paddr.c
+++ b/mm/damon/paddr.c
[ ... ]
> +static bool damon_pa_filter_pass(phys_addr_t pa, struct folio *folio,
> + struct damon_probe *p)
> +{
> + struct damon_filter *f;
> + bool pass = true;
> +
> + damon_for_each_filter(f, p) {
> + if (damon_pa_filter_match(f, folio)) {
> + pass = f->allow;
> + break;
> + }
> + pass = !f->allow;
> + }
> + return pass;
> +}
If a folio does not match any of the filters, the loop continues and pass
is repeatedly updated to the inverted allow flag of each evaluated filter.
When the loop finishes, the final returned result is purely the inverted
allow flag of the last filter in the list.
Is this arbitrary fallback logic intentional?
[ ... ]
> +static void damon_pa_apply_probes(struct damon_ctx *ctx)
> +{
> + struct damon_target *t;
> + struct damon_region *r;
> + struct damon_probe *p;
> +
> + damon_for_each_target(t, ctx) {
> + 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);
> + folio = damon_get_folio(PHYS_PFN(pa));
Because damon_pa_apply_probes() executes unconditionally on every sampling
interval, damon_get_folio() and folio_put() will be called globally across
all regions even if the user has not configured any probes.
Could we add an early return or check if ctx->probes is empty before
performing these expensive atomic refcount operations on the hot path?
> + damon_for_each_probe(p, ctx) {
> + if (damon_pa_filter_pass(pa, folio, p))
> + r->probe_hits[i]++;
The r->probe_hits[i] counter is declared as an unsigned char in
struct damon_region, which has a maximum value of 255.
Since the number of samples per DAMON aggregation interval is configurable
and can easily exceed 255 in standard use cases, won't this counter
silently wrap around to 0 and corrupt the monitoring statistics?
> + i++;
> + }
> + if (folio)
> + folio_put(folio);
> + }
> + }
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260516183712.81393-1-sj@kernel.org?part=8
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 28/28] Docs/admin-guide/mm/damon/usage: update for memcg damon filter
2026-05-16 18:37 ` [RFC PATCH v3 28/28] Docs/admin-guide/mm/damon/usage: " SeongJae Park
@ 2026-05-16 19:09 ` sashiko-bot
2026-05-16 21:57 ` SeongJae Park
0 siblings, 1 reply; 43+ messages in thread
From: sashiko-bot @ 2026-05-16 19:09 UTC (permalink / raw)
To: SeongJae Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Inconsistent sysfs UAPI naming for identical memcg filter concepts ('path' vs 'memcg_path').
- [Low] Awkward and non-standard grammar in the documentation.
--
commit eca4a8cfbb76f7f5c4df18fb3c84beeef902be91
Author: SeongJae Park <sj@kernel.org>
Docs/admin-guide/mm/damon/usage: update for memcg damon filter
Update DAMON usage document for the newly added belonging memory cgroup
attribute monitoring feature.
> diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst
> index 7b6074a1666f3..b4584c0e4cd72 100644
> --- a/Documentation/admin-guide/mm/damon/usage.rst
> +++ b/Documentation/admin-guide/mm/damon/usage.rst
[ ... ]
> @@ -283,7 +283,9 @@ the data attribute for 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
> -way similar to that for :ref:`DAMOS filter <sysfs_filters>`.
> +way similar to that for :ref:`DAMOS filter <sysfs_filters>`. When the filter
> +``type`` is ``memcg``, ``path`` file works the role of ``memcg_path`` for
^^^^^^^^^^^^^^^^^^
This isn't a bug, but this phrasing is non-standard. Would it be clearer
to use "acts as" or "serves the same role as"?
Also, does exposing this as "path" instead of "memcg_path" create an
inconsistent sysfs UAPI?
DAMOS memcg filters use "memcg_path" for the exact same concept. Could the
underlying kernel implementation rename "path" to "memcg_path" before the
interface is finalized to keep the naming consistent?
> +:ref:`DAMOS filter <sysfs_filters>`.
>
> .. _sysfs_targets:
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260516183712.81393-1-sj@kernel.org?part=28
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 25/28] mm/damon/sysfs-schemes: move memcg_path_to_id() to sysfs-common
2026-05-16 18:37 ` [RFC PATCH v3 25/28] mm/damon/sysfs-schemes: move memcg_path_to_id() to sysfs-common SeongJae Park
@ 2026-05-16 19:16 ` sashiko-bot
2026-05-16 21:54 ` SeongJae Park
0 siblings, 1 reply; 43+ messages in thread
From: sashiko-bot @ 2026-05-16 19:16 UTC (permalink / raw)
To: SeongJae Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The commit silently fixes a memcg reference leak by adding a call to `mem_cgroup_iter_break()` without documenting it in the commit message.
--
commit 1ef74f20c7bcc208023c4d45c1ced02bf234a75c
Author: SeongJae Park <sj@kernel.org>
mm/damon/sysfs-schemes: move memcg_path_to_id() to sysfs-common
This commit moves the static function damon_sysfs_memcg_path_to_id()
from sysfs-schemes.c to sysfs-common.c and makes it non-static so it can
be reused in subsequent commits.
> The next commit will need to find the memcg id from the user-passed path
> to the memory cgroup, from sysfs.c. memcg_path_to_id() is doing that,
> but defined in sysfs-schemes.c as a static function. Move the function
> to sysfs-common.c and mark it as non-static, so that the next commit can
> reuse the function.
The commit message states that the patch only moves the function and changes
its linkage. However, a functional change was included in the moved code.
[ ... ]
> diff --git a/mm/damon/sysfs-common.c b/mm/damon/sysfs-common.c
> index 83e24a9b5a0db..bdc6ae2639e4f 100644
> --- a/mm/damon/sysfs-common.c
> +++ b/mm/damon/sysfs-common.c
[ ... ]
> @@ -104,3 +104,44 @@ const struct kobj_type damon_sysfs_ul_range_ktype = {
> .default_groups = damon_sysfs_ul_range_groups,
> };
>
> +
> +static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg,
> + char *memcg_path_buf, char *path)
> +{
> +#ifdef CONFIG_MEMCG
> + cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX);
> + if (sysfs_streq(memcg_path_buf, path))
> + return true;
> +#endif /* CONFIG_MEMCG */
> + return false;
> +}
> +
> +int damon_sysfs_memcg_path_to_id(char *memcg_path, u64 *id)
> +{
> + struct mem_cgroup *memcg;
> + char *path;
> + bool found = false;
> +
> + if (!memcg_path)
> + return -EINVAL;
> +
> + path = kmalloc_array(PATH_MAX, sizeof(*path), GFP_KERNEL);
> + if (!path)
> + return -ENOMEM;
> +
> + for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg;
> + memcg = mem_cgroup_iter(NULL, memcg, NULL)) {
> + /* skip offlined memcg */
> + if (!mem_cgroup_online(memcg))
> + continue;
> + if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) {
> + *id = mem_cgroup_id(memcg);
> + found = true;
> + mem_cgroup_iter_break(NULL, memcg);
Is it intentional to include this memcg reference leak fix here?
It looks like the original code was missing this call to
mem_cgroup_iter_break() before breaking out of the loop.
Should this bug fix be split into a separate patch, or documented in the
commit message so that stable maintainers can backport it if necessary?
> + break;
> + }
> + }
> +
> + kfree(path);
> + return found ? 0 : -EINVAL;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260516183712.81393-1-sj@kernel.org?part=25
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 24/28] mm/damon/sysfs: add filters/<F>/path file
2026-05-16 18:37 ` [RFC PATCH v3 24/28] mm/damon/sysfs: add filters/<F>/path file SeongJae Park
@ 2026-05-16 19:29 ` sashiko-bot
2026-05-16 21:51 ` SeongJae Park
0 siblings, 1 reply; 43+ messages in thread
From: sashiko-bot @ 2026-05-16 19:29 UTC (permalink / raw)
To: SeongJae Park; +Cc: damon
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Missing string trimming in `path_store()` causes double newlines in `path_show()` output.
--
commit 355d50ee619dc1c941ec5aef02eb71147957c977
Author: SeongJae Park <sj@kernel.org>
mm/damon/sysfs: add filters/<F>/path file
Introduce a new DAMON sysfs file for letting users setup the target
memory cgroup of the belonging memory cgroup attribute monitoring.
> diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
> index f1b7d79386866..2df1d670ee77d 100644
> --- a/mm/damon/sysfs.c
> +++ b/mm/damon/sysfs.c
[ ... ]
> @@ -862,11 +867,46 @@ static ssize_t allow_store(struct kobject *kobj,
> return count;
> }
>
> +static ssize_t path_show(struct kobject *kobj,
> + struct kobj_attribute *attr, char *buf)
> +{
> + struct damon_sysfs_filter *filter = container_of(kobj,
> + struct damon_sysfs_filter, kobj);
> + int len;
> +
> + if (!mutex_trylock(&damon_sysfs_lock))
> + return -EBUSY;
> + len = sysfs_emit(buf, "%s\n", filter->path ? filter->path : "");
> + mutex_unlock(&damon_sysfs_lock);
> + return len;
> +}
> +
> +static ssize_t path_store(struct kobject *kobj,
> + struct kobj_attribute *attr, const char *buf, size_t count)
> +{
> + struct damon_sysfs_filter *filter = container_of(kobj,
> + struct damon_sysfs_filter, kobj);
> + char *path = kmalloc_objs(*path, size_add(count, 1));
> +
> + if (!path)
> + return -ENOMEM;
> + strscpy(path, buf, size_add(count, 1));
Will this strscpy() result in a double newline in the output of path_show()?
When users write to the path sysfs file using standard tools like echo, the
input typically includes a trailing newline character. This copy operation
will store that newline directly into filter->path.
When read back, path_show() uses sysfs_emit() with "%s\n", which will append
a second newline.
While a subsequent commit ("mm/damon/sysfs: setup damon_filter->memcg_id
from path") uses sysfs_streq() which safely ignores trailing newlines for
path matching, could we strip the trailing newline here to avoid the
formatting anomaly in the sysfs output?
> + if (!mutex_trylock(&damon_sysfs_lock)) {
> + kfree(path);
> + return -EBUSY;
> + }
> + kfree(filter->path);
> + filter->path = path;
> + mutex_unlock(&damon_sysfs_lock);
> + return count;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260516183712.81393-1-sj@kernel.org?part=24
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 05/28] mm/damon/core: introduce damon_region->probe_hits
2026-05-16 18:54 ` sashiko-bot
@ 2026-05-16 21:26 ` SeongJae Park
0 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 21:26 UTC (permalink / raw)
To: sashiko-bot; +Cc: SeongJae Park, damon
On Sat, 16 May 2026 18:54:35 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] Data type overflow of `probe_hits` array due to 8-bit `unsigned char` limit.
> - [High] Integer overflow in `probe_hits` weighted average calculation on 32-bit systems.
> --
>
> commit b34f3f1254d83e9491235fb4e8e097729be04e60
> Author: SeongJae Park <sj@kernel.org>
>
> mm/damon/core: introduce damon_region->probe_hits
>
> This commit adds a probe_hits array to the damon_region structure to track
> the number of positive samples per region for each probe. It limits the
> number of probes to a fixed maximum for a simpler implementation.
>
> > diff --git a/include/linux/damon.h b/include/linux/damon.h
> > index 32005b8b1f8cd..9e70239e5305f 100644
> > --- a/include/linux/damon.h
> > +++ b/include/linux/damon.h
> [ ... ]
> > @@ -80,6 +83,7 @@ struct damon_region {
> > unsigned long sampling_addr;
> > unsigned int nr_accesses;
> > unsigned int nr_accesses_bp;
> > + unsigned char probe_hits[DAMON_MAX_PROBES];
>
> Does probe_hits need a wider type to prevent wrapping around?
>
> Since the number of samples in an aggregation interval is determined by
> aggr_interval / sample_interval, user-configurable values could cause the
> sample count to exceed the 8-bit limit of unsigned char (255). This might
> lead to silently wrapped monitoring statistics.
Yes, but such configurations may be rare, so no blocker.
For more details, please read my previous reply [1] for same question.
>
> > struct list_head list;
> >
> > unsigned int age;
> [ ... ]
> > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > index 15f2795a1156f..e5667660b4cd9 100644
> > --- a/mm/damon/core.c
> > +++ b/mm/damon/core.c
> [ ... ]
> > @@ -2754,12 +2757,17 @@ static void damon_merge_two_regions(struct damon_target *t,
> > struct damon_region *l, struct damon_region *r)
> > {
> > unsigned long sz_l = damon_sz_region(l), sz_r = damon_sz_region(r);
> > + int i;
> >
> > l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) /
> > (sz_l + sz_r);
> > l->nr_accesses_bp = l->nr_accesses * 10000;
> > l->age = (l->age * sz_l + r->age * sz_r) / (sz_l + sz_r);
> > l->ar.end = r->ar.end;
> > + /* todo: do this for only installed probes */
> > + for (i = 0; i < DAMON_MAX_PROBES; i++)
> > + l->probe_hits[i] = (l->probe_hits[i] * sz_l + r->probe_hits[i]
> > + * sz_r) / (sz_l + sz_r);
>
> Could this weighted average calculation overflow on 32-bit architectures?
>
> Both sz_l and sz_r are unsigned long, which is 32 bits on 32-bit systems.
> If a region size is large (e.g., > 16.8MB) and probe_hits is up to 255,
> multiplying them can exceed the 32-bit limit and wrap around, corrupting
> the monitoring statistics.
>
> It appears the nr_accesses calculation just above this has the exact same
> flaw, and this patch propagates it to the new probe_hits array.
On 32bit systems, users could use the addr_unit to avoid this kind of issues.
So no blocker.
[1] https://lore.kernel.org/20260516003559.141476-1-sj@kernel.org
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 07/28] mm/damon/core: do data attributes monitoring
2026-05-16 19:00 ` sashiko-bot
@ 2026-05-16 21:33 ` SeongJae Park
0 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 21:33 UTC (permalink / raw)
To: sashiko-bot; +Cc: SeongJae Park, damon
On Sat, 16 May 2026 19:00:10 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
> - [High] The `probe_hits` array counters can silently overflow, yielding corrupted monitoring results.
> - [High] DAMON dynamically merges regions based strictly on `nr_accesses`, which corrupts the spatial granularity of `probe_hits`.
> - [High] If DAMON is run without `check_accesses`, all regions will be aggressively merged up to `sz_limit`, neutralizing data attribute monitoring.
> - [High] Size-weighted average calculations for `probe_hits` overflow `unsigned long` on 32-bit systems.
> --
>
> commit 55dcc5294b4ee96c9d7e5a24e9dcdb0d798c401d
> Author: SeongJae Park <sj@kernel.org>
>
> mm/damon/core: do data attributes monitoring
>
> Implement the data attributes monitoring execution. Update kdamond to
> invoke the probes application callback, and reset the aggregated number
> of per-region per-probe positive samples for every aggregation interval.
>
> > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > index e5667660b4cd9..dde3c8d8fef89 100644
> > --- a/mm/damon/core.c
> > +++ b/mm/damon/core.c
> > @@ -1886,10 +1886,14 @@ static void kdamond_reset_aggregated(struct damon_ctx *c)
> > struct damon_region *r;
> >
> > damon_for_each_region(r, t) {
> > + int i;
> > +
> > trace_damon_aggregated(ti, r, damon_nr_regions(t));
> > damon_warn_fix_nr_accesses_corruption(r);
> > r->last_nr_accesses = r->nr_accesses;
> > r->nr_accesses = 0;
> > + for (i = 0; i < DAMON_MAX_PROBES; i++)
> > + r->probe_hits[i] = 0;
>
> Can probe_hits overflow here?
>
> The probe_hits array is defined as unsigned char, which has a maximum value
> of 255.
>
> The number of samples per interval is user-configurable and can legitimately
> exceed 255 (e.g., a 1000ms aggregation with a 1ms sample interval yields 1000
> samples).
>
> If a probe matches continuously under such configurations, could the counter
> silently overflow and wrap around, corrupting the monitoring results?
No blocker, as I previously explained [1].
>
> > damon_verify_reset_aggregated(r, c);
> > }
> > ti++;
> > @@ -3179,6 +3183,8 @@ 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);
>
> If DAMON is configured strictly for data attribute monitoring where
> check_accesses is NULL but apply_probes is set, max_nr_accesses and all
> regional nr_accesses persistently evaluate to 0.
>
> Will this cause all adjacent regions to have a calculated difference
> threshold of 0, resulting in all regions merging indiscriminately up to
> sz_limit during the subsequent kdamond_merge_regions() call?
>
> Additionally, damon_merge_regions_of() merges adjacent regions by evaluating
> only nr_accesses:
>
> abs(prev->nr_accesses - r->nr_accesses) <= thres
>
> Since this merge condition ignores probe_hits, could two contiguous regions
> with identical access frequencies but vastly different data attributes be
> incorrectly merged?
Correct, and that's the intended behavior. Data attributes are just additional
information. Data access pattern, specifically nr_accesses, is the primary
information that drives region splits and merges. I'm planning to let users
set the primary information in future, though.
>
> Does calculating the size-weighted average for probe_hits risk overflowing on
> 32-bit systems?
>
> When damon_merge_two_regions() calculates averages using:
>
> (metric * sz_l + metric * sz_r) / (sz_l + sz_r)
>
> Both sz_l and sz_r are evaluated in bytes as unsigned long. On 32-bit
> systems where ULONG_MAX is roughly 4 GB, a 200 MB region with 25 probe_hits
> yields an intermediate product of 5,000,000,000.
>
> Does this silently overflow the 32-bit unsigned long and corrupt the region
> metrics?
I previously answered [1] this. 32-bit arch users could use addr_unit to avoid
this issue.
>
> >
> > if (time_after_eq(ctx->passed_sample_intervals,
> > next_aggregation_sis)) {
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260516183712.81393-1-sj@kernel.org?part=7
[1] https://lore.kernel.org/20260516003559.141476-1-sj@kernel.org
Thanks,
SJ
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 08/28] mm/damon/paddr: support data attributes monitoring
2026-05-16 19:05 ` sashiko-bot
@ 2026-05-16 21:46 ` SeongJae Park
0 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 21:46 UTC (permalink / raw)
To: sashiko-bot; +Cc: SeongJae Park, damon
On Sat, 16 May 2026 19:05:31 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
> - [High] Brittle filter evaluation logic in `damon_pa_filter_pass()` causes unpredictable default fallback behavior.
> - [High] Silent integer overflow of `r->probe_hits[i]` due to an 8-bit limit.
> - [High] Costly page lookups and folio refcount operations are unconditionally performed even when no probes are configured.
> --
>
> commit 3ac6d88b44843f7304cd50448ef416c14428371c
> Author: SeongJae Park <sj@kernel.org>
>
> mm/damon/paddr: support data attributes monitoring
>
> This commit implements the apply_probes() callback for physical address
> space monitoring in DAMON. It introduces filter evaluation and applies
> probe hits to region statistics.
>
> diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
> --- a/mm/damon/paddr.c
> +++ b/mm/damon/paddr.c
>
> [ ... ]
>
> > +static bool damon_pa_filter_pass(phys_addr_t pa, struct folio *folio,
> > + struct damon_probe *p)
> > +{
> > + struct damon_filter *f;
> > + bool pass = true;
> > +
> > + damon_for_each_filter(f, p) {
> > + if (damon_pa_filter_match(f, folio)) {
> > + pass = f->allow;
> > + break;
> > + }
> > + pass = !f->allow;
> > + }
> > + return pass;
> > +}
>
> If a folio does not match any of the filters, the loop continues and pass
> is repeatedly updated to the inverted allow flag of each evaluated filter.
>
> When the loop finishes, the final returned result is purely the inverted
> allow flag of the last filter in the list.
>
> Is this arbitrary fallback logic intentional?
Yes, intentional [1].
>
> [ ... ]
>
> > +static void damon_pa_apply_probes(struct damon_ctx *ctx)
> > +{
> > + struct damon_target *t;
> > + struct damon_region *r;
> > + struct damon_probe *p;
> > +
> > + damon_for_each_target(t, ctx) {
> > + 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);
> > + folio = damon_get_folio(PHYS_PFN(pa));
>
> Because damon_pa_apply_probes() executes unconditionally on every sampling
> interval, damon_get_folio() and folio_put() will be called globally across
> all regions even if the user has not configured any probes.
>
> Could we add an early return or check if ctx->probes is empty before
> performing these expensive atomic refcount operations on the hot path?
The user can set the maximum number of regions, and this is arguably not a hot
path. So no blocker.
>
> > + damon_for_each_probe(p, ctx) {
> > + if (damon_pa_filter_pass(pa, folio, p))
> > + r->probe_hits[i]++;
>
> The r->probe_hits[i] counter is declared as an unsigned char in
> struct damon_region, which has a maximum value of 255.
>
> Since the number of samples per DAMON aggregation interval is configurable
> and can easily exceed 255 in standard use cases, won't this counter
> silently wrap around to 0 and corrupt the monitoring statistics?
No blocker [2].
>
> > + i++;
> > + }
> > + if (folio)
> > + folio_put(folio);
> > + }
> > + }
> > +}
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260516183712.81393-1-sj@kernel.org?part=8
[1] https://lore.kernel.org/20260516005632.144711-1-sj@kernel.org
[2] https://lore.kernel.org/20260516003559.141476-1-sj@kernel.org
Thanks,
SJ
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 24/28] mm/damon/sysfs: add filters/<F>/path file
2026-05-16 19:29 ` sashiko-bot
@ 2026-05-16 21:51 ` SeongJae Park
0 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 21:51 UTC (permalink / raw)
To: sashiko-bot; +Cc: SeongJae Park, damon
On Sat, 16 May 2026 19:29:04 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Low] Missing string trimming in `path_store()` causes double newlines in `path_show()` output.
> --
>
> commit 355d50ee619dc1c941ec5aef02eb71147957c977
> Author: SeongJae Park <sj@kernel.org>
>
> mm/damon/sysfs: add filters/<F>/path file
>
> Introduce a new DAMON sysfs file for letting users setup the target
> memory cgroup of the belonging memory cgroup attribute monitoring.
>
> > diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
> > index f1b7d79386866..2df1d670ee77d 100644
> > --- a/mm/damon/sysfs.c
> > +++ b/mm/damon/sysfs.c
>
> [ ... ]
>
> > @@ -862,11 +867,46 @@ static ssize_t allow_store(struct kobject *kobj,
> > return count;
> > }
> >
> > +static ssize_t path_show(struct kobject *kobj,
> > + struct kobj_attribute *attr, char *buf)
> > +{
> > + struct damon_sysfs_filter *filter = container_of(kobj,
> > + struct damon_sysfs_filter, kobj);
> > + int len;
> > +
> > + if (!mutex_trylock(&damon_sysfs_lock))
> > + return -EBUSY;
> > + len = sysfs_emit(buf, "%s\n", filter->path ? filter->path : "");
> > + mutex_unlock(&damon_sysfs_lock);
> > + return len;
> > +}
> > +
> > +static ssize_t path_store(struct kobject *kobj,
> > + struct kobj_attribute *attr, const char *buf, size_t count)
> > +{
> > + struct damon_sysfs_filter *filter = container_of(kobj,
> > + struct damon_sysfs_filter, kobj);
> > + char *path = kmalloc_objs(*path, size_add(count, 1));
> > +
> > + if (!path)
> > + return -ENOMEM;
> > + strscpy(path, buf, size_add(count, 1));
>
> Will this strscpy() result in a double newline in the output of path_show()?
>
> When users write to the path sysfs file using standard tools like echo, the
> input typically includes a trailing newline character. This copy operation
> will store that newline directly into filter->path.
>
> When read back, path_show() uses sysfs_emit() with "%s\n", which will append
> a second newline.
>
> While a subsequent commit ("mm/damon/sysfs: setup damon_filter->memcg_id
> from path") uses sysfs_streq() which safely ignores trailing newlines for
> path matching, could we strip the trailing newline here to avoid the
> formatting anomaly in the sysfs output?
Good catch, but quite trivial. And other similar arbitrary string parameters
work in the same way. Let's keep this as is for now.
>
> > + if (!mutex_trylock(&damon_sysfs_lock)) {
> > + kfree(path);
> > + return -EBUSY;
> > + }
> > + kfree(filter->path);
> > + filter->path = path;
> > + mutex_unlock(&damon_sysfs_lock);
> > + return count;
> > +}
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260516183712.81393-1-sj@kernel.org?part=24
Thanks,
SJ
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 25/28] mm/damon/sysfs-schemes: move memcg_path_to_id() to sysfs-common
2026-05-16 19:16 ` sashiko-bot
@ 2026-05-16 21:54 ` SeongJae Park
0 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 21:54 UTC (permalink / raw)
To: sashiko-bot; +Cc: SeongJae Park, damon
On Sat, 16 May 2026 19:16:05 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] The commit silently fixes a memcg reference leak by adding a call to `mem_cgroup_iter_break()` without documenting it in the commit message.
> --
>
> commit 1ef74f20c7bcc208023c4d45c1ced02bf234a75c
> Author: SeongJae Park <sj@kernel.org>
>
> mm/damon/sysfs-schemes: move memcg_path_to_id() to sysfs-common
>
> This commit moves the static function damon_sysfs_memcg_path_to_id()
> from sysfs-schemes.c to sysfs-common.c and makes it non-static so it can
> be reused in subsequent commits.
>
> > The next commit will need to find the memcg id from the user-passed path
> > to the memory cgroup, from sysfs.c. memcg_path_to_id() is doing that,
> > but defined in sysfs-schemes.c as a static function. Move the function
> > to sysfs-common.c and mark it as non-static, so that the next commit can
> > reuse the function.
>
> The commit message states that the patch only moves the function and changes
> its linkage. However, a functional change was included in the moved code.
>
> [ ... ]
> > diff --git a/mm/damon/sysfs-common.c b/mm/damon/sysfs-common.c
> > index 83e24a9b5a0db..bdc6ae2639e4f 100644
> > --- a/mm/damon/sysfs-common.c
> > +++ b/mm/damon/sysfs-common.c
> [ ... ]
> > @@ -104,3 +104,44 @@ const struct kobj_type damon_sysfs_ul_range_ktype = {
> > .default_groups = damon_sysfs_ul_range_groups,
> > };
> >
> > +
> > +static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg,
> > + char *memcg_path_buf, char *path)
> > +{
> > +#ifdef CONFIG_MEMCG
> > + cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX);
> > + if (sysfs_streq(memcg_path_buf, path))
> > + return true;
> > +#endif /* CONFIG_MEMCG */
> > + return false;
> > +}
> > +
> > +int damon_sysfs_memcg_path_to_id(char *memcg_path, u64 *id)
> > +{
> > + struct mem_cgroup *memcg;
> > + char *path;
> > + bool found = false;
> > +
> > + if (!memcg_path)
> > + return -EINVAL;
> > +
> > + path = kmalloc_array(PATH_MAX, sizeof(*path), GFP_KERNEL);
> > + if (!path)
> > + return -ENOMEM;
> > +
> > + for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg;
> > + memcg = mem_cgroup_iter(NULL, memcg, NULL)) {
> > + /* skip offlined memcg */
> > + if (!mem_cgroup_online(memcg))
> > + continue;
> > + if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) {
> > + *id = mem_cgroup_id(memcg);
> > + found = true;
> > + mem_cgroup_iter_break(NULL, memcg);
>
> Is it intentional to include this memcg reference leak fix here?
>
> It looks like the original code was missing this call to
> mem_cgroup_iter_break() before breaking out of the loop.
>
> Should this bug fix be split into a separate patch, or documented in the
> commit message so that stable maintainers can backport it if necessary?
Intentional thing, that made to ensure Sashiko can [1] review this. The final
version of this patch will not have that.
>
> > + break;
> > + }
> > + }
> > +
> > + kfree(path);
> > + return found ? 0 : -EINVAL;
> > +}
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260516183712.81393-1-sj@kernel.org?part=25
[1] https://lore.kernel.org/20260516015001.147547-1-sj@kernel.org
Thanks,
SJ
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 28/28] Docs/admin-guide/mm/damon/usage: update for memcg damon filter
2026-05-16 19:09 ` sashiko-bot
@ 2026-05-16 21:57 ` SeongJae Park
0 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 21:57 UTC (permalink / raw)
To: sashiko-bot; +Cc: SeongJae Park, damon
On Sat, 16 May 2026 19:09:31 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [Medium] Inconsistent sysfs UAPI naming for identical memcg filter concepts ('path' vs 'memcg_path').
> - [Low] Awkward and non-standard grammar in the documentation.
> --
>
> commit eca4a8cfbb76f7f5c4df18fb3c84beeef902be91
> Author: SeongJae Park <sj@kernel.org>
>
> Docs/admin-guide/mm/damon/usage: update for memcg damon filter
>
> Update DAMON usage document for the newly added belonging memory cgroup
> attribute monitoring feature.
>
> > diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst
> > index 7b6074a1666f3..b4584c0e4cd72 100644
> > --- a/Documentation/admin-guide/mm/damon/usage.rst
> > +++ b/Documentation/admin-guide/mm/damon/usage.rst
>
> [ ... ]
>
> > @@ -283,7 +283,9 @@ the data attribute for 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
> > -way similar to that for :ref:`DAMOS filter <sysfs_filters>`.
> > +way similar to that for :ref:`DAMOS filter <sysfs_filters>`. When the filter
> > +``type`` is ``memcg``, ``path`` file works the role of ``memcg_path`` for
> ^^^^^^^^^^^^^^^^^^
>
> This isn't a bug, but this phrasing is non-standard. Would it be clearer
> to use "acts as" or "serves the same role as"?
Good catch, I will update the next version to use "acts as".
>
> Also, does exposing this as "path" instead of "memcg_path" create an
> inconsistent sysfs UAPI?
>
> DAMOS memcg filters use "memcg_path" for the exact same concept. Could the
> underlying kernel implementation rename "path" to "memcg_path" before the
> interface is finalized to keep the naming consistent?
No, I'm here to avoid such thing.
>
> > +:ref:`DAMOS filter <sysfs_filters>`.
> >
> > .. _sysfs_targets:
> >
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260516183712.81393-1-sj@kernel.org?part=28
Thanks,
SJ
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
` (28 preceding siblings ...)
2026-05-16 18:50 ` [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
@ 2026-05-16 22:03 ` SeongJae Park
29 siblings, 0 replies; 43+ messages in thread
From: SeongJae Park @ 2026-05-16 22:03 UTC (permalink / raw)
To: SeongJae Park
Cc: Liam R. Howlett, Andrew Morton, David Hildenbrand,
Jonathan Corbet, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Mike Rapoport, Shuah Khan,
Shuah Khan, Steven Rostedt, Suren Baghdasaryan, Vlastimil Babka,
damon, linux-doc, linux-kernel, linux-kselftest, linux-mm,
linux-trace-kernel
On Sat, 16 May 2026 11:36:41 -0700 SeongJae Park <sj@kernel.org> wrote:
> TL; DR
> ======
>
> Extend DAMON for monitoring general data attributes other than accesses.
> The short term motivation is lightweight page type (e.g., belonging
> cgroup) aware monitoring. In long term, this will help extending DAMON
> for multiple access events capture primitives (e.g., page faults and
> PMU) and eventually pivotting DAMON to a "Data Attributes Monitoring and
> Operations eNgine" in long term.
Sashiko found [1] no blocker for this version but a nice document wordsmithing
idea. Unless I get other opinions, I will drop RFC tag from the next version
of this series.
[1] https://lore.kernel.org/damon/20260516185032.82261-1-sj@kernel.org/
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 43+ messages in thread
end of thread, other threads:[~2026-05-16 22:04 UTC | newest]
Thread overview: 43+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-16 18:36 [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 01/28] mm/damon/core: introduce struct damon_probe SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 02/28] mm/damon/core: embed damon_probe objects in damon_ctx SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 03/28] mm/damon/core: introduce damon_filter SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 04/28] mm/damon/core: commit probes SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 05/28] mm/damon/core: introduce damon_region->probe_hits SeongJae Park
2026-05-16 18:54 ` sashiko-bot
2026-05-16 21:26 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 06/28] mm/damon/core: introduce damon_ops->apply_probes SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 07/28] mm/damon/core: do data attributes monitoring SeongJae Park
2026-05-16 19:00 ` sashiko-bot
2026-05-16 21:33 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 08/28] mm/damon/paddr: support " SeongJae Park
2026-05-16 19:05 ` sashiko-bot
2026-05-16 21:46 ` SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 09/28] mm/damon/sysfs: implement probes dir SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 10/28] mm/damon/sysfs: implement probe dir SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 11/28] mm/damon/sysfs: implement filters directory SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 12/28] mm/damon/sysfs: implement filter dir SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 13/28] mm/damon/sysfs: implement filter dir files SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 14/28] mm/damon/sysfs: setup probes on DAMON core API parameters SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 15/28] mm/damon/sysfs-schemes: implement tried_regions/<r>/probes/ SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 16/28] mm/damon/sysfs-schemes: implement probe dir SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 17/28] mm/damon/sysfs-schemes: implement probe/hits file SeongJae Park
2026-05-16 18:36 ` [RFC PATCH v3 18/28] mm/damon: trace probe_hits SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 19/28] selftests/damon/sysfs.sh: test probes dir SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 20/28] Docs/mm/damon/design: document data attributes monitoring SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 21/28] Docs/admin-guide/mm/damon/usage: " SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 22/28] mm/damon/core: introduce DAMON_FILTER_TYPE_MEMCG SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 23/28] mm/damon/paddr: support DAMON_FILTER_TYPE_MEMCG SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 24/28] mm/damon/sysfs: add filters/<F>/path file SeongJae Park
2026-05-16 19:29 ` sashiko-bot
2026-05-16 21:51 ` SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 25/28] mm/damon/sysfs-schemes: move memcg_path_to_id() to sysfs-common SeongJae Park
2026-05-16 19:16 ` sashiko-bot
2026-05-16 21:54 ` SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 26/28] mm/damon/sysfs: setup damon_filter->memcg_id from path SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 27/28] Docs/mm/damon/design: update for memcg damon filter SeongJae Park
2026-05-16 18:37 ` [RFC PATCH v3 28/28] Docs/admin-guide/mm/damon/usage: " SeongJae Park
2026-05-16 19:09 ` sashiko-bot
2026-05-16 21:57 ` SeongJae Park
2026-05-16 18:50 ` [RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring SeongJae Park
2026-05-16 22:03 ` SeongJae Park
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.