[PATCH 1/2] mm/damon/core: preserve the caller's quota in damon_new_scheme()
From: Karl Mehltretter
Date: Sun Sep 20 2026 - 20:31:22 EST
damon_new_scheme() calls damos_quota_init() on the caller's quota before
copying it to the new scheme. This clears the caller's effective quota,
feedback input and charging state as a side effect.
damon_commit_ctx() first copies the running context into a temporary
context for validating the proposed parameters. When
damon_commit_schemes() creates the temporary schemes, it passes the quota
of each running scheme to damon_new_scheme(). The quota pointer therefore
refers to the running scheme, and damos_quota_init() clears that scheme's
state before it is copied to the temporary scheme. Even an update
rejected with -EINVAL loses the running quota state.
For a size quota, this discards the bytes already charged and allows the
scheme to use a fresh quota before the reset interval has elapsed. For a
goal-driven quota, the consist tuner loses its accumulated input and
restarts from its minimum input. A time quota loses its throughput
estimate and falls back to the initial estimate.
The constructor side effect was introduced by commit 70e0c1d1bf94
("mm/damon/core: factor out 'damos_quota' private fileds initialization").
Commit 60bd24f272d0 ("mm/damon/sysfs: test commit input against realistic
destination"), merged in v6.19, exposed it when
validating sysfs updates against a copy of the running context. Commit
b90408ef1163 ("mm/damon/core: safely validate src on damon_commit_ctx()")
later moved that validation into the core API.
Sashiko reported the same side effect [1] on the RFC of the core API
change.
Copy the quota to the new scheme first, then initialize that copy. Make
damos_quota_init() return void, since its return value is no longer needed.
Fixes: 70e0c1d1bf94 ("mm/damon/core: factor out 'damos_quota' private fileds initialization")
Cc: <stable@xxxxxxxxxxxxxxx> # 6.19.x
Link: https://lore.kernel.org/damon/20260702212143.0CB6D1F00A3D@xxxxxxxxxxxxxxx/ [1]
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@xxxxxxxxx>
---
mm/damon/core.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 2258b72da7a78..e655863d33d9c 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -734,7 +734,7 @@ static bool damos_quota_goals_empty(struct damos_quota *q)
}
/* initialize fields of @quota that normally API users wouldn't set */
-static struct damos_quota *damos_quota_init(struct damos_quota *quota)
+static void damos_quota_init(struct damos_quota *quota)
{
quota->esz = 0;
quota->total_charged_sz = 0;
@@ -744,7 +744,6 @@ static struct damos_quota *damos_quota_init(struct damos_quota *quota)
quota->charge_target_from = NULL;
quota->charge_addr_from = 0;
quota->esz_bp = 0;
- return quota;
}
struct damos *damon_new_scheme(struct damos_access_pattern *pattern,
@@ -776,7 +775,8 @@ struct damos *damon_new_scheme(struct damos_access_pattern *pattern,
scheme->last_applied = NULL;
INIT_LIST_HEAD(&scheme->list);
- scheme->quota = *(damos_quota_init(quota));
+ scheme->quota = *quota;
+ damos_quota_init(&scheme->quota);
/* quota.goals should be separately set by caller */
INIT_LIST_HEAD(&scheme->quota.goals);
--
2.53.0