All of 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 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.