Re: [PATCH v3] mm/memory-failure: set PG_hwpoison of a non-hugetlb page under hugetlb_lock

From: Andrew Morton

Date: Fri Nov 06 2026 - 17:39:27 EST


On Fri, 06 Nov 2026 11:09:50 -0500 Mani Tofigh via B4 Relay <devnull+mt4022.columbia.edu@xxxxxxxxxx> wrote:

> From: Mani Tofigh <mt4022@xxxxxxxxxxxx>
>
> memory_failure() checks under hugetlb_lock that the page isn't part of
> a hugetlb folio and sets PG_hwpoison only after dropping the lock. The
> page can become a tail page of a new hugetlb folio in the meantime.
> With hugetlb_free_vmemmap=on its struct page then lives in the tail
> page that all such folios in the zone share, so the flag lands on tail
> pages of every one of them:
>
> Task A (memory_failure) Task B (nr_hugepages write)
> get_huge_page_for_hwpoison()
> /* P not hugetlb */
> alloc_fresh_hugetlb_folio()
> /* P becomes a tail page */
> hugetlb_vmemmap_optimize_folio()
> /* P's struct page now in
> the shared tail page */
> TestSetPageHWPoison(P)
>
> The error on P itself is ignored, while healthy pages of other folios
> stay marked and are never reused once their folio is freed. After
> freeing the pool, /proc/kpageflags shows them as hwpoisoned.
>
> This is the allocation side of the race that commit 32c877191e02
> ("hugetlb: do not clear hugetlb dtor until allocating vmemmap") fixed
> for freeing.
>
> Set the hugetlb flag of a new folio under hugetlb_lock and set
> PG_hwpoison of a non-hugetlb page inside the locked check, so that the
> vmemmap can't be optimized in between. The retry path clears it under
> the same lock, unless the page has become part of a hugetlb folio in
> the meantime and its struct page isn't in the first vmemmap page of the
> folio, which HVO doesn't share. The retry then knows the flag is its
> own. With the fix, no healthy page gets marked anymore.
>
> This bug was identified and confirmed with the help of a deterministic
> hypervisor currently under development. The C reproducer below however
> hits it within about 35s.

Thanks.

So as I understand it, if a single 4k page turns bad at just the right
time, we can mark a lot of healthy 4k pages as bad (hence lost until
reboot) while the bad 4k page remains in use? But that race is very
unlikely?

> Fixes: f41f2ed43ca5 ("mm: hugetlb: free the vmemmap pages associated with each HugeTLB page")
> Cc: stable@xxxxxxxxxxxxxxx

I'm hoping we don't need to backport, because the race is so unlikely,
the consequences aren't world-ending and the backporting story is
messy.

But I don't think I'll get my hope, because the consequences of this
race are worse in older kernels:

In 6.6.162 HVO maps shared tail metadata read-only, so the misplaced
PG_hwpoison write can cause an oops.

Also in 6.6.162 memory_failure() still has a ClearPageHWPoison(p) in
its PageCompound retry block so with HVO enabled and
CONFIG_TRANSPARENT_HUGEPAGE=n, its compound retry can still reach
read-only tail metadata.

Miaohe, wdyt?