Skip to contentSkip to conversation

mm/damon/core: fix false positive in damos_quota_is_full() when esz is zero

PATCH In review Liew Rui Yan 3 participants 18 messages Sep 2 – Sep 7

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 mm/damon/core: fix false positive in damos_quota_is_full() when esz is zero

When setting goal_tuner to 'temporal', if the goal is achieved, quota->esz_bp will be set to zero. In this case, damos_quota_is_full() will always return true, even if no regions have been tried to apply at all. This causes qt_exceeds to increase unexpectedly.

Fix it by:

- Returning false in damos_quota_is_full() when quota->charged_sz is zero.
- Adding an early exit in damon_do_apply_schemes() for schemes with zero esz.

Fixes c7ec7d5f6b3d ("mm/damon/core: handle <min_region_sz remaining quota as empty")
Cc <[email protected]> # v7.2.x

---

Changes from v2:
- v2: https://lore.kernel.org/damon/[email protected]
- Changed patch title, v2 title is truncated.

Changes from v1:
- v1: https://lore.kernel.org/damon/[email protected]
- Changed the check in damos_quota_is_full() from '!quota->esz' to '!quota->charged_sz', because the former is an upper bound, while the latter represents the actual quota usage.
- Added an early exit in damon_do_apply_schemes() to prevent a scheme with zero esz from being evaluated by damos_quota_is_full().
- Changed patch title, original title: always return false when esz is zero

---
 mm/damon/core.c | 5 +++++
 1 file changed, 5 insertions(+)
mm/damon/core.c +5 -0
index 8e3ded1a2cf6..de78ad56c8b3 100644
@@ -2560,6 +2560,8 @@ static bool damos_quota_is_full(struct damos_quota *quota,
 {
 	if (!damos_quota_is_set(quota))
 		return false;
+	if (!quota->charged_sz)
+		return false;
 	if (quota->charged_sz >= quota->esz)
 		return true;
 	/*
@@ -2666,6 +2668,9 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
 		if (!s->wmarks.activated)
 			continue;
 
+		if (!quota->esz)
+			continue;
+
 		/* Check the quota */
 		if (damos_quota_is_full(quota, c->min_region_sz))
 			continue;
Signature · 1 line
2.55.0
#1 lore raw
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] Schemes without configured quota limits (unlimited quotas) are completely skipped and never…

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Schemes without configured quota limits (unlimited quotas) are completely skipped and never applied due to the new !quota->esz early exit check.
- [Medium] Incorrect quota evaluation for very small quotas (0 < esz < min_region_sz) breaks the early short-circuit optimization, causing wasted CPU cycles, artificially inflated statistics, and broken telemetry. --

commit 4718f859e447852ff19b6830ab8bf79106ad37d1
Author: Liew Rui Yan <[email protected]>
Subject: mm/damon/core: fix false positive in damos_quota_is_full() when esz is zero

This patch aims to fix an issue where damos_quota_is_full() returns true when quota->esz_bp drops to zero, even if no regions have been tried. It attempts to resolve this by adding early checks for zero quota->charged_sz and zero quota->esz.

Cc <[email protected]> # v7.2.x

mm/damon/core.c static bool damos_quota_is_full(struct damos_quota *quota, · line 2659

Quoted 10 lines
mm/damon/core.c +2 -0
index df22621765911..f8c784df24600 100644
@@ -2655,6 +2655,8 @@ static bool damos_quota_is_full(struct damos_quota *quota,
 {
 	if (!damos_quota_is_set(quota))
 		return false;
+	if (!quota->charged_sz)
+		return false;

[Severity: Medium]
Could this cause an evaluation loop that degrades performance when the configured quota is very small?

If a quota is configured such that 0 < quota->esz < min_region_sz, quota->charged_sz starts at 0 at the beginning of the quota window. This new check will return false, bypassing the subsequent small remaining quota check:

    return quota->esz - quota->charged_sz < min_region_sz;

This falsely signals available quota. Later, when damon_do_apply_schemes() calls damos_apply_scheme(), the size is calculated as:

    sz = ALIGN_DOWN(quota->esz - quota->charged_sz, c->min_region_sz);

Because esz < min_region_sz and charged_sz is 0, sz evaluates to 0. The code then jumps to update_stat, which increments nr_tried but does not increase charged_sz.

Since charged_sz remains 0, the next region will also evaluate to 0 and skip charging. Won't this loop wastefully over every region in an O(N) fashion, artificially inflating the nr_tried statistics and breaking the qt_exceeds telemetry?

mm/damon/core.c static void damon_do_apply_schemes(struct damon_ctx *c, · line 2757

Quoted 10 lines
mm/damon/core.c +3 -0
 	if (quota->charged_sz >= quota->esz)
 		return true;
 	/*
@@ -2750,6 +2752,9 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
 		if (!s->wmarks.activated)
 			continue;
 
+		if (!quota->esz)
+			continue;
+

[Severity: High]
Does this unconditional check completely skip schemes that do not have quota limits configured?

For unlimited schemes (schemes without configured quotas), damos_adjust_quota() returns early without calculating esz, leaving quota->esz initialized to 0. With this check, won't unlimited schemes silently fail to apply entirely because the loop unconditionally continues?

Quoted 3 lines
mm/damon/core.c +0 -0
 		/* Check the quota */
 		if (damos_quota_is_full(quota, c->min_region_sz))
 			continue;
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
#2 lore raw

There is no fundamental difference between the Sashiko report in the v2 thread [1] and the Sashiko report in this thread, so I did not foward it.

Quoted 43 lines · On Wed, 02 Sep 2026 08:53:35 +0000 [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Schemes without configured quota limits (unlimited quotas) are completely skipped and never applied due to the new !quota->esz early exit check.
- [Medium] Incorrect quota evaluation for very small quotas (0 < esz < min_region_sz) breaks the early short-circuit optimization, causing wasted CPU cycles, artificially inflated statistics, and broken telemetry. --

commit 4718f859e447852ff19b6830ab8bf79106ad37d1
Author: Liew Rui Yan <[email protected]>
Subject: mm/damon/core: fix false positive in damos_quota_is_full() when esz is zero

This patch aims to fix an issue where damos_quota_is_full() returns true when quota->esz_bp drops to zero, even if no regions have been tried. It attempts to resolve this by adding early checks for zero quota->charged_sz and zero quota->esz.

Cc <[email protected]> # v7.2.x

mm/damon/core.c static bool damos_quota_is_full(struct damos_quota *quota, · line 2659

Quoted 10 lines
mm/damon/core.c +2 -0
index df22621765911..f8c784df24600 100644
@@ -2655,6 +2655,8 @@ static bool damos_quota_is_full(struct damos_quota *quota,
 {
 	if (!damos_quota_is_set(quota))
 		return false;
+	if (!quota->charged_sz)
+		return false;

[Severity: Medium]
Could this cause an evaluation loop that degrades performance when the configured quota is very small?

If a quota is configured such that 0 < quota->esz < min_region_sz, quota->charged_sz starts at 0 at the beginning of the quota window. This new check will return false, bypassing the subsequent small remaining quota check:

    return quota->esz - quota->charged_sz < min_region_sz;

This falsely signals available quota. Later, when damon_do_apply_schemes() calls damos_apply_scheme(), the size is calculated as:

    sz = ALIGN_DOWN(quota->esz - quota->charged_sz, c->min_region_sz);
Quoted 8 lines

Because esz < min_region_sz and charged_sz is 0, sz evaluates to 0. The code then jumps to update_stat, which increments nr_tried but does not increase charged_sz.

Since charged_sz remains 0, the next region will also evaluate to 0 and skip charging. Won't this loop wastefully over every region in an O(N) fashion, artificially inflating the nr_tried statistics and breaking the qt_exceeds telemetry?

Thank you for pointing this out!

So the issue is that if 0 < esz < min_region_sz, then damos_apply_scheme() might incorrectly increment nr_tried.

I believe the solution should be to ensure that esz is never less than min_region_sz if esz is not zero. However, this may cause unexpected behavior when users set quota_sz, so additional documentation may be needed.

That said, this is already out of scope.

Quoted 16 lines

mm/damon/core.c static void damon_do_apply_schemes(struct damon_ctx *c, · line 2757

Quoted 11 lines
mm/damon/core.c +3 -0
 	if (quota->charged_sz >= quota->esz)
 		return true;
 	/*
@@ -2750,6 +2752,9 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
 		if (!s->wmarks.activated)
 			continue;
 
+		if (!quota->esz)
+			continue;
+

[Severity: High]
Does this unconditional check completely skip schemes that do not have quota limits configured?

Quoted 4 lines

For unlimited schemes (schemes without configured quotas), damos_adjust_quota() returns early without calculating esz, leaving quota->esz initialized to 0. With this check, won't unlimited schemes silently fail to apply entirely because the loop unconditionally continues?

Yes, thank you for pointing this out!

So, this check should be
'if (damos_quota_is_set(quota) && !quota->esz)'.

Quoted 8 lines
Quoted 4 lines
mm/damon/core.c +0 -0
 		/* Check the quota */
 		if (damos_quota_is_full(quota, c->min_region_sz))
 			continue;
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1

[1] https://lore.kernel.org/damon/[email protected]

Best regards,
Rui Yan

maintainer
#3 lore raw
In reply to Liew Rui Yan
Quoted 4 lines · On Wed, 2 Sep 2026 16:44:45 +0800 Liew Rui Yan <[email protected]>…

When setting goal_tuner to 'temporal', if the goal is achieved, quota->esz_bp will be set to zero. In this case, damos_quota_is_full() will always return true, even if no regions have been tried to apply at all. This causes qt_exceeds to increase unexpectedly.

To me, this looks logically correct. Could this cause any user issue?

Thanks,
SJ

[...]

#4 lore raw
Quoted 8 lines · On Wed, 02 Sep 2026 07:10:00 -0700 SJ Park <[email protected]> wrote:
Quoted 4 lines · On Wed, 2 Sep 2026 16:44:45 +0800 Liew Rui Yan <[email protected]>…

When setting goal_tuner to 'temporal', if the goal is achieved, quota->esz_bp will be set to zero. In this case, damos_quota_is_full() will always return true, even if no regions have been tried to apply at all. This causes qt_exceeds to increase unexpectedly.

To me, this looks logically correct. Could this cause any user issue?

Yes, I think this might cause unnecessary confusion for users, at least it did for me.

I set quota_ms to 0 and set the target_metric for the quota goal to user_input (i.e., MemAvailable). In my use case, this caused esz_bp to be 0 most of the time. Also, because the quota->ms clamp was missing, esz wasn’t set to min_region_sz, it was actually set to 0.

As a result, nr_tried is 0 (because damos_quota_is_full() in damon_do_apply_scheme() always returns true), but qt_exceeds increments once per second (likely because reset_interval_ms defaults to 1000ms / 1s).

Best regards,
Rui Yan

maintainer
#5 lore raw
Quoted 4 lines · On Wed, 2 Sep 2026 22:22:31 +0800 Liew Rui Yan <[email protected]>…
Quoted 2 lines · On Wed, 02 Sep 2026 07:10:00 -0700 SJ Park <[email protected]> wrote:

On Wed, 2 Sep 2026 16:44:45 +0800 Liew Rui Yan <[email protected]> wrote:

Quoted 8 lines
Quoted 6 lines
Quoted 4 lines

When setting goal_tuner to 'temporal', if the goal is achieved, quota->esz_bp will be set to zero. In this case, damos_quota_is_full() will always return true, even if no regions have been tried to apply at all. This causes qt_exceeds to increase unexpectedly.

To me, this looks logically correct. Could this cause any user issue?

Yes, I think this might cause unnecessary confusion for users,

If it is _might_ kind thing, please ask questions first, or add RFC tag at least.

Quoted 2 lines

at least
it did for me.

If it confused you, definitely we need to fix it. But if it is just confusing, let's try to clarify by adding documentation, rather than changing existing behaviors.

I feel like we also found similar case that people send patches to change some behaviors that confusing them, but not really problematic. That sometimes waste unnecessary time for understanding the intention of the patch. Please feel free to ask question first, if you found some confusing behaviors and don't know why it behaves in the way or if it is a real problem.

Thanks,
SJ

[...]

#6 lore raw
Quoted 18 lines · On Wed, 02 Sep 2026 07:48:03 -0700 SJ Park <[email protected]> wrote:
Quoted 4 lines · On Wed, 2 Sep 2026 22:22:31 +0800 Liew Rui Yan <[email protected]>…
Quoted 2 lines · On Wed, 02 Sep 2026 07:10:00 -0700 SJ Park <[email protected]> wrote:

On Wed, 2 Sep 2026 16:44:45 +0800 Liew Rui Yan <[email protected]> wrote:

Quoted 8 lines
Quoted 6 lines
Quoted 4 lines

When setting goal_tuner to 'temporal', if the goal is achieved, quota->esz_bp will be set to zero. In this case, damos_quota_is_full() will always return true, even if no regions have been tried to apply at all. This causes qt_exceeds to increase unexpectedly.

To me, this looks logically correct. Could this cause any user issue?

Yes, I think this might cause unnecessary confusion for users,

If it is _might_ kind thing, please ask questions first, or add RFC tag at least.

Quoted 6 lines
Quoted 2 lines

at least
it did for me.

If it confused you, definitely we need to fix it. But if it is just confusing, let's try to clarify by adding documentation, rather than changing existing behaviors.

I agree that we should avoid unnecessary code changes if the issue is merely a matter of confusion.

However, I believe a code change is necessary in this specific case, rather than just adding documentation, for the following reasons:

First, this distorts the semantics of qt_exceeds. It is a statistic meant to track actual quota full/overflows. Incrementing qt_exceeds when the quota is completely unused (because the temporal goal is already met) misleads users and could break user-space monitoring tools or scripts that rely on this metric's accuracy.

Second, considering its original behavior when it was first introduced, the recent changes [2] have inadvertently altered this behavior.

When qt_exceeds was first introduced [1], the conditional check was:

    if (quota->esz && quota->charged_sz >= quota->esz)
            s->stat.qt_exceeds++;

Later, to handle cases where 'remaining quota < min_region_sz', damos_quota_is_full() was added [2]. When this function was added, quota->esz was replaced with !damos_quota_is_set(quota).

    static bool damos_quota_is_full(struct damos_quota *quota,
            unsigned long min_region_sz)
    {
        if (!damos_quota_is_set(quota))
            return false;
        if (quota->charged_sz >= quota->esz)
            return true;
        /*
         * DAMOS action is applied per region, so <min_region_sz remaining
         * quota means the quota is effectively full.
         */
        return quota->esz - quota->charged_sz < min_region_sz;
    }

With the introduction of DAMOS_QUOTA_GOAL_TUNER_TEMPORAL [3], quota-> esz == 0 carries two meanings: "unlimited quota" and "should not be applied". This overlap causes the damos_quota_is_full() check to return true incorrectly in the temporal goal scenario, leading to the false positive in the statistic.

Quoted 6 lines

I feel like we also found similar case that people send patches to change some behaviors that confusing them, but not really problematic. That sometimes waste unnecessary time for understanding the intention of the patch. Please feel free to ask question first, if you found some confusing behaviors and don't know why it behaves in the way or if it is a real problem.

I will ask questions on the first in the future when I encounter ambiguous behaviors, to ensure we are aligned on whether it's a real problem before drafting a patch.

[1] 6268eac34ca30 ("mm/damon/schemes: account how many times quota limit has exceeded")

    (Fri Jan 14 14:10:202022 -0800)
[2] c7ec7d5f6b3d1 ("mm/damon/core: handle <min_region_sz remaining quota as empty")
    (Mon Apr 27 18:33:50 2026 -0700)
[3] af738a6a00c1f ("mm/damon/core: introduce DAMOS_QUOTA_GOAL_TUNER_TEMPORAL")
    (Mon Mar 9 18:05:19 2026 -0700)

Best regards,
Rui Yan

maintainer
#7 lore raw
Quoted 30 lines · On Thu, 3 Sep 2026 06:31:38 +0800 Liew Rui Yan <[email protected]>…
Quoted 18 lines · On Wed, 02 Sep 2026 07:48:03 -0700 SJ Park <[email protected]> wrote:
Quoted 4 lines · On Wed, 2 Sep 2026 22:22:31 +0800 Liew Rui Yan <[email protected]>…
Quoted 2 lines · On Wed, 02 Sep 2026 07:10:00 -0700 SJ Park <[email protected]> wrote:

On Wed, 2 Sep 2026 16:44:45 +0800 Liew Rui Yan <[email protected]> wrote:

Quoted 8 lines
Quoted 6 lines
Quoted 4 lines

When setting goal_tuner to 'temporal', if the goal is achieved, quota->esz_bp will be set to zero. In this case, damos_quota_is_full() will always return true, even if no regions have been tried to apply at all. This causes qt_exceeds to increase unexpectedly.

To me, this looks logically correct. Could this cause any user issue?

Yes, I think this might cause unnecessary confusion for users,

If it is _might_ kind thing, please ask questions first, or add RFC tag at least.

Quoted 6 lines
Quoted 2 lines

at least
it did for me.

If it confused you, definitely we need to fix it. But if it is just confusing, let's try to clarify by adding documentation, rather than changing existing behaviors.

I agree that we should avoid unnecessary code changes if the issue is merely a matter of confusion.

Quoted 8 lines

However, I believe a code change is necessary in this specific case, rather than just adding documentation, for the following reasons:

First, this distorts the semantics of qt_exceeds. It is a statistic meant to track actual quota full/overflows. Incrementing qt_exceeds when the quota is completely unused (because the temporal goal is already met) misleads users and could break user-space monitoring tools or scripts that rely on this metric's accuracy.

As I mentioned in the previous comment, this doesn't look wrong to me. I understand some people could think differently. That's why I think this is a matter of clarification, not a bug to fix.

Quoted 4 lines

Second, considering its original behavior when it was first introduced, the recent changes [2] have inadvertently altered this behavior.

Quoted 8 lines

When qt_exceeds was first introduced [1], the conditional check was:

    if (quota->esz && quota->charged_sz >= quota->esz)
            s->stat.qt_exceeds++;

Later, to handle cases where 'remaining quota < min_region_sz', damos_quota_is_full() was added [2]. When this function was added, quota->esz was replaced with !damos_quota_is_set(quota).

I don't find what's wrong with this.

Quoted 15 lines
    static bool damos_quota_is_full(struct damos_quota *quota,
            unsigned long min_region_sz)
    {
        if (!damos_quota_is_set(quota))
            return false;
        if (quota->charged_sz >= quota->esz)
            return true;
        /*
         * DAMOS action is applied per region, so <min_region_sz remaining
         * quota means the quota is effectively full.
         */
        return quota->esz - quota->charged_sz < min_region_sz;
    }
Quoted 3 lines

With the introduction of DAMOS_QUOTA_GOAL_TUNER_TEMPORAL [3], quota-> esz == 0 carries two meanings: "unlimited quota" and "should not be applied".

I don't find how you think this way.

Quoted 3 lines

This overlap causes the damos_quota_is_full() check to return true incorrectly in the temporal goal scenario, leading to the false positive in the statistic.

That still sounds like just a matter of different interpretations. Let me know if I'm missing something.

Quoted 11 lines
Quoted 7 lines

I feel like we also found similar case that people send patches to change some behaviors that confusing them, but not really problematic. That sometimes waste unnecessary time for understanding the intention of the patch. Please feel free to ask question first, if you found some confusing behaviors and don't know why it behaves in the way or if it is a real problem.

I will ask questions on the first in the future when I encounter ambiguous behaviors, to ensure we are aligned on whether it's a real problem before drafting a patch.

Thanks.

Quoted 10 lines

[1] 6268eac34ca30 ("mm/damon/schemes: account how many times quota limit has exceeded")

    (Fri Jan 14 14:10:202022 -0800)
[2] c7ec7d5f6b3d1 ("mm/damon/core: handle <min_region_sz remaining quota as empty")
    (Mon Apr 27 18:33:50 2026 -0700)
[3] af738a6a00c1f ("mm/damon/core: introduce DAMOS_QUOTA_GOAL_TUNER_TEMPORAL")
    (Mon Mar 9 18:05:19 2026 -0700)

Best regards,
Rui Yan

Thanks,
SJ

#8 lore raw
Quoted 79 lines · On Wed, 02 Sep 2026 17:33:50 -0700 SJ Park <[email protected]> wrote:
Quoted 30 lines · On Thu, 3 Sep 2026 06:31:38 +0800 Liew Rui Yan <[email protected]>…
Quoted 18 lines · On Wed, 02 Sep 2026 07:48:03 -0700 SJ Park <[email protected]> wrote:
Quoted 4 lines · On Wed, 2 Sep 2026 22:22:31 +0800 Liew Rui Yan <[email protected]>…
Quoted 2 lines · On Wed, 02 Sep 2026 07:10:00 -0700 SJ Park <[email protected]> wrote:

On Wed, 2 Sep 2026 16:44:45 +0800 Liew Rui Yan <[email protected]> wrote:

Quoted 8 lines
Quoted 6 lines
Quoted 4 lines

When setting goal_tuner to 'temporal', if the goal is achieved, quota->esz_bp will be set to zero. In this case, damos_quota_is_full() will always return true, even if no regions have been tried to apply at all. This causes qt_exceeds to increase unexpectedly.

To me, this looks logically correct. Could this cause any user issue?

Yes, I think this might cause unnecessary confusion for users,

If it is _might_ kind thing, please ask questions first, or add RFC tag at least.

Quoted 6 lines
Quoted 2 lines

at least
it did for me.

If it confused you, definitely we need to fix it. But if it is just confusing, let's try to clarify by adding documentation, rather than changing existing behaviors.

I agree that we should avoid unnecessary code changes if the issue is merely a matter of confusion.

Quoted 8 lines

However, I believe a code change is necessary in this specific case, rather than just adding documentation, for the following reasons:

First, this distorts the semantics of qt_exceeds. It is a statistic meant to track actual quota full/overflows. Incrementing qt_exceeds when the quota is completely unused (because the temporal goal is already met) misleads users and could break user-space monitoring tools or scripts that rely on this metric's accuracy.

As I mentioned in the previous comment, this doesn't look wrong to me. I understand some people could think differently. That's why I think this is a matter of clarification, not a bug to fix.

Quoted 4 lines

Second, considering its original behavior when it was first introduced, the recent changes [2] have inadvertently altered this behavior.

Quoted 8 lines

When qt_exceeds was first introduced [1], the conditional check was:

    if (quota->esz && quota->charged_sz >= quota->esz)
            s->stat.qt_exceeds++;

Later, to handle cases where 'remaining quota < min_region_sz', damos_quota_is_full() was added [2]. When this function was added, quota->esz was replaced with !damos_quota_is_set(quota).

I don't find what's wrong with this.

Quoted 15 lines
    static bool damos_quota_is_full(struct damos_quota *quota,
            unsigned long min_region_sz)
    {
        if (!damos_quota_is_set(quota))
            return false;
        if (quota->charged_sz >= quota->esz)
            return true;
        /*
         * DAMOS action is applied per region, so <min_region_sz remaining
         * quota means the quota is effectively full.
         */
        return quota->esz - quota->charged_sz < min_region_sz;
    }
Quoted 3 lines

With the introduction of DAMOS_QUOTA_GOAL_TUNER_TEMPORAL [3], quota-> esz == 0 carries two meanings: "unlimited quota" and "should not be applied".

Quoted 8 lines

I don't find how you think this way.

Quoted 3 lines

This overlap causes the damos_quota_is_full() check to return true incorrectly in the temporal goal scenario, leading to the false positive in the statistic.

That still sounds like just a matter of different interpretations. Let me know if I'm missing something.

Thank you for keeping this discussion going!

First, I would like to clarify my intention to avoid any misunderstanding. My actual goal is to fix the semantic of the qt_exceeds statistic, rather than necessarily changing the underlying logic of damos_quota_is_full().

Currently, there is an issue with how qt_exceeds is incremented. When the quota is set very small, qt_exceeds increases frequently. This produces a statistical trend that looks almost identical to the continuous increments caused by the Temporal Goal being achieved.

The original intent of introducing qt_exceeds is to let users easily notice if the quota is too small.

Commit Messages [1]:

mm/damon/schemes: account how many times quota limit has exceeded

If the time/space quotas of a given DAMON-based operation scheme is too small, the scheme could show unexpectedly slow progress. However, there is no good way to notice the case in runtime. This commit extends the DAMOS stat to provide how many times the quota limits exceeded so that the users can easily notice the case and tune the scheme.

However, under the current behavior, users are forced to manually ignore or filter out the qt_exceeds increments that occur after the Temporal Goal is achieved. This adds an unnecessary burden to the users and contradicts the core goal of making it "easy" for them to tune the scheme.

If we agree that this adds unnecessary burden, perhaps we could explore a minimal fix at the point where qt_exceeds is incremented, to skip the count when the Temporal Goal is already achieved, without touching damos_quota_is_full().

Please let me know if I'm misunderstanding anything or missing some context!

[...]

Quoted 6 lines
Quoted 6 lines

[1] 6268eac34ca30 ("mm/damon/schemes: account how many times quota limit has exceeded")

    (Fri Jan 14 14:10:202022 -0800)
[2] c7ec7d5f6b3d1 ("mm/damon/core: handle <min_region_sz remaining quota as empty")
    (Mon Apr 27 18:33:50 2026 -0700)
[3] af738a6a00c1f ("mm/damon/core: introduce DAMOS_QUOTA_GOAL_TUNER_TEMPORAL")
    (Mon Mar 9 18:05:19 2026 -0700)

Best regards,
Rui Yan

maintainer
#9 lore raw
Quoted 3 lines · On Thu, 3 Sep 2026 20:41:48 +0800 Liew Rui Yan <[email protected]>…
Quoted 1 line · On Wed, 02 Sep 2026 17:33:50 -0700 SJ Park <[email protected]> wrote:

On Thu, 3 Sep 2026 06:31:38 +0800 Liew Rui Yan <[email protected]> wrote:

[...]

Quoted 23 lines

First, I would like to clarify my intention to avoid any misunderstanding. My actual goal is to fix the semantic of the qt_exceeds statistic, rather than necessarily changing the underlying logic of damos_quota_is_full().

Currently, there is an issue with how qt_exceeds is incremented. When the quota is set very small, qt_exceeds increases frequently. This produces a statistical trend that looks almost identical to the continuous increments caused by the Temporal Goal being achieved.

The original intent of introducing qt_exceeds is to let users easily notice if the quota is too small.

Commit Messages [1]:

mm/damon/schemes: account how many times quota limit has exceeded

If the time/space quotas of a given DAMON-based operation scheme is too small, the scheme could show unexpectedly slow progress. However, there is no good way to notice the case in runtime. This commit extends the DAMOS stat to provide how many times the quota limits exceeded so that the users can easily notice the case and tune the scheme.

Quoted 5 lines

However, under the current behavior, users are forced to manually ignore or filter out the qt_exceeds increments that occur after the Temporal Goal is achieved. This adds an unnecessary burden to the users and contradicts the core goal of making it "easy" for them to tune the scheme.

Still I feel the problem is unclear. Why the users need to manually ignore or filter out the increments under what situation? Knowing specific and detailed case would be helpful. Are you or some people you know doing that and feeling it is too much? If so, what is the real use case? For what purpose and how DAMON is being used? Why and how the ignorance of qt_exceeds is being done and how painful it is?

Thanks,
SJ

[...]

#10 lore raw
Quoted 35 lines · On Thu, 03 Sep 2026 07:05:20 -0700 SJ Park <[email protected]> wrote:
Quoted 3 lines · On Thu, 3 Sep 2026 20:41:48 +0800 Liew Rui Yan <[email protected]>…
Quoted 1 line · On Wed, 02 Sep 2026 17:33:50 -0700 SJ Park <[email protected]> wrote:

On Thu, 3 Sep 2026 06:31:38 +0800 Liew Rui Yan <[email protected]> wrote:

[...]

Quoted 23 lines

First, I would like to clarify my intention to avoid any misunderstanding. My actual goal is to fix the semantic of the qt_exceeds statistic, rather than necessarily changing the underlying logic of damos_quota_is_full().

Currently, there is an issue with how qt_exceeds is incremented. When the quota is set very small, qt_exceeds increases frequently. This produces a statistical trend that looks almost identical to the continuous increments caused by the Temporal Goal being achieved.

The original intent of introducing qt_exceeds is to let users easily notice if the quota is too small.

Commit Messages [1]:

mm/damon/schemes: account how many times quota limit has exceeded

If the time/space quotas of a given DAMON-based operation scheme is too small, the scheme could show unexpectedly slow progress. However, there is no good way to notice the case in runtime. This commit extends the DAMOS stat to provide how many times the quota limits exceeded so that the users can easily notice the case and tune the scheme.

Quoted 5 lines

However, under the current behavior, users are forced to manually ignore or filter out the qt_exceeds increments that occur after the Temporal Goal is achieved. This adds an unnecessary burden to the users and contradicts the core goal of making it "easy" for them to tune the scheme.

Quoted 6 lines

Still I feel the problem is unclear. Why the users need to manually ignore or filter out the increments under what situation? Knowing specific and detailed case would be helpful. Are you or some people you know doing that and feeling it is too much? If so, what is the real use case? For what purpose and how DAMON is being used? Why and how the ignorance of qt_exceeds is being done and how painful it is?

First, I'd like to clarify that this isn't a problem encountered by a real user, it's just a scenario I came up with.

1. Users sample qt_exceeds periodically (e.g., every 10 minutes).

2. Within this 10 minute sampling interval, the counter aggregates both the real quota exhaustions and the increments caused by esz==0.

3. When users notice a high qt_exceeds value, they eventually realize (perhaps by reading the code or documentation) that it includes the counts from the esz==0 state.

4. To get the actual quota exhaustion statistics, the user is now forced to perform additional testing and implement external filtering to separate the esz==0 increments from the real exceeds.

Even if we explicitly state in the documentation that qt_exceeds includes the esz==0 counts, it still burdens the user. The user still has to figure out how to filter out the esz==0 increments externally to get the signal they actually care about.

Honestly, I struggle to imagine any valid use case where a user would actually rely on the qt_exceeds increments caused by esz==0 to make decisions.

If the only purpose of qt_exceeds is to let users "easily notice" if the quota is too small, forcing them to manually filter out the noise defeats that purpose.

Best regards,
Rui Yan

maintainer
#11 lore raw
Quoted 44 lines · On Fri, 4 Sep 2026 16:07:41 +0800 Liew Rui Yan <[email protected]>…
Quoted 35 lines · On Thu, 03 Sep 2026 07:05:20 -0700 SJ Park <[email protected]> wrote:
Quoted 3 lines · On Thu, 3 Sep 2026 20:41:48 +0800 Liew Rui Yan <[email protected]>…
Quoted 1 line · On Wed, 02 Sep 2026 17:33:50 -0700 SJ Park <[email protected]> wrote:

On Thu, 3 Sep 2026 06:31:38 +0800 Liew Rui Yan <[email protected]> wrote:

[...]

Quoted 23 lines

First, I would like to clarify my intention to avoid any misunderstanding. My actual goal is to fix the semantic of the qt_exceeds statistic, rather than necessarily changing the underlying logic of damos_quota_is_full().

Currently, there is an issue with how qt_exceeds is incremented. When the quota is set very small, qt_exceeds increases frequently. This produces a statistical trend that looks almost identical to the continuous increments caused by the Temporal Goal being achieved.

The original intent of introducing qt_exceeds is to let users easily notice if the quota is too small.

Commit Messages [1]:

mm/damon/schemes: account how many times quota limit has exceeded

If the time/space quotas of a given DAMON-based operation scheme is too small, the scheme could show unexpectedly slow progress. However, there is no good way to notice the case in runtime. This commit extends the DAMOS stat to provide how many times the quota limits exceeded so that the users can easily notice the case and tune the scheme.

Quoted 5 lines

However, under the current behavior, users are forced to manually ignore or filter out the qt_exceeds increments that occur after the Temporal Goal is achieved. This adds an unnecessary burden to the users and contradicts the core goal of making it "easy" for them to tune the scheme.

Quoted 6 lines

Still I feel the problem is unclear. Why the users need to manually ignore or filter out the increments under what situation? Knowing specific and detailed case would be helpful. Are you or some people you know doing that and feeling it is too much? If so, what is the real use case? For what purpose and how DAMON is being used? Why and how the ignorance of qt_exceeds is being done and how painful it is?

Quoted 2 lines

First, I'd like to clarify that this isn't a problem encountered by a real user, it's just a scenario I came up with.

Thank you for clarifying this.

Quoted 2 lines

1. Users sample qt_exceeds periodically (e.g., every 10 minutes).

What's the purpose of this sampling?

Quoted 8 lines

2. Within this 10 minute sampling interval, the counter aggregates both the real quota exhaustions and the increments caused by esz==0.

3. When users notice a high qt_exceeds value, they eventually realize (perhaps by reading the code or documentation) that it includes the counts from the esz==0 state.

Quoted 8 lines

4. To get the actual quota exhaustion statistics, the user is now forced to perform additional testing and implement external filtering to separate the esz==0 increments from the real exceeds.

Even if we explicitly state in the documentation that qt_exceeds includes the esz==0 counts, it still burdens the user. The user still has to figure out how to filter out the esz==0 increments externally to get the signal they actually care about.

Users set the temporal goal. They can know when the goal is achieved since most of the goal metrics are already exposed to user space. Users can also show the current effective quotas. I agree that can be cumbersome, but how problematic it is? Also, as I asked above, why they want to do this after all?

Quoted 7 lines

Honestly, I struggle to imagine any valid use case where a user would actually rely on the qt_exceeds increments caused by esz==0 to make decisions.

If the only purpose of qt_exceeds is to let users "easily notice" if the quota is too small,

I agree it could be a signal to show if the quota is too small. But the real purpose of qt_exceeds is, in my opinion, letting users understand how DAMOS is internally working now. After all, how much quota means if it is too small or not? That all depends on the real use case and complicated things including their SLO etc.

If documentation is saying the purpose of qt_exceeds is to show if the quota is too small, that is what need to be updated.

Quoted 2 lines

forcing them to manually filter out the noise
defeats that purpose.

So, I don't agree.

Thanks,
SJ

[...]

#12 lore raw
Quoted 39 lines · On Fri, 04 Sep 2026 07:05:35 -0700 SJ Park <[email protected]> wrote:
Quoted 2 lines · On Fri, 4 Sep 2026 16:07:41 +0800 Liew Rui Yan <[email protected]>…

First, I'd like to clarify that this isn't a problem encountered by a real user, it's just a scenario I came up with.

Thank you for clarifying this.

Quoted 2 lines

1. Users sample qt_exceeds periodically (e.g., every 10 minutes).

What's the purpose of this sampling?

Quoted 8 lines

2. Within this 10 minute sampling interval, the counter aggregates both the real quota exhaustions and the increments caused by esz==0.

3. When users notice a high qt_exceeds value, they eventually realize (perhaps by reading the code or documentation) that it includes the counts from the esz==0 state.

Quoted 8 lines

4. To get the actual quota exhaustion statistics, the user is now forced to perform additional testing and implement external filtering to separate the esz==0 increments from the real exceeds.

Even if we explicitly state in the documentation that qt_exceeds includes the esz==0 counts, it still burdens the user. The user still has to figure out how to filter out the esz==0 increments externally to get the signal they actually care about.

Users set the temporal goal. They can know when the goal is achieved since most of the goal metrics are already exposed to user space. Users can also show the current effective quotas. I agree that can be cumbersome, but how problematic it is? Also, as I asked above, why they want to do this after all?

Quoted 5 lines

Honestly, I struggle to imagine any valid use case where a user would actually rely on the qt_exceeds increments caused by esz==0 to make decisions.

Quoted 8 lines
Quoted 2 lines

If the only purpose of qt_exceeds is to let users "easily notice" if the quota is too small,

I agree it could be a signal to show if the quota is too small. But the real purpose of qt_exceeds is, in my opinion, letting users understand how DAMOS is internally working now. After all, how much quota means if it is too small or not? That all depends on the real use case and complicated things including their SLO etc.

Thank you for your clarify.

Quoted 3 lines

If documentation is saying the purpose of qt_exceeds is to show if the quota is too small, that is what need to be updated.

I completely agree your perspective.

This is the current documentation of qt_exceeds:

- ``qt_exceeds``: Total number of times the quota of the scheme has exceeded.

Although it state the purpose of this statistic, I think adding a note to clarify that this stat also increase when the quota is zero (but not unlimited) would be helpful for users. For example:

Usually, a quota of zero means the DAMOS scheme has an unlimited quota, so qt_exceeds will not increase. However, if user sets a temporal quota goal, the quota is set to zero once the goal is [over]-achieved. In this situation, qt_exceeds will still increase.

I can prepare a formal documentation patch based on this if you agree.

[...]

That said, it's not important for me to add explanations to the document, but may I know why commit [2] changed the behavior which introduced by commit [1]?

Commit [1] Behavior:

    if (quota->esz && quota->changed_sz >= quota->esz)
        s->stat.qt_exceeds++;

Commit [2] Behavior:

    if (damos_quota_is_full(quota, c->min_region_sz))
        s->stat.qt_exceeds++;

Before commit [2], qt_exceeds will only increase when quota->esz is not zero, but after commit [2], qt_exceeds also increase even when quota->esz is zero. I'd love to understand the rationale behind this change to better grasp the design evolution.

[1] 6268eac34ca30 ("mm/damon/schemes: account how many times quota limit has exceeded")

    (Fri Jan 14 14:10:20 2022 -0800)
[2] c7ec7d5f6b3d1 ("mm/damon/core: handle <min_region_sz remaining quota as empty")
    (Mon Apr 27 18:33:50 2026 -0700)

Best regards,
Rui Yan

maintainer
#13 lore raw
Quoted 66 lines · On Fri, 4 Sep 2026 23:35:38 +0800 Liew Rui Yan <[email protected]>…
Quoted 39 lines · On Fri, 04 Sep 2026 07:05:35 -0700 SJ Park <[email protected]> wrote:
Quoted 2 lines · On Fri, 4 Sep 2026 16:07:41 +0800 Liew Rui Yan <[email protected]>…

First, I'd like to clarify that this isn't a problem encountered by a real user, it's just a scenario I came up with.

Thank you for clarifying this.

Quoted 2 lines

1. Users sample qt_exceeds periodically (e.g., every 10 minutes).

What's the purpose of this sampling?

Quoted 8 lines

2. Within this 10 minute sampling interval, the counter aggregates both the real quota exhaustions and the increments caused by esz==0.

3. When users notice a high qt_exceeds value, they eventually realize (perhaps by reading the code or documentation) that it includes the counts from the esz==0 state.

Quoted 8 lines

4. To get the actual quota exhaustion statistics, the user is now forced to perform additional testing and implement external filtering to separate the esz==0 increments from the real exceeds.

Even if we explicitly state in the documentation that qt_exceeds includes the esz==0 counts, it still burdens the user. The user still has to figure out how to filter out the esz==0 increments externally to get the signal they actually care about.

Users set the temporal goal. They can know when the goal is achieved since most of the goal metrics are already exposed to user space. Users can also show the current effective quotas. I agree that can be cumbersome, but how problematic it is? Also, as I asked above, why they want to do this after all?

Quoted 5 lines

Honestly, I struggle to imagine any valid use case where a user would actually rely on the qt_exceeds increments caused by esz==0 to make decisions.

Quoted 8 lines
Quoted 2 lines

If the only purpose of qt_exceeds is to let users "easily notice" if the quota is too small,

I agree it could be a signal to show if the quota is too small. But the real purpose of qt_exceeds is, in my opinion, letting users understand how DAMOS is internally working now. After all, how much quota means if it is too small or not? That all depends on the real use case and complicated things including their SLO etc.

Thank you for your clarify.

Quoted 3 lines

If documentation is saying the purpose of qt_exceeds is to show if the quota is too small, that is what need to be updated.

I completely agree your perspective.

This is the current documentation of qt_exceeds:

- ``qt_exceeds``: Total number of times the quota of the scheme has exceeded.

Although it state the purpose of this statistic, I think adding a note to clarify that this stat also increase when the quota is zero (but not unlimited) would be helpful for users. For example:

Quoted 6 lines

Usually, a quota of zero means the DAMOS scheme has an unlimited quota, so qt_exceeds will not increase. However, if user sets a temporal quota goal, the quota is set to zero once the goal is [over]-achieved. In this situation, qt_exceeds will still increase.

I can prepare a formal documentation patch based on this if you agree.

Yes, I believe this is the right direction. We can discuss further details on the patch. Looking forward to the patch.

Quoted 22 lines

[...]

That said, it's not important for me to add explanations to the document, but may I know why commit [2] changed the behavior which introduced by commit [1]?

Commit [1] Behavior:

    if (quota->esz && quota->changed_sz >= quota->esz)
        s->stat.qt_exceeds++;

Commit [2] Behavior:

    if (damos_quota_is_full(quota, c->min_region_sz))
        s->stat.qt_exceeds++;

Before commit [2], qt_exceeds will only increase when quota->esz is not zero, but after commit [2], qt_exceeds also increase even when quota->esz is zero. I'd love to understand the rationale behind this change to better grasp the design evolution.

Quoted 4 lines

[1] 6268eac34ca30 ("mm/damon/schemes: account how many times quota limit has exceeded")

    (Fri Jan 14 14:10:20 2022 -0800)
[2] c7ec7d5f6b3d1 ("mm/damon/core: handle <min_region_sz remaining quota as empty")
    (Mon Apr 27 18:33:50 2026 -0700)

Seems commit c7ec7d5f6b3d1 didn't make a behavior change that you are describing.

'''

$ git show c7ec7d5f6b3d1
[...]
@@ -2601,8 +2613,7 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s)
        if (!time_in_range_open(jiffies, quota->charged_from,
                                quota->charged_from +
                                msecs_to_jiffies(quota->reset_interval))) {
-               if (damos_quota_is_set(quota) &&
-                               quota->charged_sz >= quota->esz)
+               if (damos_quota_is_full(quota, c->min_region_sz))
                        s->stat.qt_exceeds++;
                quota->total_charged_sz += quota->charged_sz;
                quota->charged_from = jiffies;
'''

And I don't think there was a behavior change. Hopefully commit 54419bbd0ee3 ("mm/damon/core: allow quota goals set zero effective size quota") will give you some clues.

Thanks,
SJ

[...]

#14 lore raw
Quoted 21 lines · On Fri, 04 Sep 2026 17:25:34 -0700 SJ Park <[email protected]> wrote:
Quoted 19 lines · On Fri, 4 Sep 2026 23:35:38 +0800 Liew Rui Yan <[email protected]>…

That said, it's not important for me to add explanations to the document, but may I know why commit [2] changed the behavior which introduced by commit [1]?

Commit [1] Behavior:

    if (quota->esz && quota->changed_sz >= quota->esz)
        s->stat.qt_exceeds++;

Commit [2] Behavior:

    if (damos_quota_is_full(quota, c->min_region_sz))
        s->stat.qt_exceeds++;

Before commit [2], qt_exceeds will only increase when quota->esz is not zero, but after commit [2], qt_exceeds also increase even when quota->esz is zero. I'd love to understand the rationale behind this change to better grasp the design evolution.

Quoted 7 lines
Quoted 4 lines

[1] 6268eac34ca30 ("mm/damon/schemes: account how many times quota limit has exceeded")

    (Fri Jan 14 14:10:20 2022 -0800)
[2] c7ec7d5f6b3d1 ("mm/damon/core: handle <min_region_sz remaining quota as empty")
    (Mon Apr 27 18:33:50 2026 -0700)

Seems commit c7ec7d5f6b3d1 didn't make a behavior change that you are describing.

I actually wanted to point out the behavior difference between commit [1] and [2], but I've understood and agreed with your point.

Quoted 16 lines

'''

$ git show c7ec7d5f6b3d1
[...]
(quoted diff) +1 -2
@@ -2601,8 +2613,7 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s)
        if (!time_in_range_open(jiffies, quota->charged_from,
                                quota->charged_from +
                                msecs_to_jiffies(quota->reset_interval))) {
-               if (damos_quota_is_set(quota) &&
-                               quota->charged_sz >= quota->esz)
+               if (damos_quota_is_full(quota, c->min_region_sz))
                        s->stat.qt_exceeds++;
                quota->total_charged_sz += quota->charged_sz;
                quota->charged_from = jiffies;

'''

Quoted 3 lines

And I don't think there was a behavior change. Hopefully commit 54419bbd0ee3 ("mm/damon/core: allow quota goals set zero effective size quota") will give you some clues.

Thank you very much for your clarifying :>

Now I completely understand why there is different behavior between commit [1] and [2]. Because in commit [1], esz==0 only means quota is unlimited. After commit 54419bbd0ee3, esz==0 also can means do not have quota at all. But the qt_exceeds should just not increase when quota is unlimited, that's why the current implementation is completely correct.

Best regards,
Rui Yan

maintainer
#15 lore raw
Quoted 50 lines · On Sat, 5 Sep 2026 18:36:58 +0800 Liew Rui Yan <[email protected]>…
Quoted 21 lines · On Fri, 04 Sep 2026 17:25:34 -0700 SJ Park <[email protected]> wrote:
Quoted 19 lines · On Fri, 4 Sep 2026 23:35:38 +0800 Liew Rui Yan <[email protected]>…

That said, it's not important for me to add explanations to the document, but may I know why commit [2] changed the behavior which introduced by commit [1]?

Commit [1] Behavior:

    if (quota->esz && quota->changed_sz >= quota->esz)
        s->stat.qt_exceeds++;

Commit [2] Behavior:

    if (damos_quota_is_full(quota, c->min_region_sz))
        s->stat.qt_exceeds++;

Before commit [2], qt_exceeds will only increase when quota->esz is not zero, but after commit [2], qt_exceeds also increase even when quota->esz is zero. I'd love to understand the rationale behind this change to better grasp the design evolution.

Quoted 7 lines
Quoted 4 lines

[1] 6268eac34ca30 ("mm/damon/schemes: account how many times quota limit has exceeded")

    (Fri Jan 14 14:10:20 2022 -0800)
[2] c7ec7d5f6b3d1 ("mm/damon/core: handle <min_region_sz remaining quota as empty")
    (Mon Apr 27 18:33:50 2026 -0700)

Seems commit c7ec7d5f6b3d1 didn't make a behavior change that you are describing.

I actually wanted to point out the behavior difference between commit [1] and [2], but I've understood and agreed with your point.

Quoted 16 lines

'''

$ git show c7ec7d5f6b3d1
[...]
(quoted diff) +1 -2
@@ -2601,8 +2613,7 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s)
        if (!time_in_range_open(jiffies, quota->charged_from,
                                quota->charged_from +
                                msecs_to_jiffies(quota->reset_interval))) {
-               if (damos_quota_is_set(quota) &&
-                               quota->charged_sz >= quota->esz)
+               if (damos_quota_is_full(quota, c->min_region_sz))
                        s->stat.qt_exceeds++;
                quota->total_charged_sz += quota->charged_sz;
                quota->charged_from = jiffies;

'''

Quoted 7 lines
Quoted 3 lines

And I don't think there was a behavior change. Hopefully commit 54419bbd0ee3 ("mm/damon/core: allow quota goals set zero effective size quota") will give you some clues.

Thank you very much for your clarifying :>

Now I completely understand why there is different behavior

I told you I don't think there was a behavior change. I still think so.

Quoted 3 lines

between
commit [1] and [2]. Because in commit [1], esz==0 only means quota is unlimited.

No. Commit 54419bbd0ee3 says "DAMON core assumes zero effective quota means the user has set no quota."

Quoted 2 lines

After commit 54419bbd0ee3, esz==0 also can means do not have quota at all.

That's what the commit is describing the before-commit status...

Quoted 2 lines

But the qt_exceeds should just not increase when quota is unlimited, that's why the current implementation is completely correct.

There is no unlimited quota. Hence I don't understand what you are saying here. Please carefully read the commit message again.

Quoted 3 lines

Best regards,
Rui Yan

Thanks,
SJ

#16 lore raw
Quoted 73 lines · On Sat, 05 Sep 2026 09:12:33 -0700 SJ Park <[email protected]> wrote:
Quoted 50 lines · On Sat, 5 Sep 2026 18:36:58 +0800 Liew Rui Yan <[email protected]>…
Quoted 21 lines · On Fri, 04 Sep 2026 17:25:34 -0700 SJ Park <[email protected]> wrote:
Quoted 19 lines · On Fri, 4 Sep 2026 23:35:38 +0800 Liew Rui Yan <[email protected]>…

That said, it's not important for me to add explanations to the document, but may I know why commit [2] changed the behavior which introduced by commit [1]?

Commit [1] Behavior:

    if (quota->esz && quota->changed_sz >= quota->esz)
        s->stat.qt_exceeds++;

Commit [2] Behavior:

    if (damos_quota_is_full(quota, c->min_region_sz))
        s->stat.qt_exceeds++;

Before commit [2], qt_exceeds will only increase when quota->esz is not zero, but after commit [2], qt_exceeds also increase even when quota->esz is zero. I'd love to understand the rationale behind this change to better grasp the design evolution.

Quoted 7 lines
Quoted 4 lines

[1] 6268eac34ca30 ("mm/damon/schemes: account how many times quota limit has exceeded")

    (Fri Jan 14 14:10:20 2022 -0800)
[2] c7ec7d5f6b3d1 ("mm/damon/core: handle <min_region_sz remaining quota as empty")
    (Mon Apr 27 18:33:50 2026 -0700)

Seems commit c7ec7d5f6b3d1 didn't make a behavior change that you are describing.

I actually wanted to point out the behavior difference between commit [1] and [2], but I've understood and agreed with your point.

Quoted 16 lines

'''

$ git show c7ec7d5f6b3d1
[...]
(quoted diff) +1 -2
@@ -2601,8 +2613,7 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s)
        if (!time_in_range_open(jiffies, quota->charged_from,
                                quota->charged_from +
                                msecs_to_jiffies(quota->reset_interval))) {
-               if (damos_quota_is_set(quota) &&
-                               quota->charged_sz >= quota->esz)
+               if (damos_quota_is_full(quota, c->min_region_sz))
                        s->stat.qt_exceeds++;
                quota->total_charged_sz += quota->charged_sz;
                quota->charged_from = jiffies;

'''

Quoted 7 lines
Quoted 3 lines

And I don't think there was a behavior change. Hopefully commit 54419bbd0ee3 ("mm/damon/core: allow quota goals set zero effective size quota") will give you some clues.

Thank you very much for your clarifying :>

Now I completely understand why there is different behavior

I told you I don't think there was a behavior change. I still think so.

Quoted 3 lines

between
commit [1] and [2]. Because in commit [1], esz==0 only means quota is unlimited.

No. Commit 54419bbd0ee3 says "DAMON core assumes zero effective quota means the user has set no quota."

Quoted 2 lines

After commit 54419bbd0ee3, esz==0 also can means do not have quota at all.

Quoted 7 lines

That's what the commit is describing the before-commit status...

Quoted 2 lines

But the qt_exceeds should just not increase when quota is unlimited, that's why the current implementation is completely correct.

There is no unlimited quota. Hence I don't understand what you are saying here. Please carefully read the commit message again.

Thank you for the detailed explanation, and sorry for my confusing wording. Let me confirm my corrected understanding:

Before commit 54419bbd0ee3, esz == 0 appeared only when the quota was unset, i.e., the user has set no quota. DAMON core therefore assumed zero effective quota means the user has set no quota, and the code checked quota->esz to tell whether a quota is set. Commit 54419bbd0ee3 decoupled "quota is set" from "esz != 0" by introducing damos_quota_is_set(). After that, the temporal goal tuner (af738a6a00c1f) made it possible for a set quota to have esz == 0 as well, for example once its goal is over-achieved. In that case the scheme is intentionally deactivated, and counting qt_exceeds is intended, not a bug.

Commit c7ec7d5f6b3d1 did not change the behavior I asked about; it only refactored the check into damos_quota_is_full().

I will send a documentation patch in the near future. Thank you again for your patience.

Best regards,
Rui Yan

maintainer
#17 lore raw
Quoted 86 lines · On Mon, 7 Sep 2026 06:25:28 +0800 Liew Rui Yan <[email protected]>…
Quoted 73 lines · On Sat, 05 Sep 2026 09:12:33 -0700 SJ Park <[email protected]> wrote:
Quoted 50 lines · On Sat, 5 Sep 2026 18:36:58 +0800 Liew Rui Yan <[email protected]>…
Quoted 21 lines · On Fri, 04 Sep 2026 17:25:34 -0700 SJ Park <[email protected]> wrote:
Quoted 19 lines · On Fri, 4 Sep 2026 23:35:38 +0800 Liew Rui Yan <[email protected]>…

That said, it's not important for me to add explanations to the document, but may I know why commit [2] changed the behavior which introduced by commit [1]?

Commit [1] Behavior:

    if (quota->esz && quota->changed_sz >= quota->esz)
        s->stat.qt_exceeds++;

Commit [2] Behavior:

    if (damos_quota_is_full(quota, c->min_region_sz))
        s->stat.qt_exceeds++;

Before commit [2], qt_exceeds will only increase when quota->esz is not zero, but after commit [2], qt_exceeds also increase even when quota->esz is zero. I'd love to understand the rationale behind this change to better grasp the design evolution.

Quoted 7 lines
Quoted 4 lines

[1] 6268eac34ca30 ("mm/damon/schemes: account how many times quota limit has exceeded")

    (Fri Jan 14 14:10:20 2022 -0800)
[2] c7ec7d5f6b3d1 ("mm/damon/core: handle <min_region_sz remaining quota as empty")
    (Mon Apr 27 18:33:50 2026 -0700)

Seems commit c7ec7d5f6b3d1 didn't make a behavior change that you are describing.

I actually wanted to point out the behavior difference between commit [1] and [2], but I've understood and agreed with your point.

Quoted 16 lines

'''

$ git show c7ec7d5f6b3d1
[...]
(quoted diff) +1 -2
@@ -2601,8 +2613,7 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s)
        if (!time_in_range_open(jiffies, quota->charged_from,
                                quota->charged_from +
                                msecs_to_jiffies(quota->reset_interval))) {
-               if (damos_quota_is_set(quota) &&
-                               quota->charged_sz >= quota->esz)
+               if (damos_quota_is_full(quota, c->min_region_sz))
                        s->stat.qt_exceeds++;
                quota->total_charged_sz += quota->charged_sz;
                quota->charged_from = jiffies;

'''

Quoted 7 lines
Quoted 3 lines

And I don't think there was a behavior change. Hopefully commit 54419bbd0ee3 ("mm/damon/core: allow quota goals set zero effective size quota") will give you some clues.

Thank you very much for your clarifying :>

Now I completely understand why there is different behavior

I told you I don't think there was a behavior change. I still think so.

Quoted 3 lines

between
commit [1] and [2]. Because in commit [1], esz==0 only means quota is unlimited.

No. Commit 54419bbd0ee3 says "DAMON core assumes zero effective quota means the user has set no quota."

Quoted 2 lines

After commit 54419bbd0ee3, esz==0 also can means do not have quota at all.

Quoted 7 lines

That's what the commit is describing the before-commit status...

Quoted 2 lines

But the qt_exceeds should just not increase when quota is unlimited, that's why the current implementation is completely correct.

There is no unlimited quota. Hence I don't understand what you are saying here. Please carefully read the commit message again.

Thank you for the detailed explanation, and sorry for my confusing wording. Let me confirm my corrected understanding:

Quoted 9 lines

Before commit 54419bbd0ee3, esz == 0 appeared only when the quota was unset, i.e., the user has set no quota. DAMON core therefore assumed zero effective quota means the user has set no quota, and the code checked quota->esz to tell whether a quota is set. Commit 54419bbd0ee3 decoupled "quota is set" from "esz != 0" by introducing damos_quota_is_set(). After that, the temporal goal tuner (af738a6a00c1f) made it possible for a set quota to have esz == 0 as well, for example once its goal is over-achieved. In that case the scheme is intentionally deactivated,

From user's perspective, it may look like it is deactivated. Technically speaking, however, it is not deactivated. Everything keeps working in the normal way. Just one difference is that now it has very small (zero) quota.

Quoted 5 lines

and counting qt_exceeds is intended,
not a bug.

Commit c7ec7d5f6b3d1 did not change the behavior I asked about; it only refactored the check into damos_quota_is_full().

Seems you fully understand that now :)

Quoted 3 lines

I will send a documentation patch in the near future. Thank you again for your patience.

Thank you for your patience, too. Looking forward to the patch!

Thanks,
SJ

[...]