Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
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


  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