Commit 50585192bc2e ("mm/damon/schemes: skip already charged targets and regions") introduced a minor issue that causes the last region to be skipped before it is 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. Add a test to prevent this regression in the future. Signed-off-by: Liew Rui Yan --- mm/damon/tests/core-kunit.h | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index 4a536d41cdb2..90b0fda34fba 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -1632,6 +1632,48 @@ static void damon_test_rand(struct kunit *test) } } +static void damon_test_last_region_quota_reset(struct kunit *test) +{ + struct damos s = {0}; + struct damon_target *t; + struct damon_region *r1, *r2; + unsigned long min_region_sz = 10; + bool skipped; + + t = damon_new_target(); + if (!t) { + kunit_skip(test, "target alloc fail"); + } + + r1 = damon_new_region(0, 100); + if (!r1) { + damon_free_target(t); + kunit_skip(test, "region 1 alloc fail"); + } + damon_add_region(r1, t); + + r2 = damon_new_region(100, 200); + if (!r2) { + damon_free_target(t); + kunit_skip(test, "region 2 alloc fail"); + } + damon_add_region(r2, t); + + s.quota.charge_target_from = t; + s.quota.charge_addr_from = r1->ar.end; + + skipped = damos_skip_charged_region(t, r2, &s, min_region_sz); + + /* 'r2' is not processed, it should not skip */ + KUNIT_EXPECT_EQ(test, skipped, false); + + /* 'r2' is last region, it should reset charge_{target,addr}_from */ + KUNIT_EXPECT_PTR_EQ(test, s.quota.charge_target_from, NULL); + KUNIT_EXPECT_EQ(test, s.quota.charge_addr_from, 0); + + damon_free_target(t); +} + static struct kunit_case damon_test_cases[] = { KUNIT_CASE(damon_test_target), KUNIT_CASE(damon_test_regions), @@ -1664,6 +1706,7 @@ static struct kunit_case damon_test_cases[] = { KUNIT_CASE(damon_test_is_last_region), KUNIT_CASE(damon_test_walk_control_obsolete), KUNIT_CASE(damon_test_rand), + KUNIT_CASE(damon_test_last_region_quota_reset), {}, }; -- 2.55.0