mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/3] mm/damon: fix a minor bug, clean code, and add a test
@ 2026-10-06  6:52 SJ Park
  2026-10-06  6:52 ` [PATCH 1/3] mm/damon/ops-common: fix age_in_sec overflow on 32-bit SJ Park
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: SJ Park @ 2026-10-06  6:52 UTC (permalink / raw)
  To: Andrew Morton
  Cc: SJ Park, Brendan Higgins, David Gow, Gregory Price, damon,
	kunit-dev, linux-kernel, linux-kselftest, linux-mm

Patch 1 from Jaeyeon Lee fixes a minor overflow issue in DAMOS.  Patch 2
from Gregory Price (Meta) cleans up the code for handling of hugetlb
pages.  Patch 3 from Liew Rui Yan adds a kunit test for a recently fixed
bug.

Note to Andrew.  This is a batched reposting of DAMON patches that I
reviewed and asking for merge into mm.git.  Since there are only two
weeks before the expected opening of the next merge window, this will be
the last mm.git merge requesting unurgent DAMON reposting until the next
rc1.

Gregory Price (1):
  mm/damon: use damon_get_monitor_folio() for hugetlb entries

Jaeyeon Lee (1):
  mm/damon/ops-common: fix age_in_sec overflow on 32-bit

Liew Rui Yan (1):
  mm/damon/tests/core-kunit: add test for unconditionally skipping the
    last region

 mm/damon/ops-common.c       | 11 ++++++----
 mm/damon/tests/core-kunit.h | 42 +++++++++++++++++++++++++++++++++++++
 mm/damon/vaddr.c            | 10 +++++----
 3 files changed, 55 insertions(+), 8 deletions(-)


base-commit: 1b1d9187f46db1efb64533dab8b8d5f4f2af0eb5
-- 
2.47.3

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] mm/damon/ops-common: fix age_in_sec overflow on 32-bit
  2026-10-06  6:52 [PATCH 0/3] mm/damon: fix a minor bug, clean code, and add a test SJ Park
@ 2026-10-06  6:52 ` SJ Park
  2026-10-06  6:52 ` [PATCH 2/3] mm/damon: use damon_get_monitor_folio() for hugetlb entries SJ Park
  2026-10-06  6:52 ` [PATCH 3/3] mm/damon/tests/core-kunit: add test for unconditionally skipping the last region SJ Park
  2 siblings, 0 replies; 4+ messages in thread
From: SJ Park @ 2026-10-06  6:52 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Jaeyeon Lee, SJ Park, damon, linux-kernel, linux-mm

From: Jaeyeon Lee <jaeyeon.lee.dev@gmail.com>

damon_hot_score() calculates the age of a region by multiplying r->age
and the aggregation interval.  On 32-bit architectures, unsigned long
is 32 bits, so the multiplication overflows once the age exceeds about
4295 seconds.  Then old regions are scored as if they were young.

Fix it by doing the calculation in 64-bit arithmetic using div_u64().
Also make age_in_sec u64, so the result is not truncated back to 32
bits.

The issue was discovered [1] by Sashiko.

[1] https://lore.kernel.org/20260623011652.1354-1-sj@kernel.org

Fixes: 198f0f4c58b9 ("mm/damon/vaddr,paddr: support pageout prioritization")
Cc: Andrew Morton <akpm@linux-foundation.org>
Assisted-by: LLM
Signed-off-by: Jaeyeon Lee <jaeyeon.lee.dev@gmail.com>
Reviewed-by: SJ Park <sj@kernel.org>
Signed-off-by: SJ Park <sj@kernel.org>
---
Changes from v1
- v1: https://lore.kernel.org/20260930115812.138864-1-jaeyeon.lee.dev@gmail.com
- Collect R-b: from SJ.
- Rebase to the latest mm-new.

 mm/damon/ops-common.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
index 77366f42b3e5..7a7429359dc8 100644
--- a/mm/damon/ops-common.c
+++ b/mm/damon/ops-common.c
@@ -164,7 +164,7 @@ int damon_hot_score(struct damon_ctx *c, struct damon_region *r,
 			struct damos *s)
 {
 	int freq_subscore;
-	unsigned int age_in_sec;
+	u64 age_in_sec;
 	int age_in_log, age_subscore;
 	unsigned int freq_weight = s->quota.weight_nr_accesses;
 	unsigned int age_weight = s->quota.weight_age;
@@ -174,7 +174,8 @@ int damon_hot_score(struct damon_ctx *c, struct damon_region *r,
 			DAMON_MAX_SUBSCORE,
 			damon_nr_samples_per_aggr(&c->attrs));
 
-	age_in_sec = (unsigned long)r->age * c->attrs.aggr_interval / 1000000;
+	age_in_sec = div_u64((u64)r->age * c->attrs.aggr_interval,
+			     USEC_PER_SEC);
 	if (age_in_sec)
 		age_in_log = min_t(int, ilog2(age_in_sec) + 1,
 				DAMON_MAX_AGE_IN_LOG);
-- 
2.47.3

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 2/3] mm/damon: use damon_get_monitor_folio() for hugetlb entries
  2026-10-06  6:52 [PATCH 0/3] mm/damon: fix a minor bug, clean code, and add a test SJ Park
  2026-10-06  6:52 ` [PATCH 1/3] mm/damon/ops-common: fix age_in_sec overflow on 32-bit SJ Park
@ 2026-10-06  6:52 ` SJ Park
  2026-10-06  6:52 ` [PATCH 3/3] mm/damon/tests/core-kunit: add test for unconditionally skipping the last region SJ Park
  2 siblings, 0 replies; 4+ messages in thread
From: SJ Park @ 2026-10-06  6:52 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Gregory Price, SJ Park, damon, linux-kernel, linux-mm

From: Gregory Price <gourry@gourry.net>

Hugetlb folio acquisition is open-coded in three places:
  - damon_hugetlb_mkold()
  - damon_young_hugetlb_entry()
  - damon_va_probe_hugetlb_entry()

DAMON already has damon_get_monitor_folio(), which paddr uses to
get monitored LRU and hugetlb folios and to filter them through
damon_folio_acceptable().  These paths bypass that check.

Use that helper in these paths too, so that DAMON acquires hugetlb
folios and applies its acceptance policy in one place.

No functional change intended. All callers reach these paths with a
present hugetlb PTE under the page table lock, so the folio is always
a mapped hugetlb folio and the helper always returns it.

Cc: Gregory Price <gourry@gourry.net>
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
Reviewed-by: SJ Park <sj@kernel.org>
Signed-off-by: SJ Park <sj@kernel.org>
---
Changes from v1
- v1: https://lore.kernel.org/20261002140727.701709-1-gourry@gourry.net
- Collect R-b: from SJ.
- Rebase to the latest mm-new.

 mm/damon/ops-common.c |  6 ++++--
 mm/damon/vaddr.c      | 10 ++++++----
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
index 7a7429359dc8..2f3bf86a221b 100644
--- a/mm/damon/ops-common.c
+++ b/mm/damon/ops-common.c
@@ -140,9 +140,11 @@ void damon_hugetlb_mkold(pte_t *pte, struct mm_struct *mm,
 {
 	bool referenced = false;
 	pte_t entry = huge_ptep_get(mm, addr, pte);
-	struct folio *folio = pfn_folio(pte_pfn(entry));
+	struct folio *folio;
 
-	folio_get(folio);
+	folio = damon_get_monitor_folio(pte_pfn(entry));
+	if (!folio)
+		return;
 
 	referenced = damon_hugetlb_ptep_mkold(pte, mm, vma, addr, &entry);
 	if (mmu_notifier_clear_young(mm, addr,
diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
index d5dde97b3cd0..b549496ea8e2 100644
--- a/mm/damon/vaddr.c
+++ b/mm/damon/vaddr.c
@@ -411,8 +411,9 @@ static int damon_young_hugetlb_entry(pte_t *pte, unsigned long hmask,
 	if (!pte_present(entry))
 		goto out;
 
-	folio = pfn_folio(pte_pfn(entry));
-	folio_get(folio);
+	folio = damon_get_monitor_folio(pte_pfn(entry));
+	if (!folio)
+		goto out;
 
 	if (pte_young(entry) || !folio_test_idle(folio) ||
 	    mmu_notifier_test_young(walk->mm, addr))
@@ -660,8 +661,9 @@ static int damon_va_probe_hugetlb_entry(pte_t *pte, unsigned long hmask,
 	if (!pte_present(entry))
 		goto out;
 
-	folio = pfn_folio(pte_pfn(entry));
-	folio_get(folio);
+	folio = damon_get_monitor_folio(pte_pfn(entry));
+	if (!folio)
+		goto out;
 	damon_va_probe_folio(priv->ctx, priv->r, folio, &entry, NULL,
 			walk->vma->vm_mm);
 	folio_put(folio);
-- 
2.47.3

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 3/3] mm/damon/tests/core-kunit: add test for unconditionally skipping the last region
  2026-10-06  6:52 [PATCH 0/3] mm/damon: fix a minor bug, clean code, and add a test SJ Park
  2026-10-06  6:52 ` [PATCH 1/3] mm/damon/ops-common: fix age_in_sec overflow on 32-bit SJ Park
  2026-10-06  6:52 ` [PATCH 2/3] mm/damon: use damon_get_monitor_folio() for hugetlb entries SJ Park
@ 2026-10-06  6:52 ` SJ Park
  2 siblings, 0 replies; 4+ messages in thread
From: SJ Park @ 2026-10-06  6:52 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Liew Rui Yan, Brendan Higgins, David Gow, SJ Park, damon,
	kunit-dev, linux-kernel, linux-kselftest, linux-mm

From: Liew Rui Yan <aethernet65535@gmail.com>

Commit b3723b596b54 ("mm/damon/core: fix unconditionally skip last
region") fixed a minor bug.

Add a KUnit test case to cover this behavior and prevent regressions in
the future.

Signed-off-by: Liew Rui Yan <aethernet65535@gmail.com>
Reviewed-by: SJ Park <sj@kernel.org>
Signed-off-by: SJ Park <sj@kernel.org>
---
Changes from v3
- v3: https://lore.kernel.org/20260927175159.60703-1-aethernet65535@gmail.com
- Collect R-b: from SJ.
- Rebase to the latest mm-new.
Changes from v2:
- v2: https://lore.kernel.org/damon/20260925045350.66595-1-aethernet65535@gmail.com
- Change the commit message, mention the fix rather than the original
  bug.
Changes from v1 RESEND:
- v1 RESEND: https://lore.kernel.org/damon/20260919080453.628679-1-aethernet65535@gmail.com
- Drop braces for single line, as suggested [1] in coding-style.
- Set min_region_sz initial value to power-of-2 value, '1'.
Changes from v1:
- v1: https://lore.kernel.org/damon/20260831113735.3349-1-aethernet65535@gmail.com
- Resend since the dependent patch is merged into mm-new, that would
  help us getting AI review help.

 mm/damon/tests/core-kunit.h | 42 +++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h
index ef146ca2ae8a..3fbb4e4e36fa 100644
--- a/mm/damon/tests/core-kunit.h
+++ b/mm/damon/tests/core-kunit.h
@@ -2439,6 +2439,47 @@ static void damos_test_esz_goal_temporal(struct kunit *test)
 	damon_destroy_ctx(ctx);
 }
 
+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 = 1;
+	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),
@@ -2482,6 +2523,7 @@ static struct kunit_case damon_test_cases[] = {
 	KUNIT_CASE(damon_test_walk_control_obsolete),
 	KUNIT_CASE(damon_test_rand),
 	KUNIT_CASE(damos_test_esz_goal_temporal),
+	KUNIT_CASE(damon_test_last_region_quota_reset),
 	{},
 };
 
-- 
2.47.3

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-06  6:52 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-06  6:52 [PATCH 0/3] mm/damon: fix a minor bug, clean code, and add a test SJ Park
2026-10-06  6:52 ` [PATCH 1/3] mm/damon/ops-common: fix age_in_sec overflow on 32-bit SJ Park
2026-10-06  6:52 ` [PATCH 2/3] mm/damon: use damon_get_monitor_folio() for hugetlb entries SJ Park
2026-10-06  6:52 ` [PATCH 3/3] mm/damon/tests/core-kunit: add test for unconditionally skipping the last region SJ Park

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®