Re: [PATCH v8 02/15] memory-failure: Prevent hugetlb freeing during unpoisoning
[email protected] Mon, 3 Aug 2026 23:40:25 -0700
| Newsgroups | gmane.linux.file-systems,gmane.linux.kernel.mm |
|---|---|
| Message-ID | <[email protected]> |
On 7/31/2026 1:07 PM, Matthew Wilcox (Oracle) wrote:
> If we fail to get a reference on the hugetlb folio, then it might be=20
> freed as we operate on it. Prevent the freeing and the attendant races=20
> around manipulation of the raw_hwp list by holding the hugetlb_lock,=20
> which is also held by the hugetlb
>=20
>=20
> If we fail to get a reference on the hugetlb folio, then it might be
> freed as we operate on it. Prevent the freeing and the attendant races
> around manipulation of the raw_hwp list by holding the hugetlb_lock,
> which is also held by the hugetlb code when freeing hugetlb folios.
>=20
> Fixes: ac5fcde0a96a ("mm, hwpoison: make unpoison aware of raw error info=
in hwpoisoned hugepage")
> Signed-off-by: Matthew Wilcox (Oracle) <[email protected]>
> Reviewed-by: Gregory Price (Meta) <[email protected]>
> ---
> include/linux/hugetlb.h | 19 +++++++++++++++++++
> mm/memory-failure.c | 6 +++++-
> 2 files changed, 24 insertions(+), 1 deletion(-)
>=20
> diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
> index 2abaf99321e9..50eab2c23299 100644
> --- a/include/linux/hugetlb.h
> +++ b/include/linux/hugetlb.h
> @@ -110,6 +110,17 @@ extern struct resv_map *resv_map_alloc(void);
> void resv_map_release(struct kref *ref);
> =20
> extern spinlock_t hugetlb_lock;
> +
> +static inline void hugetlb_lock_irq(void)
> +{
> + spin_lock_irq(&hugetlb_lock);
> +}
> +
> +static inline void hugetlb_unlock_irq(void)
> +{
> + spin_unlock_irq(&hugetlb_lock);
> +}
> +
> extern int hugetlb_max_hstate __read_mostly;
> #define for_each_hstate(h) \
> for ((h) =3D hstates; (h) < &hstates[hugetlb_max_hstate]; (h)++)
> @@ -279,6 +290,14 @@ unsigned int arch_hugetlb_cma_order(void);
> =20
> #else /* !CONFIG_HUGETLB_PAGE */
> =20
> +static inline void hugetlb_lock_irq(void)
> +{
> +}
> +
> +static inline void hugetlb_unlock_irq(void)
> +{
> +}
> +
> static inline void hugetlb_dup_vma_private(struct vm_area_struct *vma)
> {
> }
> diff --git a/mm/memory-failure.c b/mm/memory-failure.c
> index 944e6e1d4971..1dd0e7b99bb1 100644
> --- a/mm/memory-failure.c
> +++ b/mm/memory-failure.c
> @@ -2725,13 +2725,17 @@ int unpoison_memory(unsigned long pfn)
> =20
> ghp =3D get_hwpoison_page(p, MF_UNPOISON);
> if (!ghp) {
> + hugetlb_lock_irq();
> if (folio_test_hugetlb(folio)) {
> huge =3D true;
> count =3D folio_free_raw_hwp(folio, false);
> - if (count =3D=3D 0)
> + if (count =3D=3D 0) {
> + hugetlb_unlock_irq();
> goto unlock_mutex;
> + }
> }
> ret =3D folio_test_clear_hwpoison(folio) ? 0 : -EBUSY;
> + hugetlb_unlock_irq();
> } else if (ghp < 0) {
> if (ghp =3D=3D -EHWPOISON) {
> ret =3D put_page_back_buddy(p) ? 0 : -EBUSY;
> --=20
> 2.47.3
>=20
Patch itself looks good, so Reviewed-by: Jane Chu <[email protected]>
That said, there is a pre-existing issue:
folio_free_raw_hwp() should check HPG_raw_hwp_unreliable, and fail the=20
act of unpoison just like what __update_and_free_hugetlb_folio() does -
static void __update_and_free_hugetlb_folio(struct hstate *h,
struct folio *folio)
{
bool clear_flag =3D folio_test_hugetlb_vmemmap_optimized(folio);
if (hstate_is_gigantic_no_runtime(h))
return;
/*
* If we don't know which subpages are hwpoisoned, we can't free
* the hugepage, so it's leaked intentionally.
*/
if (folio_test_hugetlb_raw_hwp_unreliable(folio))
return;
thanks,
-jane