Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks
@ 2026-10-26  2:57 Yuanhe Shu
  2026-10-26  9:55 ` David Hildenbrand (Arm)
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Yuanhe Shu @ 2026-10-26  2:57 UTC (permalink / raw)
  To: akpm, david
  Cc: Huang, Ying, Kaitao Cheng, vbabka, ljs, liam, rppt, surenb,
	mhocko, linmiaohe, nao.horiguchi, ziy, wangkefeng.wang,
	tujinjiang, mgorman, chengkaitao, muchun.song, linux-mm,
	linux-kernel, xiangzao

Where copy_mc_to_kernel is defined, copy_mc_user_highpage() and
copy_mc_highpage() stop at a hardware error during the copy, report
the not-copied bytes and queue the source page for memory_failure().
The !copy_mc fallbacks return 0 after a plain copy instead.  With
PG_hwpoison set while the data stays readable - software-injected
poison (MADV_HWPOISON, the debugfs corrupt-pfn injector) or a
transient hardware error - there is no fault to recover from: the
copy completes, the destination folio carries no poison marker, and
the poison is consumed silently, the same poison consumption
commit 841a8bfcbad9 ("mm: prevent poison consumption when splitting
THP") refused to risk on the split path.

Check the source folio with folio_contain_hwpoisoned_page() in both
fallbacks and return PAGE_SIZE, the not-copied-bytes convention of
the real copy_mc paths, so the callers take their existing error
paths: the COW and fork paths fail with -EHWPOISON, KSM and
khugepaged abort, and folio_mc_copy() propagates to the migration
core, where this composes with the separate migration-side checks.
On archs with copy_mc this code does not compile.

The check runs after the copy: a check before it would leave open
the window between itself and the copy.  A flag set before or during
the copy is caught, whatever state the data is in.  A late software
injection cannot have corrupted the completed copy, and a synchronous
hardware error takes an arch without copy_mc down at the access; the
residue no flag check, before or after, can catch is corruption whose
hardware report lands after the last check.  Closing that would need
architecture support, as discussed.

The fallbacks do not queue memory_failure() on refusal: the flag is
already set, and memory failure either knows about the page or has
abandoned it.

Suggested-by: "Huang, Ying" <ying.huang@linux.alibaba.com>
Suggested-by: Kaitao Cheng <kaitao.cheng@linux.dev>
Assisted-by: LLM
Signed-off-by: Yuanhe Shu <xiangzao@linux.alibaba.com>
Link: https://lore.kernel.org/r/877bjowf9i.fsf@DESKTOP-5N7EMDA/
---
 include/linux/highmem.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index d7aac9de1c8a..f90f0c6204a4 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -474,12 +474,21 @@ static inline int copy_mc_user_highpage(struct page *to, struct page *from,
 					unsigned long vaddr, struct vm_area_struct *vma)
 {
 	copy_user_highpage(to, from, vaddr, vma);
+	/*
+	 * The flag can be set while the copy runs, so check after it;
+	 * a flag landing later can no longer have corrupted this copy.
+	 */
+	if (folio_contain_hwpoisoned_page(page_folio(from)))
+		return PAGE_SIZE;
 	return 0;
 }
 
 static inline int copy_mc_highpage(struct page *to, struct page *from)
 {
 	copy_highpage(to, from);
+	/* Same reasoning as in copy_mc_user_highpage(). */
+	if (folio_contain_hwpoisoned_page(page_folio(from)))
+		return PAGE_SIZE;
 	return 0;
 }
 #endif
-- 
2.43.7



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

* Re: [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks
  2026-10-26  2:57 [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks Yuanhe Shu
@ 2026-10-26  9:55 ` David Hildenbrand (Arm)
  2026-10-27 12:13   ` Yuanhe Shu
  2026-10-26 11:21 ` Huang, Ying
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26  9:55 UTC (permalink / raw)
  To: Yuanhe Shu, akpm
  Cc: Huang, Ying, Kaitao Cheng, vbabka, ljs, liam, rppt, surenb,
	mhocko, linmiaohe, nao.horiguchi, ziy, wangkefeng.wang,
	tujinjiang, mgorman, chengkaitao, muchun.song, linux-mm,
	linux-kernel

On 10/26/26 03:57, Yuanhe Shu wrote:
> Where copy_mc_to_kernel is defined, copy_mc_user_highpage() and
> copy_mc_highpage() stop at a hardware error during the copy, report
> the not-copied bytes and queue the source page for memory_failure().
> The !copy_mc fallbacks return 0 after a plain copy instead.  With
> PG_hwpoison set while the data stays readable - software-injected
> poison (MADV_HWPOISON, the debugfs corrupt-pfn injector) or a
> transient hardware error - there is no fault to recover from: the
> copy completes, the destination folio carries no poison marker, and
> the poison is consumed silently, the same poison consumption
> commit 841a8bfcbad9 ("mm: prevent poison consumption when splitting
> THP") refused to risk on the split path.
> 
> Check the source folio with folio_contain_hwpoisoned_page() in both
> fallbacks and return PAGE_SIZE, the not-copied-bytes convention of
> the real copy_mc paths, so the callers take their existing error
> paths: the COW and fork paths fail with -EHWPOISON, KSM and
> khugepaged abort, and folio_mc_copy() propagates to the migration
> core, where this composes with the separate migration-side checks.
> On archs with copy_mc this code does not compile.
> 
> The check runs after the copy: a check before it would leave open
> the window between itself and the copy.  A flag set before or during
> the copy is caught, whatever state the data is in.  A late software
> injection cannot have corrupted the completed copy, and a synchronous
> hardware error takes an arch without copy_mc down at the access; the
> residue no flag check, before or after, can catch is corruption whose
> hardware report lands after the last check.  Closing that would need
> architecture support, as discussed.
> 
> The fallbacks do not queue memory_failure() on refusal: the flag is
> already set, and memory failure either knows about the page or has
> abandoned it.

There must be a way to shorten this description.

> 
> Suggested-by: "Huang, Ying" <ying.huang@linux.alibaba.com>
> Suggested-by: Kaitao Cheng <kaitao.cheng@linux.dev>
> Assisted-by: LLM
> Signed-off-by: Yuanhe Shu <xiangzao@linux.alibaba.com>
> Link: https://lore.kernel.org/r/877bjowf9i.fsf@DESKTOP-5N7EMDA/
> ---
>  include/linux/highmem.h | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/include/linux/highmem.h b/include/linux/highmem.h
> index d7aac9de1c8a..f90f0c6204a4 100644
> --- a/include/linux/highmem.h
> +++ b/include/linux/highmem.h
> @@ -474,12 +474,21 @@ static inline int copy_mc_user_highpage(struct page *to, struct page *from,
>  					unsigned long vaddr, struct vm_area_struct *vma)
>  {
>  	copy_user_highpage(to, from, vaddr, vma);
> +	/*
> +	 * The flag can be set while the copy runs, so check after it;
> +	 * a flag landing later can no longer have corrupted this copy.
> +	 */
> +	if (folio_contain_hwpoisoned_page(page_folio(from)))
> +		return PAGE_SIZE;
>  	return 0;
>  }
>  
>  static inline int copy_mc_highpage(struct page *to, struct page *from)
>  {
>  	copy_highpage(to, from);
> +	/* Same reasoning as in copy_mc_user_highpage(). */
> +	if (folio_contain_hwpoisoned_page(page_folio(from)))
> +		return PAGE_SIZE;
>  	return 0;
>  }
>  #endif


As I said in the other thread, how is copying data that was already poisoned
(and might trigger another MCE) reasonable?

I can understand why you would want to maintain the second check (although I do
wonder about memory barriers ... hmmm).

-- 
Cheers,

David


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

* Re: [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks
  2026-10-26  2:57 [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks Yuanhe Shu
  2026-10-26  9:55 ` David Hildenbrand (Arm)
@ 2026-10-26 11:21 ` Huang, Ying
  2026-10-26 12:17   ` Garg, Shivank
                     ` (2 more replies)
  2026-10-26 12:09 ` Garg, Shivank
  2026-10-27  2:57 ` sashiko-bot
  3 siblings, 3 replies; 11+ messages in thread
From: Huang, Ying @ 2026-10-26 11:21 UTC (permalink / raw)
  To: Yuanhe Shu
  Cc: akpm, david, Kaitao Cheng, vbabka, ljs, liam, rppt, surenb,
	mhocko, linmiaohe, nao.horiguchi, ziy, wangkefeng.wang,
	tujinjiang, mgorman, chengkaitao, muchun.song, linux-mm,
	linux-kernel

Yuanhe Shu <xiangzao@linux.alibaba.com> writes:

> Where copy_mc_to_kernel is defined, copy_mc_user_highpage() and
> copy_mc_highpage() stop at a hardware error during the copy, report
> the not-copied bytes and queue the source page for memory_failure().
> The !copy_mc fallbacks return 0 after a plain copy instead.  With
> PG_hwpoison set while the data stays readable - software-injected
> poison (MADV_HWPOISON, the debugfs corrupt-pfn injector) or a
> transient hardware error - there is no fault to recover from: the
> copy completes, the destination folio carries no poison marker, and
> the poison is consumed silently, the same poison consumption
> commit 841a8bfcbad9 ("mm: prevent poison consumption when splitting
> THP") refused to risk on the split path.

As far as I know, software-injected poison is used for debugging only ,
so I don't think it's that important.  Hardware poison state in DDR is
sticky; that is, even a transient hardware error will cause a permanent
hardware poison state until a reset.

Therefore, the primary value of this patch should be to reduce machine
checks (and panics) during memory copies.  If so, we should place the
check code before copying.

> Check the source folio with folio_contain_hwpoisoned_page() in both
> fallbacks and return PAGE_SIZE, the not-copied-bytes convention of
> the real copy_mc paths, so the callers take their existing error
> paths: the COW and fork paths fail with -EHWPOISON, KSM and
> khugepaged abort, and folio_mc_copy() propagates to the migration
> core, where this composes with the separate migration-side checks.
> On archs with copy_mc this code does not compile.
>
> The check runs after the copy: a check before it would leave open
> the window between itself and the copy.  A flag set before or during
> the copy is caught, whatever state the data is in.  A late software
> injection cannot have corrupted the completed copy, and a synchronous
> hardware error takes an arch without copy_mc down at the access; the
> residue no flag check, before or after, can catch is corruption whose
> hardware report lands after the last check.  Closing that would need
> architecture support, as discussed.
>
> The fallbacks do not queue memory_failure() on refusal: the flag is
> already set, and memory failure either knows about the page or has
> abandoned it.
>
> Suggested-by: "Huang, Ying" <ying.huang@linux.alibaba.com>
> Suggested-by: Kaitao Cheng <kaitao.cheng@linux.dev>
> Assisted-by: LLM
> Signed-off-by: Yuanhe Shu <xiangzao@linux.alibaba.com>
> Link: https://lore.kernel.org/r/877bjowf9i.fsf@DESKTOP-5N7EMDA/
> ---
>  include/linux/highmem.h | 9 +++++++++
>  1 file changed, 9 insertions(+)
>
> diff --git a/include/linux/highmem.h b/include/linux/highmem.h
> index d7aac9de1c8a..f90f0c6204a4 100644
> --- a/include/linux/highmem.h
> +++ b/include/linux/highmem.h
> @@ -474,12 +474,21 @@ static inline int copy_mc_user_highpage(struct page *to, struct page *from,
>  					unsigned long vaddr, struct vm_area_struct *vma)
>  {
>  	copy_user_highpage(to, from, vaddr, vma);
> +	/*
> +	 * The flag can be set while the copy runs, so check after it;
> +	 * a flag landing later can no longer have corrupted this copy.
> +	 */
> +	if (folio_contain_hwpoisoned_page(page_folio(from)))
> +		return PAGE_SIZE;

Why not just use PageHWPoison()?

>  	return 0;
>  }
>  
>  static inline int copy_mc_highpage(struct page *to, struct page *from)
>  {
>  	copy_highpage(to, from);
> +	/* Same reasoning as in copy_mc_user_highpage(). */
> +	if (folio_contain_hwpoisoned_page(page_folio(from)))
> +		return PAGE_SIZE;
>  	return 0;
>  }
>  #endif

---
Best Regards,
Huang, Ying


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

* Re: [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks
  2026-10-26  2:57 [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks Yuanhe Shu
  2026-10-26  9:55 ` David Hildenbrand (Arm)
  2026-10-26 11:21 ` Huang, Ying
@ 2026-10-26 12:09 ` Garg, Shivank
  2026-10-27 12:20   ` Yuanhe Shu
  2026-10-27  2:57 ` sashiko-bot
  3 siblings, 1 reply; 11+ messages in thread
From: Garg, Shivank @ 2026-10-26 12:09 UTC (permalink / raw)
  To: david@kernel.org, xiangzao@linux.alibaba.com,
	akpm@linux-foundation.org
  Cc: rppt@kernel.org, wangkefeng.wang@huawei.com,
	chengkaitao@kylinos.cn, vbabka@kernel.org,
	ying.huang@linux.alibaba.com, linux-kernel@vger.kernel.org,
	surenb@google.com, linux-mm@kvack.org, muchun.song@linux.dev,
	ziy@nvidia.com, nao.horiguchi@gmail.com, liam@infradead.org,
	linmiaohe@huawei.com, mhocko@suse.com, ljs@kernel.org,
	tujinjiang@huawei.com, kaitao.cheng@linux.dev,
	mgorman@techsingularity.net

On Mon, 2026-10-26 at 10:57 +0800, Yuanhe Shu wrote:
> Where copy_mc_to_kernel is defined, copy_mc_user_highpage() and
> copy_mc_highpage() stop at a hardware error during the copy, report
> the not-copied bytes and queue the source page for memory_failure().
> The !copy_mc fallbacks return 0 after a plain copy instead.  With
> PG_hwpoison set while the data stays readable - software-injected
> poison (MADV_HWPOISON, the debugfs corrupt-pfn injector) or a
> transient hardware error - there is no fault to recover from: the
> copy completes, the destination folio carries no poison marker, and
> the poison is consumed silently, the same poison consumption
> commit 841a8bfcbad9 ("mm: prevent poison consumption when splitting
> THP") refused to risk on the split path.
> 
> Check the source folio with folio_contain_hwpoisoned_page() in both
> fallbacks and return PAGE_SIZE, the not-copied-bytes convention of
> the real copy_mc paths, so the callers take their existing error
> paths: the COW and fork paths fail with -EHWPOISON, KSM and
> khugepaged abort, and folio_mc_copy() propagates to the migration
> core, where this composes with the separate migration-side checks.
> On archs with copy_mc this code does not compile.
> 
> The check runs after the copy: a check before it would leave open
> the window between itself and the copy.  A flag set before or during
> the copy is caught, whatever state the data is in.  A late software
> injection cannot have corrupted the completed copy, and a synchronous
> hardware error takes an arch without copy_mc down at the access; the
> residue no flag check, before or after, can catch is corruption whose
> hardware report lands after the last check.  Closing that would need
> architecture support, as discussed.
> 
> The fallbacks do not queue memory_failure() on refusal: the flag is
> already set, and memory failure either knows about the page or has
> abandoned it.
> 
> Suggested-by: "Huang, Ying" <ying.huang@linux.alibaba.com>
> Suggested-by: Kaitao Cheng <kaitao.cheng@linux.dev>
> Assisted-by: LLM
> Signed-off-by: Yuanhe Shu <xiangzao@linux.alibaba.com>
> Link: https://lore.kernel.org/r/877bjowf9i.fsf@DESKTOP-5N7EMDA/
> ---
>  include/linux/highmem.h | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/include/linux/highmem.h b/include/linux/highmem.h
> index d7aac9de1c8a..f90f0c6204a4 100644
> --- a/include/linux/highmem.h
> +++ b/include/linux/highmem.h
> @@ -474,12 +474,21 @@ static inline int copy_mc_user_highpage(struct page *to, struct page *from,
>  					unsigned long vaddr, struct vm_area_struct *vma)
>  {
>  	copy_user_highpage(to, from, vaddr, vma);
> +	/*
> +	 * The flag can be set while the copy runs, so check after it;
> +	 * a flag landing later can no longer have corrupted this copy.
> +	 */
> +	if (folio_contain_hwpoisoned_page(page_folio(from)))
> +		return PAGE_SIZE;
>  	return 0;
>  }
>  
>  static inline int copy_mc_highpage(struct page *to, struct page *from)
>  {
>  	copy_highpage(to, from);
> +	/* Same reasoning as in copy_mc_user_highpage(). */
> +	if (folio_contain_hwpoisoned_page(page_folio(from)))
> +		return PAGE_SIZE;
>  	return 0;
>  }
>  #endif

Should we use is_page_hwpoison() instead? It looks simpler and more
reliable. memory_failure() sets the page flag first and the folio flag
later, so there is a race when folio check can say "okay" but page flag
check says "poisoned".

Thanks,
Shivank

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

* Re: [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks
  2026-10-26 11:21 ` Huang, Ying
@ 2026-10-26 12:17   ` Garg, Shivank
  2026-10-27  1:33     ` Huang, Ying
  2026-10-27  1:40   ` Huang, Ying
  2026-10-27 12:14   ` Yuanhe Shu
  2 siblings, 1 reply; 11+ messages in thread
From: Garg, Shivank @ 2026-10-26 12:17 UTC (permalink / raw)
  To: xiangzao@linux.alibaba.com, ying.huang@linux.alibaba.com
  Cc: rppt@kernel.org, wangkefeng.wang@huawei.com,
	chengkaitao@kylinos.cn, vbabka@kernel.org, david@kernel.org,
	akpm@linux-foundation.org, linux-kernel@vger.kernel.org,
	surenb@google.com, linux-mm@kvack.org, muchun.song@linux.dev,
	ziy@nvidia.com, nao.horiguchi@gmail.com, liam@infradead.org,
	linmiaohe@huawei.com, mhocko@suse.com, kaitao.cheng@linux.dev,
	tujinjiang@huawei.com, mgorman@techsingularity.net,
	ljs@kernel.org

On Mon, 2026-10-26 at 19:21 +0800, Huang, Ying wrote:
> Yuanhe Shu <xiangzao@linux.alibaba.com> writes:
> 
> > Where copy_mc_to_kernel is defined, copy_mc_user_highpage() and
> > copy_mc_highpage() stop at a hardware error during the copy, report
> > the not-copied bytes and queue the source page for memory_failure().
> > The !copy_mc fallbacks return 0 after a plain copy instead.  With
> > PG_hwpoison set while the data stays readable - software-injected
> > poison (MADV_HWPOISON, the debugfs corrupt-pfn injector) or a
> > transient hardware error - there is no fault to recover from: the
> > copy completes, the destination folio carries no poison marker, and
> > the poison is consumed silently, the same poison consumption
> > commit 841a8bfcbad9 ("mm: prevent poison consumption when splitting
> > THP") refused to risk on the split path.
> 
> As far as I know, software-injected poison is used for debugging only ,
> so I don't think it's that important.  Hardware poison state in DDR is
> sticky; that is, even a transient hardware error will cause a permanent
> hardware poison state until a reset.
> 
> Therefore, the primary value of this patch should be to reduce machine
> checks (and panics) during memory copies.  If so, we should place the
> check code before copying.
> 
> > Check the source folio with folio_contain_hwpoisoned_page() in both
> > fallbacks and return PAGE_SIZE, the not-copied-bytes convention of
> > the real copy_mc paths, so the callers take their existing error
> > paths: the COW and fork paths fail with -EHWPOISON, KSM and
> > khugepaged abort, and folio_mc_copy() propagates to the migration
> > core, where this composes with the separate migration-side checks.
> > On archs with copy_mc this code does not compile.
> > 
> > The check runs after the copy: a check before it would leave open
> > the window between itself and the copy.  A flag set before or during
> > the copy is caught, whatever state the data is in.  A late software
> > injection cannot have corrupted the completed copy, and a synchronous
> > hardware error takes an arch without copy_mc down at the access; the
> > residue no flag check, before or after, can catch is corruption whose
> > hardware report lands after the last check.  Closing that would need
> > architecture support, as discussed.
> > 
> > The fallbacks do not queue memory_failure() on refusal: the flag is
> > already set, and memory failure either knows about the page or has
> > abandoned it.
> > 
> > Suggested-by: "Huang, Ying" <ying.huang@linux.alibaba.com>
> > Suggested-by: Kaitao Cheng <kaitao.cheng@linux.dev>
> > Assisted-by: LLM
> > Signed-off-by: Yuanhe Shu <xiangzao@linux.alibaba.com>
> > Link: https://lore.kernel.org/r/877bjowf9i.fsf@DESKTOP-5N7EMDA/
> > ---
> >  include/linux/highmem.h | 9 +++++++++
> >  1 file changed, 9 insertions(+)
> > 
> > diff --git a/include/linux/highmem.h b/include/linux/highmem.h
> > index d7aac9de1c8a..f90f0c6204a4 100644
> > --- a/include/linux/highmem.h
> > +++ b/include/linux/highmem.h
> > @@ -474,12 +474,21 @@ static inline int copy_mc_user_highpage(struct page *to, struct page *from,
> >  					unsigned long vaddr, struct vm_area_struct *vma)
> >  {
> >  	copy_user_highpage(to, from, vaddr, vma);
> > +	/*
> > +	 * The flag can be set while the copy runs, so check after it;
> > +	 * a flag landing later can no longer have corrupted this copy.
> > +	 */
> > +	if (folio_contain_hwpoisoned_page(page_folio(from)))
> > +		return PAGE_SIZE;
> 
> Why not just use PageHWPoison()?

This will miss out on hugetlb folios I think. is_page_hwpoison() is more
appropriate as it covers hugetlb cases as well.

Thanks,
Shivank

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

* Re: [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks
  2026-10-26 12:17   ` Garg, Shivank
@ 2026-10-27  1:33     ` Huang, Ying
  0 siblings, 0 replies; 11+ messages in thread
From: Huang, Ying @ 2026-10-27  1:33 UTC (permalink / raw)
  To: Garg, Shivank
  Cc: xiangzao@linux.alibaba.com, rppt@kernel.org,
	wangkefeng.wang@huawei.com, chengkaitao@kylinos.cn,
	vbabka@kernel.org, david@kernel.org, akpm@linux-foundation.org,
	linux-kernel@vger.kernel.org, surenb@google.com,
	linux-mm@kvack.org, muchun.song@linux.dev, ziy@nvidia.com,
	nao.horiguchi@gmail.com, liam@infradead.org, linmiaohe@huawei.com,
	mhocko@suse.com, kaitao.cheng@linux.dev, tujinjiang@huawei.com,
	mgorman@techsingularity.net, ljs@kernel.org

"Garg, Shivank" <shivankg@amd.com> writes:

> On Mon, 2026-10-26 at 19:21 +0800, Huang, Ying wrote:
>> Yuanhe Shu <xiangzao@linux.alibaba.com> writes:
>> 
>> > Where copy_mc_to_kernel is defined, copy_mc_user_highpage() and
>> > copy_mc_highpage() stop at a hardware error during the copy, report
>> > the not-copied bytes and queue the source page for memory_failure().
>> > The !copy_mc fallbacks return 0 after a plain copy instead.  With
>> > PG_hwpoison set while the data stays readable - software-injected
>> > poison (MADV_HWPOISON, the debugfs corrupt-pfn injector) or a
>> > transient hardware error - there is no fault to recover from: the
>> > copy completes, the destination folio carries no poison marker, and
>> > the poison is consumed silently, the same poison consumption
>> > commit 841a8bfcbad9 ("mm: prevent poison consumption when splitting
>> > THP") refused to risk on the split path.
>> 
>> As far as I know, software-injected poison is used for debugging only ,
>> so I don't think it's that important.  Hardware poison state in DDR is
>> sticky; that is, even a transient hardware error will cause a permanent
>> hardware poison state until a reset.
>> 
>> Therefore, the primary value of this patch should be to reduce machine
>> checks (and panics) during memory copies.  If so, we should place the
>> check code before copying.
>> 
>> > Check the source folio with folio_contain_hwpoisoned_page() in both
>> > fallbacks and return PAGE_SIZE, the not-copied-bytes convention of
>> > the real copy_mc paths, so the callers take their existing error
>> > paths: the COW and fork paths fail with -EHWPOISON, KSM and
>> > khugepaged abort, and folio_mc_copy() propagates to the migration
>> > core, where this composes with the separate migration-side checks.
>> > On archs with copy_mc this code does not compile.
>> > 
>> > The check runs after the copy: a check before it would leave open
>> > the window between itself and the copy.  A flag set before or during
>> > the copy is caught, whatever state the data is in.  A late software
>> > injection cannot have corrupted the completed copy, and a synchronous
>> > hardware error takes an arch without copy_mc down at the access; the
>> > residue no flag check, before or after, can catch is corruption whose
>> > hardware report lands after the last check.  Closing that would need
>> > architecture support, as discussed.
>> > 
>> > The fallbacks do not queue memory_failure() on refusal: the flag is
>> > already set, and memory failure either knows about the page or has
>> > abandoned it.
>> > 
>> > Suggested-by: "Huang, Ying" <ying.huang@linux.alibaba.com>
>> > Suggested-by: Kaitao Cheng <kaitao.cheng@linux.dev>
>> > Assisted-by: LLM
>> > Signed-off-by: Yuanhe Shu <xiangzao@linux.alibaba.com>
>> > Link: https://lore.kernel.org/r/877bjowf9i.fsf@DESKTOP-5N7EMDA/
>> > ---
>> >  include/linux/highmem.h | 9 +++++++++
>> >  1 file changed, 9 insertions(+)
>> > 
>> > diff --git a/include/linux/highmem.h b/include/linux/highmem.h
>> > index d7aac9de1c8a..f90f0c6204a4 100644
>> > --- a/include/linux/highmem.h
>> > +++ b/include/linux/highmem.h
>> > @@ -474,12 +474,21 @@ static inline int copy_mc_user_highpage(struct page *to, struct page *from,
>> >  					unsigned long vaddr, struct vm_area_struct *vma)
>> >  {
>> >  	copy_user_highpage(to, from, vaddr, vma);
>> > +	/*
>> > +	 * The flag can be set while the copy runs, so check after it;
>> > +	 * a flag landing later can no longer have corrupted this copy.
>> > +	 */
>> > +	if (folio_contain_hwpoisoned_page(page_folio(from)))
>> > +		return PAGE_SIZE;
>> 
>> Why not just use PageHWPoison()?
>
> This will miss out on hugetlb folios I think. is_page_hwpoison() is more
> appropriate as it covers hugetlb cases as well.

Yes, that is better.  Thanks for pointing that out.

---
Best Regards,
Huang, Ying


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

* Re: [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks
  2026-10-26 11:21 ` Huang, Ying
  2026-10-26 12:17   ` Garg, Shivank
@ 2026-10-27  1:40   ` Huang, Ying
  2026-10-27 12:14   ` Yuanhe Shu
  2 siblings, 0 replies; 11+ messages in thread
From: Huang, Ying @ 2026-10-27  1:40 UTC (permalink / raw)
  To: Yuanhe Shu
  Cc: akpm, david, Kaitao Cheng, vbabka, ljs, liam, rppt, surenb,
	mhocko, linmiaohe, nao.horiguchi, ziy, wangkefeng.wang,
	tujinjiang, mgorman, chengkaitao, muchun.song, linux-mm,
	linux-kernel

"Huang, Ying" <ying.huang@linux.alibaba.com> writes:

> Yuanhe Shu <xiangzao@linux.alibaba.com> writes:
>
>> Where copy_mc_to_kernel is defined, copy_mc_user_highpage() and
>> copy_mc_highpage() stop at a hardware error during the copy, report
>> the not-copied bytes and queue the source page for memory_failure().
>> The !copy_mc fallbacks return 0 after a plain copy instead.  With
>> PG_hwpoison set while the data stays readable - software-injected
>> poison (MADV_HWPOISON, the debugfs corrupt-pfn injector) or a
>> transient hardware error - there is no fault to recover from: the
>> copy completes, the destination folio carries no poison marker, and
>> the poison is consumed silently, the same poison consumption
>> commit 841a8bfcbad9 ("mm: prevent poison consumption when splitting
>> THP") refused to risk on the split path.
>
> As far as I know, software-injected poison is used for debugging only ,
> so I don't think it's that important.  Hardware poison state in DDR is
> sticky; that is, even a transient hardware error will cause a permanent
> hardware poison state until a reset.
>
> Therefore, the primary value of this patch should be to reduce machine
> checks (and panics) during memory copies.  If so, we should place the
> check code before copying.
>

Another factor to consider is performance; the change shouldn't hurt
performance.  Please do some performance tests and share the results
too.

---
Best Regards,
Huang, Ying


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

* Re: [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks
  2026-10-26  2:57 [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks Yuanhe Shu
                   ` (2 preceding siblings ...)
  2026-10-26 12:09 ` Garg, Shivank
@ 2026-10-27  2:57 ` sashiko-bot
  3 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-10-27  2:57 UTC (permalink / raw)
  To: Yuanhe Shu, akpm, david
  Cc: Huang, Ying, Kaitao Cheng, vbabka, ljs, liam, rppt, surenb,
	mhocko, linmiaohe, nao.horiguchi, ziy, wangkefeng.wang,
	tujinjiang, mgorman, chengkaitao, muchun.song, linux-mm

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] mm/highmem: wrong hwpoison granularity in copy_mc_*_highpage() fallbacks
- [High] mm/highmem: copy_mc_*_highpage() reads poisoned page before flag check
--

commit e960425b93cf423ea993320abfce6ba212a1b8fe
Author: Yuanhe Shu <xiangzao@linux.alibaba.com>

mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks

This commit updates the !copy_mc_to_kernel fallbacks for
copy_mc_user_highpage() and copy_mc_highpage() to check
folio_contain_hwpoisoned_page(page_folio(from)) after copying the page
and return PAGE_SIZE if set.

Link: https://lore.kernel.org/r/877bjowf9i.fsf@DESKTOP-5N7EMDA/

> diff --git a/include/linux/highmem.h b/include/linux/highmem.h
> index d7aac9de1c8a4..f90f0c6204a4e 100644
> --- a/include/linux/highmem.h
> +++ b/include/linux/highmem.h
> @@ -474,12 +474,21 @@ static inline int copy_mc_user_highpage(struct page *to, struct page *from,
>  					unsigned long vaddr, struct vm_area_struct *vma)
>  {
>  	copy_user_highpage(to, from, vaddr, vma);
> +	/*
> +	 * The flag can be set while the copy runs, so check after it;
> +	 * a flag landing later can no longer have corrupted this copy.
> +	 */

[Severity: High]
What happens in copy_mc_user_highpage() and copy_mc_highpage() if the
source page already has PG_hwpoison set from a real hardware memory error
before the copy starts (for example, reported earlier via ACPI APEI GHES, a
patrol scrubber, or a prior user-mode fault where memory_failure() set
PG_hwpoison before locking or unmapping the folio)?

On architectures without copy_mc_to_kernel (such as arm64, riscv, and
loongarch), copy_user_highpage() and copy_highpage() map the page with
kmap_local_page(from) and perform a plain kernel memory read via
copy_user_page() or copy_page() without exception-table recovery for
hardware memory errors.

Callers such as folio_mc_copy(), wp_page_copy() -> __wp_page_copy_user(),
copy_present_page(), collapse_file(), and __collapse_huge_page_copy() rely
on copy_mc_user_highpage() and copy_mc_highpage() to refuse poisoned pages.
If the check only runs after the copy, won't reading an already-poisoned
physical page in kernel mode trigger an unrecoverable kernel-mode fault
(such as an EL1 synchronous external abort on arm64) and panic the kernel
before reaching the post-copy check?

Should both functions check whether the source page is hwpoisoned before
the copy in addition to after the copy?

> +	if (folio_contain_hwpoisoned_page(page_folio(from)))
> +		return PAGE_SIZE;
>  	return 0;
>  }
>  
>  static inline int copy_mc_highpage(struct page *to, struct page *from)
>  {
>  	copy_highpage(to, from);
> +	/* Same reasoning as in copy_mc_user_highpage(). */
> +	if (folio_contain_hwpoisoned_page(page_folio(from)))
> +		return PAGE_SIZE;

[Severity: Critical]
Is folio_contain_hwpoisoned_page(page_folio(from)) the right granularity
for single-page copy helpers like copy_mc_user_highpage() and
copy_mc_highpage()?

In include/linux/page-flags.h:

static inline bool folio_contain_hwpoisoned_page(struct folio *folio)
{
	return folio_test_hwpoison(folio) ||
	    (folio_test_large(folio) && folio_test_has_hwpoisoned(folio));
}

Because FOLIO_PF_ANY is 0, folio_test_hwpoison(folio) only tests
PG_hwpoison on the head page (&folio->page[0]), not on a tail page passed
as from. For any tail page of a large folio,
folio_contain_hwpoisoned_page(page_folio(from)) relies purely on the
folio-wide PG_has_hwpoisoned flag. Doesn't this cause both false negatives
and false positives?

First, for tail pages with PG_hwpoison set where PG_has_hwpoisoned is not
set, folio_contain_hwpoisoned_page(page_folio(from)) returns false and the
poisoned tail page is silently copied:

1. In mm/memory-failure.c:memory_failure(), TestSetPageHWPoison(p) sets
   PG_hwpoison on the target tail page before get_hwpoison_page() and
   folio_lock(folio), while folio_set_has_hwpoisoned(folio) is only called
   after acquiring and releasing folio_lock(folio):

   memory_failure()
       if (TestSetPageHWPoison(p))
           ...
       res = get_hwpoison_page(p, flags);
       ...
       folio_lock(folio);
       ...
       folio_unlock(folio);
       if (folio_test_large(folio)) {
           ...
           folio_set_has_hwpoisoned(folio);

   Callers holding folio_lock on the source folio during the copy -- such
   as migrate_folio() / filemap_migrate_folio() / __migrate_folio() ->
   folio_mc_copy(), do_cow_fault(), collapse_file(), and
   __collapse_huge_page_copy() -- block a concurrent memory_failure() at
   folio_lock(folio) after PageHWPoison(from) is already set on the tail
   page, before folio_set_has_hwpoisoned(folio) can run.

2. If memory_failure() (e.g., via debugfs corrupt-pfn without
   MF_COUNT_INCREASED) hits a tail page while a large folio is isolated
   from the LRU for migration or khugepaged, TestSetPageHWPoison(p) sets
   PG_hwpoison on the tail page, get_hwpoison_page() fails because
   HWPoisonHandlable() returns false for !PageLRU, and memory_failure()
   aborts without ever setting PG_has_hwpoisoned.

3. When CONFIG_TRANSPARENT_HUGEPAGE=n and CONFIG_MEMORY_FAILURE=y,
   folio_test_has_hwpoisoned() is compiled as FOLIO_FLAG_FALSE (always
   false), so poisoned tail pages of large page-cache folios are never
   detected, and mf_dax_kill_procs() sets PageHWPoison(page) on FS-DAX
   subpages without setting PG_has_hwpoisoned.

Second, for a non-hugetlb large folio that has PG_has_hwpoisoned set
because one subpage is poisoned (and could not be split to order 0, e.g.
due to extra references or min_order_for_split(folio) > 0 on a large block
size filesystem), unpoisoned subpages remain PTE-mappable and accessible.
When a single-page copy runs on a healthy subpage of that folio via
do_cow_fault(), wp_page_copy() -> __wp_page_copy_user(), or
copy_present_page() during fork(),
folio_contain_hwpoisoned_page(page_folio(from)) returns true and fails the
operation with VM_FAULT_HWPOISON (SIGBUS) or -EHWPOISON even though the
copied subpage from is not poisoned.

Would using is_page_hwpoison(from) in include/linux/page-flags.h instead of
folio_contain_hwpoisoned_page(page_folio(from)) avoid both problems by
checking PageHWPoison(from) on the specific subpage being copied while
still checking the head page for hugetlb folios?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261026025724.1430747-1-xiangzao@linux.alibaba.com?part=1


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

* Re: [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks
  2026-10-26  9:55 ` David Hildenbrand (Arm)
@ 2026-10-27 12:13   ` Yuanhe Shu
  0 siblings, 0 replies; 11+ messages in thread
From: Yuanhe Shu @ 2026-10-27 12:13 UTC (permalink / raw)
  To: akpm, david
  Cc: Huang, Ying, Kaitao Cheng, vbabka, ljs, liam, rppt, surenb,
	mhocko, linmiaohe, nao.horiguchi, ziy, wangkefeng.wang,
	tujinjiang, mgorman, chengkaitao, muchun.song, linux-mm,
	linux-kernel, xiangzao

On 10/26/26 09:55, David Hildenbrand wrote:
> As I said in the other thread, how is copying data that was already
> poisoned (and might trigger another MCE) reasonable?
>
> (although I do wonder about memory barriers ... hmmm)

Agreed, the next version will shorten it.

On the copy itself: you are right, it is not reasonable.  Huang Ying
suggests the same in his reply - the next version checks before the
copy as well, so data the flag already condemns is not read at all.
The check after the copy stays for the flag that lands while the copy
runs: the data has been read already, the destination folio carries
no marker, and the callers discard it on refusal.

On the memory barriers: PG_hwpoison is set atomically and not
cleared while the page is alive.  An unsynchronized check can only
miss a concurrently set flag.  That is the residual window.  And a
check that sees the flag set is never wrong.

-- 
Yuanhe


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

* Re: [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks
  2026-10-26 11:21 ` Huang, Ying
  2026-10-26 12:17   ` Garg, Shivank
  2026-10-27  1:40   ` Huang, Ying
@ 2026-10-27 12:14   ` Yuanhe Shu
  2 siblings, 0 replies; 11+ messages in thread
From: Yuanhe Shu @ 2026-10-27 12:14 UTC (permalink / raw)
  To: Huang, Ying
  Cc: david, akpm, Kaitao Cheng, vbabka, ljs, liam, rppt, surenb,
	mhocko, linmiaohe, nao.horiguchi, ziy, wangkefeng.wang,
	tujinjiang, mgorman, chengkaitao, muchun.song, linux-mm,
	linux-kernel, xiangzao

On 10/26/26 11:21, Huang, Ying wrote:
> Therefore, the primary value of this patch should be to reduce
> machine checks (and panics) during memory copies.  If so, we
> should place the check code before copying.

On the placement: agreed - the next version checks before the copy as
well, so data the flag already condemns is not read at all.  The
check after the copy stays: a flag landing between the check and the
copy would otherwise be missed, and since the DDR poison state is
sticky, a late flag reliably marks bad data while the destination
folio carries no marker.

On software-injected poison: it was our reproducer, but the state is
not debugfs-only.  Errors reported asynchronously (GHES et al.) set
PG_hwpoison with the data still readable, and a THP whose split fails
is left on the LRU flagged by design.

On the predicate: agreed, the next version checks
is_page_hwpoison(from) before and after the copy.

Performance numbers will follow with the next version.

-- 
Yuanhe


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

* Re: [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks
  2026-10-26 12:09 ` Garg, Shivank
@ 2026-10-27 12:20   ` Yuanhe Shu
  0 siblings, 0 replies; 11+ messages in thread
From: Yuanhe Shu @ 2026-10-27 12:20 UTC (permalink / raw)
  To: Garg, Shivank
  Cc: akpm, david, Huang, Ying, Kaitao Cheng, vbabka, ljs, liam, rppt,
	surenb, mhocko, linmiaohe, nao.horiguchi, ziy, wangkefeng.wang,
	tujinjiang, mgorman, chengkaitao, muchun.song, linux-mm,
	linux-kernel, xiangzao

On 10/26/26 12:10, Garg, Shivank wrote:
> Should we use is_page_hwpoison() instead? It looks simpler and more
> reliable.

Agreed.  The next version checks is_page_hwpoison(from) before
and after the copy, so the race is refused at the first check and a
flag landing during the copy at the second.

-- 
Yuanhe


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

end of thread, other threads:[~2026-10-27 12:21 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-26  2:57 [PATCH] mm/highmem: refuse to copy hwpoisoned folios in the !copy_mc fallbacks Yuanhe Shu
2026-10-26  9:55 ` David Hildenbrand (Arm)
2026-10-27 12:13   ` Yuanhe Shu
2026-10-26 11:21 ` Huang, Ying
2026-10-26 12:17   ` Garg, Shivank
2026-10-27  1:33     ` Huang, Ying
2026-10-27  1:40   ` Huang, Ying
2026-10-27 12:14   ` Yuanhe Shu
2026-10-26 12:09 ` Garg, Shivank
2026-10-27 12:20   ` Yuanhe Shu
2026-10-27  2:57 ` sashiko-bot

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