Skip to contentSkip to conversation

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

PATCH In review SJ Park 3 participants 8 messages Sep 29 – Sep 30

Subsystems (2)
lore
Share & tools
lore

SJ Park

author maintainer
#0 lore raw

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

From: Liew Rui Yan <[email protected]>

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
(cherry picked from commit 90179da203ba8b708c84a12a07cd44be0f346334)
---
 mm/damon/core.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
mm/damon/core.c +3 -2
index 6fa02025d2af1..facb1fa1f695f 100644
@@ -2191,6 +2191,7 @@ static void damos_set_effective_quota(struct damos_quota *quota,
 {
 	unsigned long throughput;
 	unsigned long esz = ULONG_MAX;
+	unsigned long esz_time;
 
 	if (!quota->ms && list_empty(&quota->goals)) {
 		quota->esz = quota->sz;
@@ -2212,8 +2213,8 @@ static void damos_set_effective_quota(struct damos_quota *quota,
 							quota->total_charged_ns);
 		else
 			throughput = PAGE_SIZE * 1024;
-		esz = min(throughput * quota->ms, esz);
-		esz = max(ctx->min_sz_region, esz);
+		esz_time = max(throughput * quota->ms, ctx->min_sz_region);
+		esz = min(esz_time, esz);
 	}
 
 	if (quota->sz && quota->sz < esz)
Signature · 1 line
2.47.3
author maintainer
#1 lore raw

PATCH 2/2 mm/damon/core: fix unconditionally skip last region

From: Liew Rui Yan <[email protected]>

Once quota set, the charge_{target,addr}_from unconditionally skips and resets at the last region of the tracked target, so the last region can be skipped even when it has not been processed.

Example:

1. Target has 2 regions: R1 (0-100 bytes) and R2 (100-200 bytes).
2. Quota is configured to process only 100 bytes per window.
3. Window 1: Processes R1 (0-100). Quota is full. charge_{target, addr}_from is saved at (Target, 100).
4. Window 2: The loop reaches R2. Because R2 is damon_last_region(t), the old code unconditionally returns true, skipping R2 entirely and resetting the charge_{target,addr}_from.

Result: R2 is permanently skipped even though it has never been processed.

However, it is important to note that this is a very minor issue. This is because it is triggered only when the previous window saved/kept charge_{target,addr}_from, and in the next window, all regions except the last region were skipped by damos_skip_charged_region().

Fix this by only resetting the charge_{target,addr}_from when last region is reached, only skipping when it is applied or cannot split.

Fixes 50585192bc2e ("mm/damon/schemes: skip already charged targets and regions")
Cc <[email protected]> # v5.16.x
(cherry picked from commit b3723b596b548c837a766aae3553c14a7b15af2b)
---
 mm/damon/core.c | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)
mm/damon/core.c +14 -10
index facb1fa1f695f..5bb69a4d2ffdf 100644
@@ -1746,37 +1746,41 @@ static bool damos_skip_charged_region(struct damon_target *t,
 	struct damon_region *r = *rp;
 	struct damos_quota *quota = &s->quota;
 	unsigned long sz_to_skip;
+	bool skip = false;
 
 	/* Skip previously charged regions */
 	if (quota->charge_target_from) {
 		if (t != quota->charge_target_from)
 			return true;
-		if (r == damon_last_region(t)) {
-			quota->charge_target_from = NULL;
-			quota->charge_addr_from = 0;
-			return true;
-		}
 		if (quota->charge_addr_from &&
-				r->ar.end <= quota->charge_addr_from)
-			return true;
+				r->ar.end <= quota->charge_addr_from) {
+			skip = true;
+			goto out;
+		}
 
 		if (quota->charge_addr_from && r->ar.start <
 				quota->charge_addr_from) {
 			sz_to_skip = ALIGN_DOWN(quota->charge_addr_from -
 					r->ar.start, min_sz_region);
 			if (!sz_to_skip) {
-				if (damon_sz_region(r) <= min_sz_region)
-					return true;
+				if (damon_sz_region(r) <= min_sz_region) {
+					skip = true;
+					goto out;
+				}
 				sz_to_skip = min_sz_region;
 			}
 			damon_split_region_at(t, r, sz_to_skip);
 			r = damon_next_region(r);
 			*rp = r;
+			skip = false;
 		}
+	}
+out:
+	if (r == damon_last_region(t)) {
 		quota->charge_target_from = NULL;
 		quota->charge_addr_from = 0;
 	}
-	return false;
+	return skip;
 }
 
 static void damos_update_stat(struct damos *s,
Signature · 1 line
2.47.3
#2 lore raw

Re: [PATCH 6.18.y 2/2] mm/damon/core: fix unconditionally skip last region

Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 15 lines

From: Liew Rui Yan <[email protected]>

Once quota set, the charge_{target,addr}_from unconditionally skips and resets at the last region of the tracked target, so the last region can be skipped even when it has not been processed.

Example:

1. Target has 2 regions: R1 (0-100 bytes) and R2 (100-200 bytes).
2. Quota is configured to process only 100 bytes per window.
3. Window 1: Processes R1 (0-100). Quota is full. charge_{target, addr}_from is saved at (Target, 100).
4. Window 2: The loop reaches R2. Because R2 is damon_last_region(t), the old code unconditionally returns true, skipping R2 entirely and resetting the charge_{target,addr}_from.

Quoted 6 lines
[ ... ]
Cc <[email protected]> # v5.16.x
(cherry picked from commit b3723b596b548c837a766aae3553c14a7b15af2b)

Sashiko has reviewed this patch and found no issues. It looks great!

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
#3 lore raw
In reply to SJ Park
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] mm/damon: removing min_sz_region clamp on esz breaks quota accounting --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] mm/damon: removing min_sz_region clamp on esz breaks quota accounting --

commit f7906e90ad53cf62853b7b051dfd11b8012181f1
Author: Liew Rui Yan <[email protected]>
Subject: mm/damon/core: allow esz to be set to zero

This patch modifies damos_set_effective_quota() to allow the effective size quota (esz) to be reduced as much as possible when temporal quota goals are achieved. It does this by removing the clamp against min_sz_region when calculating esz.

Quoted 4 lines
mm/damon/core.c +0 -0
index 6fa02025d2af1..facb1fa1f695f 100644

[ ... ]

mm/damon/core.c static void damos_set_effective_quota(struct damos_quota *quota, · line 2218

Quoted 9 lines
mm/damon/core.c +2 -2
@@ -2212,8 +2213,8 @@ static void damos_set_effective_quota(struct damos_quota *quota,
 							quota->total_charged_ns);
 		else
 			throughput = PAGE_SIZE * 1024;
-		esz = min(throughput * quota->ms, esz);
-		esz = max(ctx->min_sz_region, esz);
+		esz_time = max(throughput * quota->ms, ctx->min_sz_region);
+		esz = min(esz_time, esz);
 	}

[Severity: Medium]
Will this break quota accounting when goals are over-achieved?

By removing the clamp against min_sz_region, esz can drop below the minimum region size, for example to 1.

If esz becomes 1, does ALIGN_DOWN() in damos_apply_scheme() evaluate to 0?

mm/damon/core.c:damos_apply_scheme() {
        if (quota->esz && quota->charged_sz + sz > quota->esz) {
                sz = ALIGN_DOWN(quota->esz - quota->charged_sz,
                                c->min_sz_region);
                if (!sz)
                        goto update_stat;
                damon_split_region_at(t, r, sz);
        }
        ...
        quota->charged_sz += sz;
}

If sz evaluates to 0, it jumps to update_stat and bypasses incrementing quota->charged_sz.

Because quota->charged_sz gets frozen at 0, wouldn't this prevent the quota short-circuit from ever being taken in damon_do_apply_schemes()?

mm/damon/core.c:damon_do_apply_schemes() {
        /* Check the quota */
        if (quota->esz && quota->charged_sz >= quota->esz)
                continue;
}

Can this also corrupt the qt_exceeds statistic since the same check fails in damos_adjust_quota()?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
author maintainer
#4 lore raw
In reply to SJ Park

Hello stable team,

Please don't apply this patch.

Quoted 7 lines · On Tue, 29 Sep 2026 10:44:55 -0700 SJ Park <[email protected]> wrote:

From: Liew Rui Yan <[email protected]>

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 8 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.

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

The problem happens only when there is temporal tuner. Temporal tuner is a feature that introduced in 7.1. Hence <7.1 stable kernels don't have the temporal tuner, and this patch shouldn't be applied.

Thanks,
SJ

[...]

#5 lore raw
Quoted 18 lines · SJ Park

Hello stable team,

Please don't apply this patch.

Quoted 11 lines · On Tue, 29 Sep 2026 10:44:55 -0700 SJ Park <[email protected]> wrote:

From: Liew Rui Yan <[email protected]>

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.

Quoted 8 lines
Quoted 4 lines

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

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

The problem happens only when there is temporal tuner. Temporal tuner is a feature that introduced in 7.1. Hence <7.1 stable kernels don't have the temporal tuner, and this patch shouldn't be applied.

SHould we skip patch 2/2 here too?

author maintainer
#6 lore raw
Quoted 21 lines · On Wed, 30 Sep 2026 06:34:35 +0200 Greg KH <[email protected]> wrote:
Quoted 20 lines · SJ Park

Hello stable team,

Please don't apply this patch.

Quoted 13 lines · On Tue, 29 Sep 2026 10:44:55 -0700 SJ Park <[email protected]> wrote:

From: Liew Rui Yan <[email protected]>

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.

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

The problem happens only when there is temporal tuner. Temporal tuner is a feature that introduced in 7.1. Hence <7.1 stable kernels don't have the temporal tuner, and this patch shouldn't be applied.

SHould we skip patch 2/2 here too?

2/2 is good. Sorry for not clarifying it. Please let me know if there is anything I can help.

Thanks,
SJ

#7 lore raw
Quoted 26 lines · SJ Park
Quoted 24 lines · On Wed, 30 Sep 2026 06:34:35 +0200 Greg KH <[email protected]> wrote:
Quoted 23 lines · SJ Park

Hello stable team,

Please don't apply this patch.

Quoted 15 lines · On Tue, 29 Sep 2026 10:44:55 -0700 SJ Park <[email protected]> wrote:

From: Liew Rui Yan <[email protected]>

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")
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines

The problem happens only when there is temporal tuner. Temporal tuner is a feature that introduced in 7.1. Hence <7.1 stable kernels don't have the temporal tuner, and this patch shouldn't be applied.

SHould we skip patch 2/2 here too?

2/2 is good. Sorry for not clarifying it. Please let me know if there is anything I can help.

Great, I'll take that one now, thanks.

greg k-h