Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mm/hugetlb: fix missing migratable flag on same-node hugetlb migration
@ 2026-07-07 11:02 Wupeng Ma
  2026-07-07 20:21 ` Andrew Morton
  0 siblings, 1 reply; 3+ messages in thread
From: Wupeng Ma @ 2026-07-07 11:02 UTC (permalink / raw)
  To: muchun.song, osalvador, david, akpm, baolin.wang
  Cc: mawupeng1, linux-mm, linux-kernel

Commit ba23f58de896 ("mm/migrate: don't call
folio_putback_active_hugetlb() on dst hugetlb folio") moved setting of
the migratable flag and active-list placement from
folio_putback_active_hugetlb(dst) into move_hugetlb_state(), so that
the freshly allocated destination folio is handled where allocation is
known to have succeeded.

Unfortunately, the new code was appended after the existing
temporary-folio block in move_hugetlb_state(), which contains an early
return added earlier by commit 5af1ab1d24e08 ("mm/hugetlb: optimize
the surplus state transfer code in move_hugetlb_state()"):

  if (folio_test_hugetlb_temporary(new_folio)) {
      ...
      if (new_nid == old_nid)
          return;                       <-- skips the new code
      ...
  }

  /* added by ba23f58 */
  folio_set_hugetlb_migratable(new_folio);
  list_move_tail(&new_folio->lru, ...&h->hugepage_activelist);

When the destination folio is temporary (i.e. the hugetlb pool was
exhausted and the migration callback fell back to
alloc_migrate_hugetlb_folio()) and the migration does not cross a
node -- the common case, and always true on a single-NUMA system --
move_hugetlb_state() returns before setting the migratable flag or
adding the new folio to the active list. The destination folio is
then installed in the page table but cannot be isolated afterwards,
since folio_isolate_hugetlb() rejects folios without the migratable
flag; a subsequent soft-offline, hard-offline or memory-hotplug
offline of that folio fails with -EBUSY.

This was reproduced on a single-NUMA arm64 VM: a second
MADV_SOFT_OFFLINE on an already-migrated hugetlb page returned EBUSY
and logged "hugepage isolation failed".

Keep the surplus adjustment, which is the only part that depends on
the node crossing, guarded by `if (new_nid != old_nid)', while making
the migratable flag and active-list placement unconditional. This
preserves the cleanup intent of ba23f58 and closes the early-return
hole.

Fixes: ba23f58de896 ("mm/migrate: don't call folio_putback_active_hugetlb() on dst hugetlb folio")
Signed-off-by: Wupeng Ma <mawupeng1@huawei.com>
---
 mm/hugetlb.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 571212b80835..cafadfdb63c0 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -7211,14 +7211,14 @@ void move_hugetlb_state(struct folio *old_folio, struct folio *new_folio, int re
 		 * There is no need to transfer the per-node surplus state
 		 * when we do not cross the node.
 		 */
-		if (new_nid == old_nid)
-			return;
-		spin_lock_irq(&hugetlb_lock);
-		if (h->surplus_huge_pages_node[old_nid]) {
-			h->surplus_huge_pages_node[old_nid]--;
-			h->surplus_huge_pages_node[new_nid]++;
+		if (new_nid != old_nid) {
+			spin_lock_irq(&hugetlb_lock);
+			if (h->surplus_huge_pages_node[old_nid]) {
+				h->surplus_huge_pages_node[old_nid]--;
+				h->surplus_huge_pages_node[new_nid]++;
+			}
+			spin_unlock_irq(&hugetlb_lock);
 		}
-		spin_unlock_irq(&hugetlb_lock);
 	}
 
 	/*
-- 
2.43.0



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

* Re: [PATCH] mm/hugetlb: fix missing migratable flag on same-node hugetlb migration
  2026-07-07 11:02 [PATCH] mm/hugetlb: fix missing migratable flag on same-node hugetlb migration Wupeng Ma
@ 2026-07-07 20:21 ` Andrew Morton
  2026-07-08  1:14   ` mawupeng
  0 siblings, 1 reply; 3+ messages in thread
From: Andrew Morton @ 2026-07-07 20:21 UTC (permalink / raw)
  To: Wupeng Ma
  Cc: muchun.song, osalvador, david, baolin.wang, linux-mm,
	linux-kernel

On Tue, 7 Jul 2026 19:02:54 +0800 Wupeng Ma <mawupeng1@huawei.com> wrote:

> Commit ba23f58de896 ("mm/migrate: don't call
> folio_putback_active_hugetlb() on dst hugetlb folio") moved setting of
> the migratable flag and active-list placement from
> folio_putback_active_hugetlb(dst) into move_hugetlb_state(), so that
> the freshly allocated destination folio is handled where allocation is
> known to have succeeded.
> 
> Unfortunately, the new code was appended after the existing
> temporary-folio block in move_hugetlb_state(), which contains an early
> return added earlier by commit 5af1ab1d24e08 ("mm/hugetlb: optimize
> the surplus state transfer code in move_hugetlb_state()"):
> 
>   if (folio_test_hugetlb_temporary(new_folio)) {
>       ...
>       if (new_nid == old_nid)
>           return;                       <-- skips the new code
>       ...
>   }
> 
>   /* added by ba23f58 */
>   folio_set_hugetlb_migratable(new_folio);
>   list_move_tail(&new_folio->lru, ...&h->hugepage_activelist);
> 
> When the destination folio is temporary (i.e. the hugetlb pool was
> exhausted and the migration callback fell back to
> alloc_migrate_hugetlb_folio()) and the migration does not cross a
> node -- the common case, and always true on a single-NUMA system --
> move_hugetlb_state() returns before setting the migratable flag or
> adding the new folio to the active list. The destination folio is
> then installed in the page table but cannot be isolated afterwards,
> since folio_isolate_hugetlb() rejects folios without the migratable
> flag; a subsequent soft-offline, hard-offline or memory-hotplug
> offline of that folio fails with -EBUSY.
> 
> This was reproduced on a single-NUMA arm64 VM: a second
> MADV_SOFT_OFFLINE on an already-migrated hugetlb page returned EBUSY
> and logged "hugepage isolation failed".
> 
> Keep the surplus adjustment, which is the only part that depends on
> the node crossing, guarded by `if (new_nid != old_nid)', while making
> the migratable flag and active-list placement unconditional. This
> preserves the cleanup intent of ba23f58 and closes the early-return
> hole.

Thanks, I'll queue this for test and review.

> Fixes: ba23f58de896 ("mm/migrate: don't call folio_putback_active_hugetlb() on dst hugetlb folio")

It sounds like we should backport this into -stable kernels?




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

* Re: [PATCH] mm/hugetlb: fix missing migratable flag on same-node hugetlb migration
  2026-07-07 20:21 ` Andrew Morton
@ 2026-07-08  1:14   ` mawupeng
  0 siblings, 0 replies; 3+ messages in thread
From: mawupeng @ 2026-07-08  1:14 UTC (permalink / raw)
  To: akpm
  Cc: mawupeng1, muchun.song, osalvador, david, baolin.wang, linux-mm,
	linux-kernel



On 周三 2026-7-8 04:21, Andrew Morton wrote:
> On Tue, 7 Jul 2026 19:02:54 +0800 Wupeng Ma <mawupeng1@huawei.com> wrote:
> 
>> Commit ba23f58de896 ("mm/migrate: don't call
>> folio_putback_active_hugetlb() on dst hugetlb folio") moved setting of
>> the migratable flag and active-list placement from
>> folio_putback_active_hugetlb(dst) into move_hugetlb_state(), so that
>> the freshly allocated destination folio is handled where allocation is
>> known to have succeeded.
>>
>> Unfortunately, the new code was appended after the existing
>> temporary-folio block in move_hugetlb_state(), which contains an early
>> return added earlier by commit 5af1ab1d24e08 ("mm/hugetlb: optimize
>> the surplus state transfer code in move_hugetlb_state()"):
>>
>>   if (folio_test_hugetlb_temporary(new_folio)) {
>>       ...
>>       if (new_nid == old_nid)
>>           return;                       <-- skips the new code
>>       ...
>>   }
>>
>>   /* added by ba23f58 */
>>   folio_set_hugetlb_migratable(new_folio);
>>   list_move_tail(&new_folio->lru, ...&h->hugepage_activelist);
>>
>> When the destination folio is temporary (i.e. the hugetlb pool was
>> exhausted and the migration callback fell back to
>> alloc_migrate_hugetlb_folio()) and the migration does not cross a
>> node -- the common case, and always true on a single-NUMA system --
>> move_hugetlb_state() returns before setting the migratable flag or
>> adding the new folio to the active list. The destination folio is
>> then installed in the page table but cannot be isolated afterwards,
>> since folio_isolate_hugetlb() rejects folios without the migratable
>> flag; a subsequent soft-offline, hard-offline or memory-hotplug
>> offline of that folio fails with -EBUSY.
>>
>> This was reproduced on a single-NUMA arm64 VM: a second
>> MADV_SOFT_OFFLINE on an already-migrated hugetlb page returned EBUSY
>> and logged "hugepage isolation failed".
>>
>> Keep the surplus adjustment, which is the only part that depends on
>> the node crossing, guarded by `if (new_nid != old_nid)', while making
>> the migratable flag and active-list placement unconditional. This
>> preserves the cleanup intent of ba23f58 and closes the early-return
>> hole.
> 
> Thanks, I'll queue this for test and review.
> 
>> Fixes: ba23f58de896 ("mm/migrate: don't call folio_putback_active_hugetlb() on dst hugetlb folio")
> 
> It sounds like we should backport this into -stable kernels?

Yes, it is precisely because this patch was backported to 6.6 stable that
we discovered this issue.

> 
> 



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

end of thread, other threads:[~2026-07-08  1:14 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-07 11:02 [PATCH] mm/hugetlb: fix missing migratable flag on same-node hugetlb migration Wupeng Ma
2026-07-07 20:21 ` Andrew Morton
2026-07-08  1:14   ` mawupeng

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