Skip to contentSkip to conversation

FAILED: patch "[PATCH] mm/damon/core: allow esz to be set to zero" failed to apply to 6.12-stable tree

PATCH In review [email protected] 3 participants 4 messages Sep 29 – Sep 30

Subsystems (3)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

The patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.

To reproduce the conflict and resubmit, you may use the following commands:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 90179da203ba8b708c84a12a07cd44be0f346334
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026092900-prize-superglue-6d70@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'

Possible dependencies:

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From 90179da203ba8b708c84a12a07cd44be0f346334 Mon Sep 17 00:00:00 2001
From: Liew Rui Yan <[email protected]>
Date: Tue, 8 Sep 2026 06:54:11 -0700
Subject: [PATCH] mm/damon/core: allow esz to be set to zero

When the temporal quota goal tuner determines that the goal has been achieved (score >= 10000), it sets esz_bp to zero so that the esz becomes zero. However, damos_set_effective_quota() clamps the esz to min_region_sz when quota->ms is set.

This is a minor issue, the main problem is that it doesn't match the description in the documentation, which state that if the goal has already been [over-]achieved, the quota will be set to zero.

Fix this by set quota (esz) as minimum as possible.

Fixes 8bbde987c2b8 ("mm/damon/core: disallow time-quota setting zero esz")
Cc <[email protected]> # v7.1.x
mm/damon/core.c +3 -2
index 644daf5a1656..2b294fb46648 100644
@@ -3091,6 +3091,7 @@ static void damos_set_effective_quota(struct damon_ctx *ctx, struct damos *s)
 	struct damos_quota *quota = &s->quota;
 	unsigned long throughput;
 	unsigned long esz = ULONG_MAX;
+	unsigned long esz_time;
 
 	if (!quota->ms && list_empty(&quota->goals)) {
 		quota->esz = quota->sz;
@@ -3111,8 +3112,8 @@ static void damos_set_effective_quota(struct damon_ctx *ctx, struct damos *s)
 					1000000, quota->total_charged_ns);
 		else
 			throughput = PAGE_SIZE * 1024;
-		esz = min(throughput * quota->ms, esz);
-		esz = max(ctx->min_region_sz, esz);
+		esz_time = max(throughput * quota->ms, ctx->min_region_sz);
+		esz = min(esz_time, esz);
 	}
 
 	if (quota->sz && quota->sz < esz)
maintainer
#1 lore raw

PATCH 1/2 mm/damon: rename DAMON_MIN_REGION to DAMON_MIN_REGION_SZ

From: SeongJae Park <[email protected]>

[ Upstream commit dfb1b0c9dc0d61e422905640e1e7334b3cf6f384 ]

The macro is for the default minimum size of each DAMON region. There was a case that a reader was confused if it is the minimum number of total DAMON regions, which is set on damon_attrs->min_nr_regions. Make the name more explicit.

Stable dependency adaptation for 90179da203ba:

Rename every use present in 6.12, including the core KUnit override and filter tests. Drop upstream hunks for address units, per-context region alignment, and the newer damon_set_regions() signature, which are absent from this tree. Preserve the stable region-setting validation and error handling.

Prepare the existing quota calculation for the unmodified target patch:
store the fixed minimum region size in damon_ctx, pass the context and scheme to damos_set_effective_quota(), initialize esz to ULONG_MAX, and use the upstream mult_frac() throughput calculation. Keep the existing minimum quota clamp for the target to fix. No functions are added.

[ sashal: Reduced backport -- upstream dfb1b0c9dc0d6 touches 7 file(s), this
backport carries 4. Not backported here:
mm/damon/lru_sort.c
mm/damon/reclaim.c
mm/damon/sysfs.c
mm/damon/tests/vaddr-kunit.h
This note is generated from the file lists only; see the resolution record for the reasoning. ]

Stable-dep-of: 90179da203ba ("mm/damon/core: allow esz to be set to zero")

---
 include/linux/damon.h       |  4 ++-
 mm/damon/core.c             | 56 ++++++++++++++++++-------------------
 mm/damon/tests/core-kunit.h | 36 ++++++++++++------------
 mm/damon/vaddr.c            | 22 +++++++--------
 4 files changed, 60 insertions(+), 58 deletions(-)
include/linux/damon.h +3 -1
index 4688a10eca89b..dda0357026edf 100644
@@ -15,7 +15,7 @@
 #include <linux/random.h>
 
 /* Minimal region size.  Every damon_region is aligned by this. */
-#define DAMON_MIN_REGION	PAGE_SIZE
+#define DAMON_MIN_REGION_SZ	PAGE_SIZE
 /* Max priority score for DAMON-based operation schemes */
 #define DAMOS_MAX_SCORE		(99)
 
@@ -631,6 +631,8 @@ struct damon_ctx {
 	struct completion kdamond_started;
 	/* for scheme quotas prioritization */
 	unsigned long *regions_score_histogram;
+	/* minimum region size for time quotas, fixed on this stable branch */
+	unsigned long min_region_sz;
 
 /* public: */
 	struct task_struct *kdamond;
mm/damon/core.c +28 -28

145 lines not on this page · raw message

mm/damon/tests/core-kunit.h +18 -18
index ff9f73579f7b3..a97a4326a227e 100644
@@ -530,10 +530,10 @@ static void damos_test_filter_out(struct kunit *test)
 
 	f = damos_new_filter(DAMOS_FILTER_TYPE_ADDR, true);
 	f->addr_range = (struct damon_addr_range){
-		.start = DAMON_MIN_REGION * 2, .end = DAMON_MIN_REGION * 6};
+		.start = DAMON_MIN_REGION_SZ * 2, .end = DAMON_MIN_REGION_SZ * 6};
 
 	t = damon_new_target();
-	r = damon_new_region(DAMON_MIN_REGION * 3, DAMON_MIN_REGION * 5);
+	r = damon_new_region(DAMON_MIN_REGION_SZ * 3, DAMON_MIN_REGION_SZ * 5);
 	damon_add_region(r, t);
 
 	/* region in the range */
@@ -541,45 +541,45 @@ static void damos_test_filter_out(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1);
 
 	/* region before the range */
-	r->ar.start = DAMON_MIN_REGION * 1;
-	r->ar.end = DAMON_MIN_REGION * 2;
+	r->ar.start = DAMON_MIN_REGION_SZ * 1;
+	r->ar.end = DAMON_MIN_REGION_SZ * 2;
 	KUNIT_EXPECT_FALSE(test, __damos_filter_out(NULL, t, r, f));
 	KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1);
 
 	/* region after the range */
-	r->ar.start = DAMON_MIN_REGION * 6;
-	r->ar.end = DAMON_MIN_REGION * 8;
+	r->ar.start = DAMON_MIN_REGION_SZ * 6;
+	r->ar.end = DAMON_MIN_REGION_SZ * 8;
 	KUNIT_EXPECT_FALSE(test, __damos_filter_out(NULL, t, r, f));
 	KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1);
 
 	/* region started before the range */
-	r->ar.start = DAMON_MIN_REGION * 1;
-	r->ar.end = DAMON_MIN_REGION * 4;
+	r->ar.start = DAMON_MIN_REGION_SZ * 1;
+	r->ar.end = DAMON_MIN_REGION_SZ * 4;
 	KUNIT_EXPECT_FALSE(test, __damos_filter_out(NULL, t, r, f));
 	/* filter should have split the region */
-	KUNIT_EXPECT_EQ(test, r->ar.start, DAMON_MIN_REGION * 1);
-	KUNIT_EXPECT_EQ(test, r->ar.end, DAMON_MIN_REGION * 2);
+	KUNIT_EXPECT_EQ(test, r->ar.start, DAMON_MIN_REGION_SZ * 1);
+	KUNIT_EXPECT_EQ(test, r->ar.end, DAMON_MIN_REGION_SZ * 2);
 	KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 2);
 	if (damon_nr_regions(t) != 2)
 		goto out;
 	r2 = damon_next_region(r);
-	KUNIT_EXPECT_EQ(test, r2->ar.start, DAMON_MIN_REGION * 2);
-	KUNIT_EXPECT_EQ(test, r2->ar.end, DAMON_MIN_REGION * 4);
+	KUNIT_EXPECT_EQ(test, r2->ar.start, DAMON_MIN_REGION_SZ * 2);
+	KUNIT_EXPECT_EQ(test, r2->ar.end, DAMON_MIN_REGION_SZ * 4);
 	damon_destroy_region(r2, t);
 
 	/* region started in the range */
-	r->ar.start = DAMON_MIN_REGION * 2;
-	r->ar.end = DAMON_MIN_REGION * 8;
+	r->ar.start = DAMON_MIN_REGION_SZ * 2;
+	r->ar.end = DAMON_MIN_REGION_SZ * 8;
 	KUNIT_EXPECT_TRUE(test, __damos_filter_out(NULL, t, r, f));
 	/* filter should have split the region */
-	KUNIT_EXPECT_EQ(test, r->ar.start, DAMON_MIN_REGION * 2);
-	KUNIT_EXPECT_EQ(test, r->ar.end, DAMON_MIN_REGION * 6);
+	KUNIT_EXPECT_EQ(test, r->ar.start, DAMON_MIN_REGION_SZ * 2);
+	KUNIT_EXPECT_EQ(test, r->ar.end, DAMON_MIN_REGION_SZ * 6);
 	KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 2);
 	if (damon_nr_regions(t) != 2)
 		goto out;
 	r2 = damon_next_region(r);
-	KUNIT_EXPECT_EQ(test, r2->ar.start, DAMON_MIN_REGION * 6);
-	KUNIT_EXPECT_EQ(test, r2->ar.end, DAMON_MIN_REGION * 8);
+	KUNIT_EXPECT_EQ(test, r2->ar.start, DAMON_MIN_REGION_SZ * 6);
+	KUNIT_EXPECT_EQ(test, r2->ar.end, DAMON_MIN_REGION_SZ * 8);
 	damon_destroy_region(r2, t);
 
 out:
mm/damon/vaddr.c +11 -11
index 089ee23e07de7..b423ce9da392d 100644
@@ -18,8 +18,8 @@
 #include "ops-common.h"
 
 #ifdef CONFIG_DAMON_VADDR_KUNIT_TEST
-#undef DAMON_MIN_REGION
-#define DAMON_MIN_REGION 1
+#undef DAMON_MIN_REGION_SZ
+#define DAMON_MIN_REGION_SZ 1
 #endif
 
 /*
@@ -74,7 +74,7 @@ static int damon_va_evenly_split_region(struct damon_target *t,
 
 	orig_end = r->ar.end;
 	sz_orig = damon_sz_region(r);
-	sz_piece = ALIGN_DOWN(sz_orig / nr_pieces, DAMON_MIN_REGION);
+	sz_piece = ALIGN_DOWN(sz_orig / nr_pieces, DAMON_MIN_REGION_SZ);
 
 	if (!sz_piece)
 		return -EINVAL;
@@ -157,12 +157,12 @@ static int __damon_va_three_regions(struct mm_struct *mm,
 		swap(first_gap, second_gap);
 
 	/* Store the result */
-	regions[0].start = ALIGN(start, DAMON_MIN_REGION);
-	regions[0].end = ALIGN(first_gap.start, DAMON_MIN_REGION);
-	regions[1].start = ALIGN(first_gap.end, DAMON_MIN_REGION);
-	regions[1].end = ALIGN(second_gap.start, DAMON_MIN_REGION);
-	regions[2].start = ALIGN(second_gap.end, DAMON_MIN_REGION);
-	regions[2].end = ALIGN(prev->vm_end, DAMON_MIN_REGION);
+	regions[0].start = ALIGN(start, DAMON_MIN_REGION_SZ);
+	regions[0].end = ALIGN(first_gap.start, DAMON_MIN_REGION_SZ);
+	regions[1].start = ALIGN(first_gap.end, DAMON_MIN_REGION_SZ);
+	regions[1].end = ALIGN(second_gap.start, DAMON_MIN_REGION_SZ);
+	regions[2].start = ALIGN(second_gap.end, DAMON_MIN_REGION_SZ);
+	regions[2].end = ALIGN(prev->vm_end, DAMON_MIN_REGION_SZ);
 
 	return 0;
 }
@@ -255,8 +255,8 @@ static void __damon_va_init_regions(struct damon_ctx *ctx,
 		sz += regions[i].end - regions[i].start;
 	if (ctx->attrs.min_nr_regions)
 		sz /= ctx->attrs.min_nr_regions;
-	if (sz < DAMON_MIN_REGION)
-		sz = DAMON_MIN_REGION;
+	if (sz < DAMON_MIN_REGION_SZ)
+		sz = DAMON_MIN_REGION_SZ;
 
 	/* Set the initial three regions of the target */
 	for (i = 0; i < 3; i++) {
Signature · 1 line
2.53.0
maintainer
#2 lore raw

PATCH 2/2 mm/damon/core: allow esz to be set to zero

From: Liew Rui Yan <[email protected]>

[ Upstream commit 90179da203ba8b708c84a12a07cd44be0f346334 ]

When the temporal quota goal tuner determines that the goal has been achieved (score >= 10000), it sets esz_bp to zero so that the esz becomes zero. However, damos_set_effective_quota() clamps the esz to min_region_sz when quota->ms is set.

This is a minor issue, the main problem is that it doesn't match the description in the documentation, which state that if the goal has already been [over-]achieved, the quota will be set to zero.

Fix this by set quota (esz) as minimum as possible.

Fixes 8bbde987c2b8 ("mm/damon/core: disallow time-quota setting zero esz")
Cc <[email protected]> # v7.1.x
---
 mm/damon/core.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
mm/damon/core.c +3 -2
index c74a0cc9ea413..5b86d3db627ad 100644
@@ -1638,6 +1638,7 @@ static void damos_set_effective_quota(struct damon_ctx *ctx, struct damos *s)
 	struct damos_quota *quota = &s->quota;
 	unsigned long throughput;
 	unsigned long esz = ULONG_MAX;
+	unsigned long esz_time;
 
 	if (!quota->ms && list_empty(&quota->goals)) {
 		quota->esz = quota->sz;
@@ -1659,8 +1660,8 @@ static void damos_set_effective_quota(struct damon_ctx *ctx, struct damos *s)
 					1000000, quota->total_charged_ns);
 		else
 			throughput = PAGE_SIZE * 1024;
-		esz = min(throughput * quota->ms, esz);
-		esz = max(ctx->min_region_sz, esz);
+		esz_time = max(throughput * quota->ms, ctx->min_region_sz);
+		esz = min(esz_time, esz);
 	}
 
 	if (quota->sz && quota->sz < esz)
Signature · 1 line
2.53.0
maintainer
#3 lore raw

Re: [PATCH 6.12.y 2/2] mm/damon/core: allow esz to be set to zero

Hello Sasha,

Quoted 9 lines · On Tue, 29 Sep 2026 20:04:01 -0400 Sasha Levin <[email protected]> wrote:

From: Liew Rui Yan <[email protected]>

[ Upstream commit 90179da203ba8b708c84a12a07cd44be0f346334 ]

When the temporal quota goal tuner determines that the goal has been achieved (score >= 10000), it sets esz_bp to zero so that the esz becomes zero. However, damos_set_effective_quota() clamps the esz to min_region_sz when quota->ms is set.

Quoted 5 lines

This is a minor issue, the main problem is that it doesn't match the description in the documentation, which state that if the goal has already been [over-]achieved, the quota will be set to zero.

Fix this by set quota (esz) as minimum as possible.

Thank you for doing this backport.

Quoted 3 lines
Fixes 8bbde987c2b8 ("mm/damon/core: disallow time-quota setting zero esz")

However, this patch also depends on temporal tuner feature, which was introduced by 7.1. It is not in <7.1 stable kernels. So this patch shouldn't be applied on those, including 6.12.y. Could you please drop this patch?

Thanks,
SJ

[...]