From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794330906; b=t1xcyaGg4a4GLJSPD9X/POjMy/orLih69DKCfoTrYqJsil8VkCu/l73S3z4j/EThIzhA yFiKzLYd1vCQD7jijLs2YW5e2x8uDnICenA9CMqH24kQRHF5CUTiw3zctorS1cmBE2RbN 9abjFByG3oFilcElpNz0NngdvUg64lP48K50p2w3BlEBMU0xLRVWaohvqAdHxJmlgaaUK jHYx6SeNQO4XyYsiGqMpDr7z74i0GLh+6uSmL7MRIK9x1Ols5SnFCOREILmu76hTx5hb3 sM8oXePyrC1ubhEAcIk9cKylF9yDGeBt1Icp16YslYs6Xi2Ksf8dOcqwco+xfP7dMFw== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794330906; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=h5zZr8osbh0hlYbp05uBL7+cdp7ESQRRTPwM6uuFiM0=; b=4IVOm+eb1e0hRKcdrTz/PIiG69n/wxi15IQW3IHbOJWwAYl608Zn9vHJtiIaCpTNEymD RelO+NzXR1gZHtLcS5YmfdpPOFR+Lxd0DEMXe2DD70GKqbttfxTYQtB3lb0q+DUwHgBsr lTrfEdS6Awp97eroDVdRWRPc8lh68DitdjS5G88itfOLnWP+z9XNF6evu0pUZjrSzCGUU D4UwZpo31lRtaXmLrNdGrq6/+o9iDBIvSiZvvuP0kE4nkkmMSMn4zrRBPV40ITvBfou9b oBBANBXskhiZrSwa+sc44ZXiyRSZ1cxUDImSHi9oSdI1WrtIXhLOz6qlng384u/53XA== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=IZUYnR81; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CC0E0606A323 for ; Tue, 10 Nov 2026 17:15:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=IZUYnR81 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 03A6F1F0089F; Tue, 10 Nov 2026 17:15:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1794330905; bh=h5zZr8osbh0hlYbp05uBL7+cdp7ESQRRTPwM6uuFiM0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=IZUYnR81uh2OOknZcIMo4EqN3jwmkIggEy8pGLttkktR5/Tgq4LWyMpbpLN65h73j ZtSNPSc3CW8mD5/WvZKPIh3y+VuBmuwHu5OF1P5+m/LlkBzJ9irXKjWKW9fekiza8l 4N3i+oc2uPSMVavUBwFLGVvB48SZ5SF6dIlImB8P/Xarr1y54t/MeuLw27wr/Pb9yg SIsY2yrbwwfEU2tsV0lMOzOLZ+2a5iSpIQnyOdrSk9MpuHHBSUgDi5JCSSgSghMgZX TkKJJg4FJIydDZnAPetGzJ6Jl5mr2UxdAt7QkhFIa4h70OqcYlShUqEixJs4AoD1SO EbhNFl18maYdQ== From: Sasha Levin To: stable@vger.kernel.org Cc: SJ Park , Andrew Morton , David Hildenbrand , Jonathan Corbet , "Liam R. Howlett" , Lorenzo Stoakes , Michal Hocko , Mike Rapoport , Randy Dunlap , Suren Baghdasaryan , Vlastimil Babka , Sasha Levin 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 Message-ID: <20261110171205.2600662-1-sashal@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261107050429-failed-7.3-1d2397b2c414@kernel.org> References: <20261107050429-failed-7.3-1d2397b2c414@kernel.org> X-Mailing-List: stable@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: SJ Park [ 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 Signed-off-by: Andrew Morton Cc: David Hildenbrand Cc: Jonathan Corbet Cc: Liam R. Howlett Cc: Lorenzo Stoakes Cc: Michal Hocko Cc: Mike Rapoport Cc: Randy Dunlap Cc: Suren Baghdasaryan Cc: Vlastimil Babka 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 --- 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 ` 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 ` 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