From: Sasha Levin <sashal@kernel.org>
To: stable@vger.kernel.org
Cc: SJ Park <sj@kernel.org>,
Andrew Morton <akpm@linux-foundation.org>,
David Hildenbrand <david@kernel.org>,
Jonathan Corbet <corbet@lwn.net>,
"Liam R. Howlett" <liam@infradead.org>,
Lorenzo Stoakes <ljs@kernel.org>, Michal Hocko <mhocko@suse.com>,
Mike Rapoport <rppt@kernel.org>,
Randy Dunlap <rdunlap@infradead.org>,
Suren Baghdasaryan <surenb@google.com>,
Vlastimil Babka <vbabka@kernel.org>,
Sasha Levin <sashal@kernel.org>
Subject: [PATCH 7.3.y 1/2] mm/damon/sysfs-schemes: rename sysfs_filter->sz_range to range_{min,max}
Date: Tue, 10 Nov 2026 12:15:01 -0500 [thread overview]
Message-ID: <20261110171205.2600662-1-sashal@kernel.org> (raw)
In-Reply-To: <20261107050429-failed-7.3-1d2397b2c414@kernel.org>
From: SJ Park <sj@kernel.org>
[ Upstream commit 7bcb11735cee6f936a66ac718fd582bb4a85b11e ]
DAMON sysfs interface provides 'min' and 'max' files under the DAMOS
filter directory. The purpose is setting the general range arguments for
hugepage_size like filters that require range arguments. So far,
hugepage_size was the only filter using it. Hence sz_range field of
damon_sysfs_scheme_filter struct was connected to the files.
In future, we could add a new filter that can reuse the 'min' and 'max'
files. And the filter might use a range of a type that is not size. For
example, probe_hits weighted sum. In this case, simply reusing the
sz_range field would make it a little confusing. Rename sz_range to
range_{min,max} to avoid such confusion.
Link: https://lore.kernel.org/20260911135510.96914-5-sj@kernel.org
Signed-off-by: SJ Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Keep copying the size bounds before validating them so each sysfs value
is read only once. Include the probe-hits filter range representation and
handling, along with core range validation and error propagation. These
prerequisites allow the subsequent removal of duplicate sysfs validation
without leaving invalid ranges unchecked. The virtual-address probe
caller adjustment is unnecessary because that caller is absent.
Assisted-by: LLM
Stable-dep-of: 1d2397b2c414 ("mm/damon/sysfs-schemes: drop centralized filter range arg validations")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
Documentation/admin-guide/mm/damon/usage.rst | 4 ++
Documentation/mm/damon/design.rst | 3 +
include/linux/damon.h | 22 +++++--
mm/damon/core.c | 67 +++++++++++++++-----
mm/damon/paddr.c | 2 +-
mm/damon/sysfs-schemes.c | 27 ++++++--
6 files changed, 94 insertions(+), 31 deletions(-)
diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst
index da5f9afd08aef..7d1d63d18d729 100644
--- a/Documentation/admin-guide/mm/damon/usage.rst
+++ b/Documentation/admin-guide/mm/damon/usage.rst
@@ -539,6 +539,10 @@ and ``damon_target_idx``. To ``type`` file, you can write the type of the
filter. Refer to :ref:`the design doc <damon_design_damos_filters>` for
available type names, their meaning and on what layer those are handled.
+For ``probe_hits_wsum`` type, you can specify the minimum and maximum probe
+hits weighted sum value for the filter to ``min`` and ``max`` files,
+respectively.
+
For ``memcg`` type, you can specify the memory cgroup of the interest by
writing the path of the memory cgroup from the cgroups mount point to
``memcg_path`` file. For ``addr`` type, you can specify the start and end
diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst
index aed6cb1cf4831..7ee95a49ca70e 100644
--- a/Documentation/mm/damon/design.rst
+++ b/Documentation/mm/damon/design.rst
@@ -809,6 +809,9 @@ Below ``type`` of filters are currently supported.
- Applied to pages that belonging to a given address range.
- target
- Applied to pages that belonging to a given DAMON monitoring target.
+ - probe_hits_wsum
+ - Matches to monitoring regions having a given range of :ref:`probe
+ hits weighted sum <damon_design_attrs_only_monitoring>` value.
- Operations layer handled, supported by only ``paddr`` operations set.
- anon
- Applied to pages that containing data that not stored in files.
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 9772309b2b587..f267c3082ca6f 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -396,14 +396,15 @@ struct damos_stat {
* @DAMOS_FILTER_TYPE_UNMAPPED: Unmapped pages.
* @DAMOS_FILTER_TYPE_ADDR: Address range.
* @DAMOS_FILTER_TYPE_TARGET: Data Access Monitoring target.
+ * @DAMOS_FILTER_TYPE_PROBE_HITS_WSUM: probe_hits weighted sum range.
* @NR_DAMOS_FILTER_TYPES: Number of filter types.
*
- * All types except &DAMOS_FILTER_TYPE_ADDR and &DAMOS_FILTER_TYPE_TARGET
- * are handled by the underlying &struct damon_operations as a part of scheme
- * action trying, and therefore accounted as 'tried'. In contrast,
- * &DAMOS_FILTER_TYPE_ADDR and &DAMOS_FILTER_TYPE_TARGET filters are handled
- * by the core layer before trying of the action, and therefore not accounted
- * as 'tried'.
+ * All types except &DAMOS_FILTER_TYPE_ADDR, &DAMOS_FILTER_TYPE_TARGET and
+ * &DAMOS_FILTER_TYPE_PROBE_HITS_WSUM are handled by the underlying &struct
+ * damon_operations as a part of scheme action trying, and therefore accounted
+ * as 'tried'. In contrast, &DAMOS_FILTER_TYPE_ADDR, &DAMOS_FILTER_TYPE_TARGET
+ * and &DAMOS_FILTER_TYPE_PROBE_HITS_WSUM filters are handled by the core layer
+ * before trying of the action, and therefore not accounted as 'tried'.
*
* Support for the operations-handled filters depends on the running
* &struct damon_operations.
@@ -417,6 +418,7 @@ enum damos_filter_type {
DAMOS_FILTER_TYPE_UNMAPPED,
DAMOS_FILTER_TYPE_ADDR,
DAMOS_FILTER_TYPE_TARGET,
+ DAMOS_FILTER_TYPE_PROBE_HITS_WSUM,
NR_DAMOS_FILTER_TYPES,
};
@@ -431,6 +433,8 @@ enum damos_filter_type {
* &damon_ctx->adaptive_targets if @type is
* DAMOS_FILTER_TYPE_TARGET.
* @sz_range: Size range if @type is DAMOS_FILTER_TYPE_HUGEPAGE_SIZE.
+ * @range_min: Minimum value of range arguments.
+ * @range_max: Maximum value of range arguments.
*
* Before applying the &damos->action to a memory region, DAMOS checks if each
* byte of the region matches to this given condition and avoid applying the
@@ -447,6 +451,10 @@ struct damos_filter {
struct damon_addr_range addr_range;
int target_idx;
struct damon_size_range sz_range;
+ struct {
+ unsigned long range_min;
+ unsigned long range_max;
+ };
};
/* private: */
/* List head for siblings. */
@@ -1033,7 +1041,7 @@ unsigned int damon_nr_accesses_mvsum(struct damon_region *r,
struct damon_ctx *ctx);
unsigned char damon_probe_hits_mvsum(int probe_idx, struct damon_region *r,
struct damon_ctx *ctx);
-unsigned int damon_probe_hits_wsum(struct damon_region *r, bool last,
+unsigned int damon_probe_hits_wsum(struct damon_region *r, bool last, bool mv,
struct damon_ctx *ctx);
int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges,
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 85bcb6da9ad0b..0a179315c222d 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -408,11 +408,12 @@ static bool damon_is_last_region(struct damon_region *r,
* damon_probe_hits_wsum() - Returns probe hits weighted sum of a region.
* @r: region to get the weighted sum of.
* @last: if the request is for last-window aggregated probe hits.
+ * @mv: use moving sum.
* @ctx: context of &r.
*
* Return: the weighted sum of probe hits of the region.
*/
-unsigned int damon_probe_hits_wsum(struct damon_region *r, bool last,
+unsigned int damon_probe_hits_wsum(struct damon_region *r, bool last, bool mv,
struct damon_ctx *ctx)
{
struct damon_probe *probe;
@@ -422,6 +423,9 @@ unsigned int damon_probe_hits_wsum(struct damon_region *r, bool last,
damon_for_each_probe(probe, ctx) {
if (last)
sum += r->last_probe_hits[i++] * probe->weight;
+ else if (mv)
+ sum += damon_probe_hits_mvsum(i++, r, ctx) *
+ probe->weight;
else
sum += r->probe_hits[i++] * probe->weight;
}
@@ -593,6 +597,7 @@ bool damos_filter_for_ops(enum damos_filter_type type)
switch (type) {
case DAMOS_FILTER_TYPE_ADDR:
case DAMOS_FILTER_TYPE_TARGET:
+ case DAMOS_FILTER_TYPE_PROBE_HITS_WSUM:
return false;
default:
break;
@@ -1244,7 +1249,7 @@ static struct damos_filter *damos_nth_ops_filter(int n, struct damos *s)
return NULL;
}
-static void damos_commit_filter_arg(
+static int damos_commit_filter_arg(
struct damos_filter *dst, struct damos_filter *src)
{
switch (dst->type) {
@@ -1252,39 +1257,53 @@ static void damos_commit_filter_arg(
dst->memcg_id = src->memcg_id;
break;
case DAMOS_FILTER_TYPE_ADDR:
+ if (src->addr_range.end < src->addr_range.start)
+ return -EINVAL;
dst->addr_range = src->addr_range;
break;
case DAMOS_FILTER_TYPE_TARGET:
dst->target_idx = src->target_idx;
break;
case DAMOS_FILTER_TYPE_HUGEPAGE_SIZE:
+ if (src->sz_range.max < src->sz_range.min)
+ return -EINVAL;
dst->sz_range = src->sz_range;
break;
+ case DAMOS_FILTER_TYPE_PROBE_HITS_WSUM:
+ if (src->range_max < src->range_min)
+ return -EINVAL;
+ dst->range_min = src->range_min;
+ dst->range_max = src->range_max;
+ break;
default:
break;
}
+ return 0;
}
-static void damos_commit_filter(
+static int damos_commit_filter(
struct damos_filter *dst, struct damos_filter *src)
{
dst->type = src->type;
dst->matching = src->matching;
dst->allow = src->allow;
- damos_commit_filter_arg(dst, src);
+ return damos_commit_filter_arg(dst, src);
}
static int damos_commit_core_filters(struct damos *dst, struct damos *src)
{
struct damos_filter *dst_filter, *next, *src_filter, *new_filter;
- int i = 0, j = 0;
+ int i = 0, j = 0, err;
damos_for_each_core_filter_safe(dst_filter, next, dst) {
src_filter = damos_nth_core_filter(i++, src);
- if (src_filter)
- damos_commit_filter(dst_filter, src_filter);
- else
+ if (src_filter) {
+ err = damos_commit_filter(dst_filter, src_filter);
+ if (err)
+ return err;
+ } else {
damos_destroy_filter(dst_filter);
+ }
}
damos_for_each_core_filter_safe(src_filter, next, src) {
@@ -1296,7 +1315,11 @@ static int damos_commit_core_filters(struct damos *dst, struct damos *src)
src_filter->allow);
if (!new_filter)
return -ENOMEM;
- damos_commit_filter_arg(new_filter, src_filter);
+ err = damos_commit_filter_arg(new_filter, src_filter);
+ if (err) {
+ damos_destroy_filter(new_filter);
+ return err;
+ }
damos_add_filter(dst, new_filter);
}
return 0;
@@ -1305,14 +1328,17 @@ static int damos_commit_core_filters(struct damos *dst, struct damos *src)
static int damos_commit_ops_filters(struct damos *dst, struct damos *src)
{
struct damos_filter *dst_filter, *next, *src_filter, *new_filter;
- int i = 0, j = 0;
+ int i = 0, j = 0, err;
damos_for_each_ops_filter_safe(dst_filter, next, dst) {
src_filter = damos_nth_ops_filter(i++, src);
- if (src_filter)
- damos_commit_filter(dst_filter, src_filter);
- else
+ if (src_filter) {
+ err = damos_commit_filter(dst_filter, src_filter);
+ if (err)
+ return err;
+ } else {
damos_destroy_filter(dst_filter);
+ }
}
damos_for_each_ops_filter_safe(src_filter, next, src) {
@@ -1324,7 +1350,11 @@ static int damos_commit_ops_filters(struct damos *dst, struct damos *src)
src_filter->allow);
if (!new_filter)
return -ENOMEM;
- damos_commit_filter_arg(new_filter, src_filter);
+ err = damos_commit_filter_arg(new_filter, src_filter);
+ if (err) {
+ damos_destroy_filter(new_filter);
+ return err;
+ }
damos_add_filter(dst, new_filter);
}
return 0;
@@ -2413,7 +2443,7 @@ static bool damos_filter_match(struct damon_ctx *ctx, struct damon_target *t,
bool matched = false;
struct damon_target *ti;
int target_idx = 0;
- unsigned long start, end;
+ unsigned long start, end, wsum;
*err = 0;
switch (filter->type) {
@@ -2450,6 +2480,11 @@ static bool damos_filter_match(struct damon_ctx *ctx, struct damon_target *t,
*err = damon_split_region_at(t, r, end - r->ar.start);
matched = true;
break;
+ case DAMOS_FILTER_TYPE_PROBE_HITS_WSUM:
+ wsum = damon_probe_hits_wsum(r, false, true, ctx);
+ matched = filter->range_min <= wsum &&
+ wsum <= filter->range_max;
+ break;
default:
return false;
}
@@ -3391,7 +3426,7 @@ static unsigned int damon_merge_score(struct damon_region *r, bool last,
struct damon_ctx *ctx, bool use_probe_hits)
{
if (use_probe_hits)
- return damon_probe_hits_wsum(r, last, ctx);
+ return damon_probe_hits_wsum(r, last, false, ctx);
if (last)
return r->last_nr_accesses;
return r->nr_accesses;
diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
index 9ddd1ec8202b7..7d93db475f8cd 100644
--- a/mm/damon/paddr.c
+++ b/mm/damon/paddr.c
@@ -183,7 +183,7 @@ static unsigned int damon_pa_apply_probes(struct damon_ctx *ctx,
folio_put(folio);
if (return_max_wsum)
max_wsum = max(damon_probe_hits_wsum(r, false,
- ctx), max_wsum);
+ false, ctx), max_wsum);
}
}
return max_wsum;
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index 20eb8c242f2f8..a997539d0e816 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -534,7 +534,8 @@ struct damon_sysfs_scheme_filter {
bool allow;
char *memcg_path;
struct damon_addr_range addr_range;
- struct damon_size_range sz_range;
+ unsigned long range_min;
+ unsigned long range_max;
int target_idx;
};
@@ -588,6 +589,10 @@ damos_sysfs_filter_type_names[] = {
.type = DAMOS_FILTER_TYPE_TARGET,
.name = "target",
},
+ {
+ .type = DAMOS_FILTER_TYPE_PROBE_HITS_WSUM,
+ .name = "probe_hits_wsum",
+ },
};
static ssize_t type_show(struct kobject *kobj,
@@ -778,7 +783,7 @@ static ssize_t min_show(struct kobject *kobj,
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
struct damon_sysfs_scheme_filter, kobj);
- return sysfs_emit(buf, "%lu\n", filter->sz_range.min);
+ return sysfs_emit(buf, "%lu\n", filter->range_min);
}
static ssize_t min_store(struct kobject *kobj,
@@ -786,7 +791,7 @@ static ssize_t min_store(struct kobject *kobj,
{
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
struct damon_sysfs_scheme_filter, kobj);
- int err = kstrtoul(buf, 0, &filter->sz_range.min);
+ int err = kstrtoul(buf, 0, &filter->range_min);
return err ? err : count;
}
@@ -797,7 +802,7 @@ static ssize_t max_show(struct kobject *kobj,
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
struct damon_sysfs_scheme_filter, kobj);
- return sysfs_emit(buf, "%lu\n", filter->sz_range.max);
+ return sysfs_emit(buf, "%lu\n", filter->range_max);
}
static ssize_t max_store(struct kobject *kobj,
@@ -805,7 +810,7 @@ static ssize_t max_store(struct kobject *kobj,
{
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
struct damon_sysfs_scheme_filter, kobj);
- int err = kstrtoul(buf, 0, &filter->sz_range.max);
+ int err = kstrtoul(buf, 0, &filter->range_max);
return err ? err : count;
}
@@ -2834,8 +2839,16 @@ static int damon_sysfs_add_scheme_filters(struct damos *scheme,
} else if (filter->type == DAMOS_FILTER_TYPE_TARGET) {
filter->target_idx = sysfs_filter->target_idx;
} else if (filter->type == DAMOS_FILTER_TYPE_HUGEPAGE_SIZE) {
- filter->sz_range = sysfs_filter->sz_range;
- if (filter->sz_range.min > filter->sz_range.max) {
+ filter->sz_range.min = sysfs_filter->range_min;
+ filter->sz_range.max = sysfs_filter->range_max;
+ if (filter->range_min > filter->range_max) {
+ damos_destroy_filter(filter);
+ return -EINVAL;
+ }
+ } else if (filter->type == DAMOS_FILTER_TYPE_PROBE_HITS_WSUM) {
+ filter->range_min = sysfs_filter->range_min;
+ filter->range_max = sysfs_filter->range_max;
+ if (filter->range_min > filter->range_max) {
damos_destroy_filter(filter);
return -EINVAL;
}
--
2.53.0
next prev parent reply other threads:[~2026-11-10 17:15 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-07 10:04 FAILED: patch "[PATCH] mm/damon/sysfs-schemes: drop centralized filter range arg validations" failed to apply to 7.3-stable tree Sasha Levin
2026-11-10 17:15 ` Sasha Levin [this message]
2026-11-10 17:15 ` [PATCH 7.3.y 2/2] mm/damon/sysfs-schemes: drop centralized filter range arg validations Sasha Levin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261110171205.2600662-1-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=corbet@lwn.net \
--cc=david@kernel.org \
--cc=liam@infradead.org \
--cc=ljs@kernel.org \
--cc=mhocko@suse.com \
--cc=rdunlap@infradead.org \
--cc=rppt@kernel.org \
--cc=sj@kernel.org \
--cc=stable@vger.kernel.org \
--cc=surenb@google.com \
--cc=vbabka@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox