From: sashiko-bot@kernel.org
To: "Yuanhe Shu" <xiangzao@linux.alibaba.com>, akpm@linux-foundation.org
Cc: david@kernel.org, "Huang, Ying" <ying.huang@linux.alibaba.com>,
"Kaitao Cheng" <kaitao.cheng@linux.dev>,
vbabka@kernel.org, linmiaohe@huawei.com, nao.horiguchi@gmail.com,
ziy@nvidia.com, wangkefeng.wang@huawei.com,
tujinjiang@huawei.com, mgorman@techsingularity.net,
chengkaitao@kylinos.cn, muchun.song@linux.dev,
linux-mm@kvack.org
Subject: Re: [PATCH v2 2/2] mm/migrate: refuse to migrate folios containing hwpoisoned pages
Date: Tue, 27 Oct 2026 02:56:11 +0000 [thread overview]
Message-ID: <sashiko-outbox-186035@kernel.org> (raw)
In-Reply-To: <20261026025552.1427901-3-xiangzao@linux.alibaba.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] mm/migrate: folio_contain_hwpoisoned_page() misses poisoned large folio tails
- [High] mm/migrate: hugetlb -EHWPOISON putback sets HPG_migratable and skips unmap
--
commit acde5bc8e89d5c66775184576ff11220f73371d5
Author: Yuanhe Shu <xiangzao@linux.alibaba.com>
mm/migrate: refuse to migrate folios containing hwpoisoned pages
This patch adds folio_contain_hwpoisoned_page() checks at entry, before copy,
and after copy in the standard and hugetlb folio migration paths so that
folios raced by memory_failure() fail migration with -EHWPOISON instead of
copying corrupted data into a fresh destination folio.
Link: https://lore.kernel.org/r/20260707090136.52904-1-kaitao.cheng@linux.dev/
> diff --git a/mm/migrate.c b/mm/migrate.c
> index 15b45832bcfa7..208a3991ca061 100644
> --- a/mm/migrate.c
> +++ b/mm/migrate.c
[ ... ]
> @@ -881,6 +889,14 @@ static int __migrate_folio(struct address_space *mapping, struct folio *dst,
> if (unlikely(rc))
> return rc;
>
> + /*
> + * Recheck after the copy: an injector can set the flag while the
> + * copy is in progress. The mapping has not been transferred yet,
> + * so failing here is the same unwinding as a copy failure.
> + */
> + if (unlikely(folio_contain_hwpoisoned_page(src)))
> + return -EHWPOISON;
[Severity: High]
Does folio_contain_hwpoisoned_page(src) here (and in migrate_folio_unmap()
and migrate_folio_move() below) catch a race where memory_failure() hits a
tail subpage of an isolated non-hugetlb large folio (THP or mTHP)?
In include/linux/page-flags.h, folio_contain_hwpoisoned_page() only checks
PG_hwpoison on the head page and PG_has_hwpoisoned on the folio:
static inline bool folio_contain_hwpoisoned_page(struct folio *folio)
{
return folio_test_hwpoison(folio) ||
(folio_test_large(folio) && folio_test_has_hwpoisoned(folio));
}
When a large folio src has already been isolated from the LRU by migration
(clearing PG_lru) and memory_failure() runs on a tail page p (p != &src->page),
memory_failure() sets PG_hwpoison on that specific tail page via
TestSetPageHWPoison(p) (which has PF_ANY policy) and then calls
get_hwpoison_page(p, flags) -> get_any_page(p, flags). Because PG_lru is
clear on src, HWPoisonHandlable() returns false, get_hwpoison_page() fails
(even when MF_COUNT_INCREASED is set, after dropping the reference and
retrying), and memory_failure() exits with MF_IGNORED before reaching
folio_set_has_hwpoisoned(folio):
mm/memory-failure.c:memory_failure() {
if (TestSetPageHWPoison(p)) {
...
}
...
res = get_hwpoison_page(p, flags);
switch (res) {
...
default:
res = action_result(pfn, MF_MSG_GET_HWPOISON, MF_IGNORED);
goto unlock_mutex;
}
...
if (folio_test_large(folio)) {
...
folio_set_has_hwpoisoned(folio);
}
Similarly, if get_hwpoison_page() succeeded before PG_lru was cleared or via
debugfs corrupt-pfn while migration already holds folio_lock(src),
memory_failure() blocks on folio_lock(folio) before setting
PG_has_hwpoisoned.
Because neither the head page's PG_hwpoison nor the folio's
PG_has_hwpoisoned is set in this window, all three
folio_contain_hwpoisoned_page(src) checks in migrate_folio_unmap(),
migrate_folio_move(), and __migrate_folio() return false, and folio_mc_copy()
copies each subpage without checking PageHWPoison(folio_page(src, i)). Won't
migration still copy the poisoned tail page into dst without a poison marker
and free src back to the page allocator with PG_hwpoison left set on its tail
page?
[ ... ]
> @@ -1521,6 +1555,12 @@ static int unmap_and_move_hugetlb_folio(new_folio_t get_new_folio,
> goto out_unlock;
> }
>
> + if (unlikely(folio_contain_hwpoisoned_page(src))) {
> + /* Same reasoning as in migrate_folio_unmap(). */
> + rc = -EHWPOISON;
> + goto out_unlock;
> + }
> +
> if (folio_test_anon(src))
> anon_vma = folio_get_anon_vma(src);
>
> @@ -1546,8 +1586,13 @@ static int unmap_and_move_hugetlb_folio(new_folio_t get_new_folio,
> was_mapped = 1;
> }
>
> - if (!folio_mapped(src))
> - rc = move_to_new_folio(dst, src, mode);
> + if (!folio_mapped(src)) {
> + /* Same reasoning as in migrate_folio_move(). */
> + if (unlikely(folio_contain_hwpoisoned_page(src)))
> + rc = -EHWPOISON;
> + else
> + rc = move_to_new_folio(dst, src, mode);
> + }
[Severity: High]
What happens to a hugetlb folio when unmap_and_move_hugetlb_folio() (or
migrate_huge_page_move_mapping()) fails with -EHWPOISON and puts src on the
ret list for putback_movable_pages()?
When src was isolated via folio_isolate_hugetlb(), HPG_migratable was cleared.
If memory_failure() races during isolation (for example without
MF_COUNT_INCREASED via hardware MCE or corrupt-pfn),
try_memory_failure_hugetlb() -> get_huge_page_for_hwpoison() calls
hugetlb_update_hwpoison(src, page), which sets PG_hwpoison on src, and then
returns MF_HUGETLB_RETRY so memory_failure() gives up with MF_IGNORED without
unmapping src.
When unmap_and_move_hugetlb_folio() then returns -EHWPOISON (after restoring
migration PTEs to src if it was mapped), putback_movable_pages() calls
folio_putback_hugetlb(src), which unconditionally sets HPG_migratable back on
the poisoned hugetlb folio:
mm/hugetlb.c:folio_putback_hugetlb() {
spin_lock_irq(&hugetlb_lock);
folio_set_hugetlb_migratable(folio);
list_move_tail(&folio->lru, &(folio_hstate(folio))->hugepage_activelist);
spin_unlock_irq(&hugetlb_lock);
folio_put(folio);
}
Doesn't this cause two problems for hugetlb folios?
First, hugetlb folios are not reclaimed by vmscan, and any later
memory_failure() call on src sees PG_hwpoison already set in
hugetlb_update_hwpoison(), returning MF_HUGETLB_PAGE_PRE_POISONED or
MF_HUGETLB_FOLIO_PRE_POISONED so get_huge_page_for_hwpoison() exits early
with -EHWPOISON without ever unmapping src or clearing HPG_migratable.
Second, get_huge_page_for_hwpoison() explicitly clears HPG_migratable on
hwpoisoned hugepages to prevent memory hotremove from trying to migrate them:
mm/memory-failure.c:get_huge_page_for_hwpoison() {
rc = hugetlb_update_hwpoison(folio, page);
if (rc >= MF_HUGETLB_FOLIO_PRE_POISONED) {
ret = rc;
goto out_unlock;
}
/*
* Clearing hugetlb_migratable for hwpoisoned hugepages to prevent them
* from being migrated by memory hotremove.
*/
if (count_increased && folio_test_hugetlb_migratable(folio)) {
folio_clear_hugetlb_migratable(folio);
*migratable_cleared = true;
}
}
With HPG_migratable re-enabled by folio_putback_hugetlb(src) on a PG_hwpoison
hugetlb folio, won't offline_pages() loop indefinitely because
scan_movable_pages() keeps reporting folio_test_hugetlb_migratable(folio) as
movable while do_migrate_range() skips it due to
folio_contain_hwpoisoned_page(folio) without clearing HPG_migratable?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261026025552.1427901-1-xiangzao@linux.alibaba.com?part=2
next prev parent reply other threads:[~2026-10-27 2:56 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-26 2:55 [PATCH v2 0/2] mm: don't migrate folios containing hwpoisoned pages Yuanhe Shu
2026-10-26 2:55 ` [PATCH v2 1/2] mm/compaction: skip " Yuanhe Shu
2026-10-26 2:55 ` [PATCH v2 2/2] mm/migrate: refuse to migrate " Yuanhe Shu
2026-10-27 2:56 ` sashiko-bot [this message]
2026-10-26 9:56 ` [PATCH v2 0/2] mm: don't " David Hildenbrand (Arm)
2026-10-27 12:08 ` Yuanhe Shu
2026-10-28 9:02 ` David Hildenbrand (Arm)
2026-10-28 12:22 ` Yuanhe Shu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-186035@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=chengkaitao@kylinos.cn \
--cc=david@kernel.org \
--cc=kaitao.cheng@linux.dev \
--cc=linmiaohe@huawei.com \
--cc=linux-mm@kvack.org \
--cc=mgorman@techsingularity.net \
--cc=muchun.song@linux.dev \
--cc=nao.horiguchi@gmail.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=tujinjiang@huawei.com \
--cc=vbabka@kernel.org \
--cc=wangkefeng.wang@huawei.com \
--cc=xiangzao@linux.alibaba.com \
--cc=ying.huang@linux.alibaba.com \
--cc=ziy@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox