mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 13:14:02 +02:00
mm/damon/core: fix unconditionally skip last region
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.
Link: https://lore.kernel.org/20260908134739.96919-1-sj@kernel.org
Fixes: 50585192bc ("mm/damon/schemes: skip already charged targets and regions")
Signed-off-by: Liew Rui Yan <aethernet65535@gmail.com>
Reviewed-by: SJ Park <sj@kernel.org>
Signed-off-by: SJ Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: <stable@vger.kernel.org> # v5.16.x
This commit is contained in:
parent
39c0ceedd5
commit
b3723b596b
|
|
@ -2342,36 +2342,39 @@ static bool damos_skip_charged_region(struct damon_target *t,
|
|||
{
|
||||
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_region_sz);
|
||||
if (!sz_to_skip) {
|
||||
if (damon_sz_region(r) <= min_region_sz)
|
||||
return true;
|
||||
if (damon_sz_region(r) <= min_region_sz) {
|
||||
skip = true;
|
||||
goto out;
|
||||
}
|
||||
sz_to_skip = min_region_sz;
|
||||
}
|
||||
damon_split_region_at(t, r, sz_to_skip);
|
||||
return true;
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user