* [PATCH] mm/damon/ops-common: putback folios on invalid migrate nid
@ 2026-07-23 6:12 dayou5941
2026-07-23 6:24 ` sashiko-bot
2026-07-23 13:46 ` SJ Park
0 siblings, 2 replies; 4+ messages in thread
From: dayou5941 @ 2026-07-23 6:12 UTC (permalink / raw)
To: sj, akpm; +Cc: damon, liyouhong
From: liyouhong <liyouhong@kylinos.cn>
damon_pa_migrate() and damos_va_migrate() isolate folios into a local list
and then call damon_migrate_pages(). When target_nid is invalid (including
the scheme default NUMA_NO_NODE / -1), damon_migrate_pages() returns early
without putting the folios back to the LRU.
Callers then discard the list head while those folios remain isolated with
an extra reference taken by folio_isolate_lru(). The pages stay off the
LRU for as long as the mapping exists (anon active+inactive counts drop
while RSS does not), and the leftover references can pin the pages after
the mapping is gone.
Factor the existing putback loop into damon_putback_folio_list() and use it
on the invalid-nid path as well, so ignored migration requests still return
folios to the LRU.
Fixes: 7e6c3130690a ("mm/damon/ops-common: ignore migration request to invalid nodes")
Signed-off-by: liyouhong <liyouhong@kylinos.cn>
---
mm/damon/ops-common.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
index d1842e2b00ef..9a1e8aec5444 100644
--- a/mm/damon/ops-common.c
+++ b/mm/damon/ops-common.c
@@ -331,12 +331,22 @@ static unsigned int __damon_migrate_folio_list(
return nr_succeeded;
}
+static void damon_putback_folio_list(struct list_head *folio_list)
+{
+ struct folio *folio;
+
+ while (!list_empty(folio_list)) {
+ folio = lru_to_folio(folio_list);
+ list_del(&folio->lru);
+ folio_putback_lru(folio);
+ }
+}
+
static unsigned int damon_migrate_folio_list(struct list_head *folio_list,
struct pglist_data *pgdat,
int target_nid)
{
unsigned int nr_migrated = 0;
- struct folio *folio;
LIST_HEAD(ret_folios);
LIST_HEAD(migrate_folios);
@@ -374,11 +384,7 @@ static unsigned int damon_migrate_folio_list(struct list_head *folio_list,
list_splice(&ret_folios, folio_list);
- while (!list_empty(folio_list)) {
- folio = lru_to_folio(folio_list);
- list_del(&folio->lru);
- folio_putback_lru(folio);
- }
+ damon_putback_folio_list(folio_list);
return nr_migrated;
}
@@ -394,8 +400,10 @@ unsigned long damon_migrate_pages(struct list_head *folio_list, int target_nid)
return nr_migrated;
if (target_nid < 0 || target_nid >= MAX_NUMNODES ||
- !node_state(target_nid, N_MEMORY))
+ !node_state(target_nid, N_MEMORY)) {
+ damon_putback_folio_list(folio_list);
return nr_migrated;
+ }
noreclaim_flag = memalloc_noreclaim_save();
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH] mm/damon/ops-common: putback folios on invalid migrate nid
2026-07-23 6:12 [PATCH] mm/damon/ops-common: putback folios on invalid migrate nid dayou5941
@ 2026-07-23 6:24 ` sashiko-bot
2026-07-23 13:50 ` SJ Park
2026-07-23 13:46 ` SJ Park
1 sibling, 1 reply; 4+ messages in thread
From: sashiko-bot @ 2026-07-23 6:24 UTC (permalink / raw)
To: dayou5941; +Cc: damon
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Incorrect Loop Advancement / Bounds Oversight (PFN advancement bug)
- [High] Missing yield in unbounded list putback loop
--
--- Patch [1]: [PATCH] mm/damon/ops-common: putback folios on invalid migrate nid ---
commit b4aa488aeb8640931363ab9a919f2ae6536d57ba
Author: liyouhong <liyouhong@kylinos.cn>
mm/damon/ops-common: putback folios on invalid migrate nid
This commit extracts the LRU putback logic into a helper function and
uses it to return folios to the LRU when damon_migrate_pages() is called
with an invalid target_nid. This prevents folios from remaining isolated
from the LRU permanently.
> diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
> index e59f77eca83b2..1286fe54b0d9d 100644
> --- a/mm/damon/ops-common.c
> +++ b/mm/damon/ops-common.c
> @@ -330,12 +330,22 @@ static unsigned int __damon_migrate_folio_list(
> return nr_succeeded;
> }
>
> +static void damon_putback_folio_list(struct list_head *folio_list)
> +{
> + struct folio *folio;
> +
> + while (!list_empty(folio_list)) {
> + folio = lru_to_folio(folio_list);
> + list_del(&folio->lru);
> + folio_putback_lru(folio);
> + }
> +}
[Severity: High]
This is a pre-existing issue, but can this tight loop cause CPU soft lockups?
If a DAMON scheme isolates a massive region that fails to migrate, or is
given an invalid migration NID, the isolated folio list could scale to
millions of folios. Because this loop takes the LRU lock for each folio
without a yield point, could it monopolize the CPU and cause severe latency
spikes? Should there be a cond_resched() in this loop?
[ ... ]
[Severity: High]
This is a pre-existing issue, but do these unconditionally sized advancements
elsewhere in the DAMON codebase risk skipping uninspected memory regions?
In mm/damon/paddr.c:damon_pa_pageout():
addr += folio_size(folio);
And similarly in mm/damon/vaddr.c:damos_va_migrate_pmd_entry() and
damos_va_stat_pmd_entry():
nr = folio_nr_pages(folio);
When a DAMON region starts in the middle of a large folio (a tail page), or
a PTE walk encounters a partially mapped large folio, advancing the pointer
by the total folio size or total number of pages overshoots the bounds. Does
this silently skip adjacent, unrelated PTEs and physical addresses?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260723061246.1878435-1-dayou5941@163.com?part=1
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] mm/damon/ops-common: putback folios on invalid migrate nid
2026-07-23 6:24 ` sashiko-bot
@ 2026-07-23 13:50 ` SJ Park
0 siblings, 0 replies; 4+ messages in thread
From: SJ Park @ 2026-07-23 13:50 UTC (permalink / raw)
To: sashiko-bot; +Cc: SJ Park, dayou5941, damon
On Thu, 23 Jul 2026 06:24:27 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] Incorrect Loop Advancement / Bounds Oversight (PFN advancement bug)
> - [High] Missing yield in unbounded list putback loop
> --
>
> --- Patch [1]: [PATCH] mm/damon/ops-common: putback folios on invalid migrate nid ---
> commit b4aa488aeb8640931363ab9a919f2ae6536d57ba
> Author: liyouhong <liyouhong@kylinos.cn>
> mm/damon/ops-common: putback folios on invalid migrate nid
>
> This commit extracts the LRU putback logic into a helper function and
> uses it to return folios to the LRU when damon_migrate_pages() is called
> with an invalid target_nid. This prevents folios from remaining isolated
> from the LRU permanently.
>
> > diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
> > index e59f77eca83b2..1286fe54b0d9d 100644
> > --- a/mm/damon/ops-common.c
> > +++ b/mm/damon/ops-common.c
> > @@ -330,12 +330,22 @@ static unsigned int __damon_migrate_folio_list(
> > return nr_succeeded;
> > }
> >
> > +static void damon_putback_folio_list(struct list_head *folio_list)
> > +{
> > + struct folio *folio;
> > +
> > + while (!list_empty(folio_list)) {
> > + folio = lru_to_folio(folio_list);
> > + list_del(&folio->lru);
> > + folio_putback_lru(folio);
> > + }
> > +}
>
> [Severity: High]
> This is a pre-existing issue, but can this tight loop cause CPU soft lockups?
>
> If a DAMON scheme isolates a massive region that fails to migrate, or is
> given an invalid migration NID, the isolated folio list could scale to
> millions of folios. Because this loop takes the LRU lock for each folio
> without a yield point, could it monopolize the CPU and cause severe latency
> spikes? Should there be a cond_resched() in this loop?
Users could set the maximum size of regions with max_nr_regions parameter. We
could revisit this if it turns out the knob is not really useful, from the real
world.
>
> [ ... ]
>
> [Severity: High]
> This is a pre-existing issue, but do these unconditionally sized advancements
> elsewhere in the DAMON codebase risk skipping uninspected memory regions?
>
> In mm/damon/paddr.c:damon_pa_pageout():
>
> addr += folio_size(folio);
>
> And similarly in mm/damon/vaddr.c:damos_va_migrate_pmd_entry() and
> damos_va_stat_pmd_entry():
>
> nr = folio_nr_pages(folio);
>
> When a DAMON region starts in the middle of a large folio (a tail page), or
> a PTE walk encounters a partially mapped large folio, advancing the pointer
> by the total folio size or total number of pages overshoots the bounds. Does
> this silently skip adjacent, unrelated PTEs and physical addresses?
Known issue. I'm working on this.
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260723061246.1878435-1-dayou5941@163.com?part=1
Thanks,
SJ
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] mm/damon/ops-common: putback folios on invalid migrate nid
2026-07-23 6:12 [PATCH] mm/damon/ops-common: putback folios on invalid migrate nid dayou5941
2026-07-23 6:24 ` sashiko-bot
@ 2026-07-23 13:46 ` SJ Park
1 sibling, 0 replies; 4+ messages in thread
From: SJ Park @ 2026-07-23 13:46 UTC (permalink / raw)
To: dayou5941; +Cc: SJ Park, akpm, damon, liyouhong
On Thu, 23 Jul 2026 14:12:46 +0800 dayou5941@163.com wrote:
> From: liyouhong <liyouhong@kylinos.cn>
>
> damon_pa_migrate() and damos_va_migrate() isolate folios into a local list
> and then call damon_migrate_pages(). When target_nid is invalid (including
> the scheme default NUMA_NO_NODE / -1), damon_migrate_pages() returns early
> without putting the folios back to the LRU.
>
> Callers then discard the list head while those folios remain isolated with
> an extra reference taken by folio_isolate_lru(). The pages stay off the
> LRU for as long as the mapping exists (anon active+inactive counts drop
> while RSS does not), and the leftover references can pin the pages after
> the mapping is gone.
Nice catch!
Sounds like this is a very bad bug. Users can trigger it (though it is
arguably weird or poor setup at least) and the consequence is quote bad:
visible but silent memory exhaustion that cannot be restored without reboot. I
believe this deserves the hot fixes fast track. Let me know if I'm missing
something.
>
> Factor the existing putback loop into damon_putback_folio_list() and use it
> on the invalid-nid path as well, so ignored migration requests still return
> folios to the LRU.
As this is a hotfix, I'd prefer skipping putback loop facotring out part, for
simplicity of backporting.
>
> Fixes: 7e6c3130690a ("mm/damon/ops-common: ignore migration request to invalid nodes")
Let's Cc: stable@.
> Signed-off-by: liyouhong <liyouhong@kylinos.cn>
> ---
> mm/damon/ops-common.c | 22 +++++++++++++++-------
> 1 file changed, 15 insertions(+), 7 deletions(-)
>
> diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
> index d1842e2b00ef..9a1e8aec5444 100644
> --- a/mm/damon/ops-common.c
> +++ b/mm/damon/ops-common.c
> @@ -331,12 +331,22 @@ static unsigned int __damon_migrate_folio_list(
> return nr_succeeded;
> }
>
> +static void damon_putback_folio_list(struct list_head *folio_list)
> +{
> + struct folio *folio;
> +
> + while (!list_empty(folio_list)) {
> + folio = lru_to_folio(folio_list);
> + list_del(&folio->lru);
> + folio_putback_lru(folio);
> + }
> +}
> +
> static unsigned int damon_migrate_folio_list(struct list_head *folio_list,
> struct pglist_data *pgdat,
> int target_nid)
> {
> unsigned int nr_migrated = 0;
> - struct folio *folio;
> LIST_HEAD(ret_folios);
> LIST_HEAD(migrate_folios);
>
> @@ -374,11 +384,7 @@ static unsigned int damon_migrate_folio_list(struct list_head *folio_list,
>
> list_splice(&ret_folios, folio_list);
>
> - while (!list_empty(folio_list)) {
> - folio = lru_to_folio(folio_list);
> - list_del(&folio->lru);
> - folio_putback_lru(folio);
> - }
> + damon_putback_folio_list(folio_list);
I agree this is good cleanup. For simple porting to stable@ series, however,
let's not touch this function.
>
> return nr_migrated;
> }
> @@ -394,8 +400,10 @@ unsigned long damon_migrate_pages(struct list_head *folio_list, int target_nid)
> return nr_migrated;
>
> if (target_nid < 0 || target_nid >= MAX_NUMNODES ||
> - !node_state(target_nid, N_MEMORY))
> + !node_state(target_nid, N_MEMORY)) {
Please keep the original indentation.
> + damon_putback_folio_list(folio_list);
> return nr_migrated;
> + }
Let's open-code the putback here. We could factor out that later.
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-07-23 13:51 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-23 6:12 [PATCH] mm/damon/ops-common: putback folios on invalid migrate nid dayou5941
2026-07-23 6:24 ` sashiko-bot
2026-07-23 13:50 ` SJ Park
2026-07-23 13:46 ` SJ Park
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.