From: Miaohe Lin <linmiaohe@huawei.com>
To: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Muchun Song <muchun.song@linux.dev>,
Oscar Salvador <osalvador@suse.de>,
David Hildenbrand <david@kernel.org>,
Naoya Horiguchi <nao.horiguchi@gmail.com>,
Jan Kara <jack@suse.cz>, <linux-fsdevel@vger.kernel.org>,
Christian Brauner <christian@brauner.io>,
Jiaqi Yan <jiaqiyan@google.com>,
"Gregory Price (Meta)" <gourry@gourry.net>,
Andrew Morton <akpm@linux-foundation.org>,
Jane Chu <jane.chu@oracle.com>, <linux-mm@kvack.org>
Subject: Re: [PATCH v9 08/15] hugetlb: Use the has_hwpoisoned flag
Date: Fri, 4 Sep 2026 11:46:07 +0800 [thread overview]
Message-ID: <d30db03b-ffb4-52ce-c922-415ad75661ea@huawei.com> (raw)
In-Reply-To: <20260805210557.1118966-9-willy@infradead.org>
On 2026/8/6 5:05, Matthew Wilcox (Oracle) wrote:
> Other large folios use the has_hwpoisoned flag. Convert hugetlb to match.
> This will help us use the per-page hwpoison flag in the future.
>
> Also introduce a folio_test_huge_poison(). This has exactly the same
> meaning as folio_test_has_hwpoisoned() but can be used when we don't have
> a reference to the folio containing the page. folio_test_has_hwpoisoned()
> can race with folio splitting / reallocation and trip the assertions
> in const_folio_flags().
>
> This closes a gap where a page in a previously-poisoned hugetlb folio
> could be observed to not have the hwpoison bit set.
>
> Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> Reviewed-by: Jane Chu <jane.chu@oracle.com>
> Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
> ---
> fs/Kconfig | 2 +-
> fs/hugetlbfs/inode.c | 2 +-
> include/linux/page-flags.h | 47 ++++++++++++++++++++++++------
> mm/Kconfig | 6 +++-
> mm/hugetlb.c | 10 +++----
> mm/memory-failure.c | 58 +++++++++++++++++++++++++++-----------
> mm/rmap.c | 43 +++++++++++++++++-----------
> 7 files changed, 120 insertions(+), 48 deletions(-)
>
> diff --git a/fs/Kconfig b/fs/Kconfig
> index cf6ae64776e6..eddac4ed214b 100644
> --- a/fs/Kconfig
> +++ b/fs/Kconfig
> @@ -272,7 +272,7 @@ endif # HUGETLBFS
>
> config HUGETLB_PAGE
> def_bool HUGETLBFS
> - select XARRAY_MULTI
> + select LARGE_FOLIO
>
> config HUGETLB_PAGE_OPTIMIZE_VMEMMAP
> def_bool HUGETLB_PAGE
> diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
> index 216e1a0dd0b2..fbac554886c3 100644
> --- a/fs/hugetlbfs/inode.c
> +++ b/fs/hugetlbfs/inode.c
> @@ -258,7 +258,7 @@ static ssize_t hugetlbfs_read_iter(struct kiocb *iocb, struct iov_iter *to)
> } else {
> folio_unlock(folio);
>
> - if (!folio_test_hwpoison(folio))
> + if (!folio_test_has_hwpoisoned(folio))
> want = nr;
> else {
> /*
> diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
> index 4185a03a45cf..7e8784e852fb 100644
> --- a/include/linux/page-flags.h
> +++ b/include/linux/page-flags.h
> @@ -893,14 +893,20 @@ static inline int PageTransCompound(const struct page *page)
> TESTPAGEFLAG_FALSE(TransCompound, transcompound)
> #endif
>
> -#if defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_TRANSPARENT_HUGEPAGE)
> +#if defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_LARGE_FOLIO)
> /*
> - * PageHasHWPoisoned indicates that at least one subpage is hwpoisoned in the
> - * compound page.
> + * The has_hwpoisoned flag indicates that at least one page is hwpoisoned
> + * in the folio. That page will usually also have the HWPoison flag
> + * set, but this is not possible for folios which have HugeTLB vmemmap
> + * optimization (see hugetlb_update_hwpoison() for the scheme used
> + * in that case). You probably don't want to call this directly; use
> + * folio_has_hwpoisoned_page() instead.
> *
> * This flag is set by hwpoison handler. Cleared by THP split or free page.
> */
> FOLIO_FLAG(has_hwpoisoned, FOLIO_SECOND_PAGE)
> +FOLIO_TEST_SET_FLAG(has_hwpoisoned, FOLIO_SECOND_PAGE)
> +FOLIO_TEST_CLEAR_FLAG(has_hwpoisoned, FOLIO_SECOND_PAGE)
> #else
> FOLIO_FLAG_FALSE(has_hwpoisoned)
> #endif
> @@ -1041,8 +1047,29 @@ PAGE_TYPE_OPS(Slab, slab, slab)
>
> #ifdef CONFIG_HUGETLB_PAGE
> FOLIO_TYPE_OPS(hugetlb, hugetlb)
> +
> +#ifdef CONFIG_MEMORY_FAILURE
> +static inline bool folio_test_huge_poison(const struct folio *folio)
> +{
> + return (READ_ONCE(folio->page.page_type) >> 23) ==
> + ((PGTY_hugetlb << 1) | 1);
> +}
> +
> +static inline void folio_set_huge_poison(struct folio *folio)
> +{
> + folio->page.page_type |= (1 << 23);
> +}
> +
> +static inline void folio_clear_huge_poison(struct folio *folio)
> +{
> + folio->page.page_type &= ~(1 << 23);
> +}
> +#else
> +FOLIO_TEST_FLAG_FALSE(huge_poison)
> +#endif
> #else
> FOLIO_TEST_FLAG_FALSE(hugetlb)
> +FOLIO_TEST_FLAG_FALSE(huge_poison)
> #endif
>
> PAGE_TYPE_OPS(Zsmalloc, zsmalloc, zsmalloc)
> @@ -1069,9 +1096,10 @@ static inline bool PageHuge(const struct page *page)
> }
>
> /*
> - * Check if a page is currently marked HWPoisoned. Note that this check is
> - * best effort only and inherently racy: there is no way to synchronize with
> - * failing hardware.
> + * Check if a page is currently marked HWPoisoned. This check is best
> + * effort only and inherently racy: there is no way to synchronize with
> + * failing hardware. The caller may not have a refcount on the folio
> + * containing the page, so we must be careful to not trip any assertions.
> */
> static inline bool is_page_hwpoison(const struct page *page)
> {
> @@ -1080,12 +1108,15 @@ static inline bool is_page_hwpoison(const struct page *page)
> if (PageHWPoison(page))
> return true;
> folio = page_folio(page);
> - return folio_test_hugetlb(folio) && PageHWPoison(&folio->page);
> + if (folio_test_huge_poison(folio))
> + return true;
> + /* In case we raced with hugetlb transferring flags */
> + return PageHWPoison(page);
> }
>
> static inline bool folio_has_hwpoisoned_page(const struct folio *folio)
> {
> - return folio_test_hwpoison(folio) ||
> + return PageHWPoison(&folio->page) ||
> (folio_test_large(folio) && folio_test_has_hwpoisoned(folio));
> }
>
> diff --git a/mm/Kconfig b/mm/Kconfig
> index 9e0ca4824905..e666dd14ca0c 100644
> --- a/mm/Kconfig
> +++ b/mm/Kconfig
> @@ -843,11 +843,15 @@ config PERSISTENT_HUGE_ZERO_FOLIO
> config MM_ID
> def_bool n
>
> +config LARGE_FOLIO
> + def_bool n
> + select XARRAY_MULTI
> +
> menuconfig TRANSPARENT_HUGEPAGE
> bool "Transparent Hugepage Support"
> depends on HAVE_ARCH_TRANSPARENT_HUGEPAGE && !PREEMPT_RT
> select COMPACTION
> - select XARRAY_MULTI
> + select LARGE_FOLIO
> select MM_ID
> help
> Transparent Hugepages allows the kernel to use huge pages and
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index 47403d02be88..40ae967b9ecc 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -1255,7 +1255,7 @@ static struct folio *dequeue_hugetlb_folio_node_exact(struct hstate *h,
> if (pin && !folio_is_longterm_pinnable(folio))
> continue;
>
> - if (folio_test_hwpoison(folio))
> + if (folio_test_has_hwpoisoned(folio))
> continue;
>
> if (is_migrate_isolate_page(&folio->page))
> @@ -1387,7 +1387,7 @@ static void folio_clear_hugetlb(struct folio *folio)
> * Move HWPoison flag to each error page
> * which makes any healthy pages reusable.
> */
> - if (unlikely(folio_test_hwpoison(folio)))
> + if (unlikely(folio_test_has_hwpoisoned(folio)))
> folio_clear_hugetlb_hwpoison(folio);
>
> __folio_clear_hugetlb(folio);
> @@ -4003,7 +4003,7 @@ long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,
> struct folio *folio, *next;
>
> list_for_each_entry_safe(folio, next, &src->hugepage_freelists[node], lru) {
> - if (folio_test_hwpoison(folio))
> + if (folio_test_has_hwpoisoned(folio))
> continue;
>
> remove_hugetlb_folio(src, folio, false);
> @@ -5814,7 +5814,7 @@ static vm_fault_t hugetlb_no_page(struct address_space *mapping,
> * don't have hwpoisoned swap entry for errored virtual address.
> * So we need to block hugepage fault by PG_hwpoison bit check.
> */
> - if (unlikely(folio_test_hwpoison(folio))) {
> + if (unlikely(folio_test_has_hwpoisoned(folio))) {
> ret = VM_FAULT_HWPOISON_LARGE |
> VM_FAULT_SET_HINDEX(hstate_index(h));
> goto backout_unlocked;
> @@ -6323,7 +6323,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
> ptl = huge_pte_lock(h, dst_mm, dst_pte);
>
> ret = -EIO;
> - if (folio_test_hwpoison(folio))
> + if (folio_test_has_hwpoisoned(folio))
> goto out_release_unlock;
>
> ret = -EEXIST;
> diff --git a/mm/memory-failure.c b/mm/memory-failure.c
> index 1dd0e7b99bb1..714e1b398f2c 100644
> --- a/mm/memory-failure.c
> +++ b/mm/memory-failure.c
> @@ -1829,7 +1829,7 @@ bool is_raw_hwpoison_page_in_hugepage(struct page *page)
> struct folio *folio = page_folio(page);
> bool ret = false;
>
> - if (!folio_test_hwpoison(folio))
> + if (!folio_test_has_hwpoisoned(folio))
> return false;
>
> if (!folio_test_hugetlb(folio))
> @@ -1881,6 +1881,24 @@ static unsigned long __folio_free_raw_hwp(struct folio *folio, bool move_flag)
> #define MF_HUGETLB_FOLIO_PRE_POISONED 3 /* folio already poisoned */
> #define MF_HUGETLB_PAGE_PRE_POISONED 4 /* exact page already poisoned */
> #define MF_HUGETLB_RETRY 5 /* hugepage is busy, retry */
> +
> +static inline int hugetlb_set_poison(struct folio *folio)
> +{
> + if (folio_test_set_has_hwpoisoned(folio))
> + return MF_HUGETLB_FOLIO_PRE_POISONED;
> + folio_set_huge_poison(folio);
> + return 0;
> +}
> +
> +static inline int hugetlb_clear_poison(struct folio *folio)
> +{
> + if (!folio_test_has_hwpoisoned(folio))
> + return -EBUSY;
> + folio_clear_huge_poison(folio);
> + folio_clear_has_hwpoisoned(folio);
> + return 0;
> +}
> +
> /*
> * Set hugetlb folio as hwpoisoned, update folio private raw hwpoison list
> * to keep track of the poisoned pages.
> @@ -1890,12 +1908,12 @@ static int hugetlb_update_hwpoison(struct folio *folio, struct page *page)
> struct llist_head *head;
> struct raw_hwp_page *raw_hwp;
> struct raw_hwp_page *p;
> - int ret = folio_test_set_hwpoison(folio) ? MF_HUGETLB_FOLIO_PRE_POISONED : 0;
> + int ret = hugetlb_set_poison(folio);
>
> /*
> * Once the hwpoison hugepage has lost reliable raw error info,
> - * there is little meaning to keep additional error info precisely,
> - * so skip to add additional raw error info.
> + * there is no point in keeping additional error info precisely,
> + * so skip adding additional raw error info.
> */
> if (folio_test_hugetlb_raw_hwp_unreliable(folio))
> return MF_HUGETLB_FOLIO_PRE_POISONED;
> @@ -1950,8 +1968,8 @@ void folio_clear_hugetlb_hwpoison(struct folio *folio)
> return;
> if (folio_test_hugetlb_vmemmap_optimized(folio))
> return;
> - folio_clear_hwpoison(folio);
> folio_free_raw_hwp(folio, true);
> + folio_clear_has_hwpoisoned(folio);
Should hugetlb_clear_poison be used here to clear huge_poison flag now that hwpoison flag
is transferred to the raw error pages? Apart from this, this patch looks good to me.
Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
Thanks.
.
next prev parent reply other threads:[~2026-09-04 3:46 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-05 21:05 [PATCH v9 00/15] Use generic_file_read_iter() in hugetlbfs Matthew Wilcox (Oracle)
2026-08-05 21:05 ` [PATCH v9 01/15] memory-failure: Fix hardware poison check in unpoison_memory() again Matthew Wilcox (Oracle)
2026-08-05 21:05 ` [PATCH v9 02/15] memory-failure: Prevent hugetlb freeing during unpoisoning Matthew Wilcox (Oracle)
2026-09-04 3:38 ` Miaohe Lin
2026-08-05 21:05 ` [PATCH v9 03/15] mm: Rename folio_contain_hwpoison_page() to folio_has_hwpoison_page() Matthew Wilcox (Oracle)
2026-08-13 7:20 ` David Hildenbrand (Arm)
2026-08-05 21:05 ` [PATCH v9 04/15] hugetlb: Mark some function arguments as const Matthew Wilcox (Oracle)
2026-08-05 21:05 ` [PATCH v9 05/15] guest_memfd: Use folio_has_hwpoisoned_page() Matthew Wilcox (Oracle)
2026-08-13 7:20 ` David Hildenbrand (Arm)
2026-08-13 11:50 ` Matthew Wilcox
2026-08-25 18:41 ` David Hildenbrand (Arm)
2026-08-05 21:05 ` [PATCH v9 06/15] kpageflags: Use is_page_hwpoison() to set KPF_HWPOISON Matthew Wilcox (Oracle)
2026-08-13 7:25 ` David Hildenbrand (Arm)
2026-08-13 9:01 ` David Hildenbrand (Arm)
2026-08-05 21:05 ` [PATCH v9 07/15] hugetlb: Move poison to pages before clearing hugetlb page type Matthew Wilcox (Oracle)
2026-08-05 21:05 ` [PATCH v9 08/15] hugetlb: Use the has_hwpoisoned flag Matthew Wilcox (Oracle)
2026-08-13 8:29 ` David Hildenbrand (Arm)
2026-08-13 16:17 ` Matthew Wilcox
2026-08-13 11:12 ` Pedro Falcato
2026-09-04 3:46 ` Miaohe Lin [this message]
2026-08-05 21:05 ` [PATCH v9 09/15] mm: Remove locking mf_mutex in is_raw_hwpoison_page_in_hugepage() Matthew Wilcox (Oracle)
2026-09-04 6:35 ` Miaohe Lin
2026-08-05 21:05 ` [PATCH v9 10/15] mm: Check individual hugetlb pages for poison Matthew Wilcox (Oracle)
2026-09-04 6:37 ` Miaohe Lin
2026-08-05 21:05 ` [PATCH v9 11/15] filemap: Add hwpoison handling to filemap_read() Matthew Wilcox (Oracle)
2026-08-13 10:55 ` Pedro Falcato
2026-08-13 16:33 ` Matthew Wilcox
2026-08-05 21:05 ` [PATCH v9 12/15] filemap: Remove checks in mapping_set_folio_order_range() Matthew Wilcox (Oracle)
2026-08-13 11:05 ` Pedro Falcato
2026-08-05 21:05 ` [PATCH v9 13/15] hugetlb: Set mapping folio order Matthew Wilcox (Oracle)
2026-08-13 11:06 ` Pedro Falcato
2026-08-05 21:05 ` [PATCH v9 14/15] filemap: Add support for authoritative mappings Matthew Wilcox (Oracle)
2026-08-13 11:10 ` Pedro Falcato
2026-08-05 21:05 ` [PATCH v9 15/15] hugetlb: replace hugetlbfs_read_iter() with generic_file_read_iter() Matthew Wilcox (Oracle)
2026-08-13 11:10 ` Pedro Falcato
2026-08-06 19:47 ` [PATCH v9 00/15] Use generic_file_read_iter() in hugetlbfs jane.chu
2026-08-13 8:37 ` Lorenzo Stoakes (ARM)
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=d30db03b-ffb4-52ce-c922-415ad75661ea@huawei.com \
--to=linmiaohe@huawei.com \
--cc=akpm@linux-foundation.org \
--cc=christian@brauner.io \
--cc=david@kernel.org \
--cc=gourry@gourry.net \
--cc=jack@suse.cz \
--cc=jane.chu@oracle.com \
--cc=jiaqiyan@google.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=muchun.song@linux.dev \
--cc=nao.horiguchi@gmail.com \
--cc=osalvador@suse.de \
--cc=willy@infradead.org \
/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.