Checking to see whether a page inside a hugetlb folio is hardware poisoned is more complicated than I realised. The correct logic was in is_raw_hwpoison_page_in_hugepage(). Make is_page_hwpoison() the official entry point for "is this page hwpoison", no matter what kind of folio it belongs to. Rename is_raw_hwpoison_page_in_hugepage() to hugetlb_page_hwpoison(), and remove the attempt to handle non-hugetlb folios from it. Signed-off-by: Matthew Wilcox (Oracle) --- fs/hugetlbfs/inode.c | 4 ++-- include/linux/hugetlb.h | 5 ----- include/linux/page-flags.h | 24 +++++++++++++++++++----- mm/memory-failure.c | 9 ++++----- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 1760df6f2709..725bb945a440 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -198,7 +198,7 @@ static size_t adjust_range_hwpoison(struct folio *folio, size_t offset, struct page *page = folio_page(folio, offset / PAGE_SIZE); size_t safe_bytes; - if (is_raw_hwpoison_page_in_hugepage(page)) + if (hugetlb_page_hwpoison(folio, page)) return 0; /* Safe to read the remaining bytes in this page. */ safe_bytes = PAGE_SIZE - (offset % PAGE_SIZE); @@ -206,7 +206,7 @@ static size_t adjust_range_hwpoison(struct folio *folio, size_t offset, /* Check each remaining page as long as we are not done yet. */ for (; safe_bytes < bytes; safe_bytes += PAGE_SIZE, page++) - if (is_raw_hwpoison_page_in_hugepage(page)) + if (hugetlb_page_hwpoison(folio, page)) break; return min(safe_bytes, bytes); diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 2abaf99321e9..5df0bb618b05 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -1070,11 +1070,6 @@ void hugetlb_register_node(struct node *node); void hugetlb_unregister_node(struct node *node); #endif -/* - * Check if a given raw @page in a hugepage is HWPOISON. - */ -bool is_raw_hwpoison_page_in_hugepage(struct page *page); - static inline unsigned long huge_page_mask_align(struct file *file) { return PAGE_MASK & ~huge_page_mask(hstate_file(file)); diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 7223f6f4e2b4..b0b451b4e632 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -1068,6 +1068,9 @@ static inline bool PageHuge(const struct page *page) return folio_test_hugetlb(page_folio(page)); } +#ifdef CONFIG_MEMORY_FAILURE +bool hugetlb_page_hwpoison(const struct folio *folio, 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 @@ -1075,13 +1078,24 @@ static inline bool PageHuge(const struct page *page) */ static inline bool is_page_hwpoison(const struct page *page) { - const struct folio *folio; + const struct folio *folio = page_folio(page); + + if (folio_test_hugetlb(folio)) + return hugetlb_page_hwpoison(folio, page); + return PageHWPoison(page); +} +#else +static inline bool hugetlb_page_hwpoison(const struct folio *folio, + const struct page *page) +{ + return false; +} - if (PageHWPoison(page)) - return true; - folio = page_folio(page); - return folio_test_hugetlb(folio) && PageHWPoison(&folio->page); +static inline bool is_page_hwpoison(const struct page *page) +{ + return false; } +#endif static inline bool folio_contain_hwpoisoned_page(struct folio *folio) { diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 51508a55c405..0980791108a4 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1822,19 +1822,18 @@ static inline struct llist_head *raw_hwp_list_head(struct folio *folio) return (struct llist_head *)&folio->_hugetlb_hwpoison; } -bool is_raw_hwpoison_page_in_hugepage(struct page *page) +/* + * Check if a given @page in a hugetlb folio is HWPOISON. + */ +bool hugetlb_page_hwpoison(const struct folio *folio, const struct page *page) { struct llist_head *raw_hwp_head; struct raw_hwp_page *p; - struct folio *folio = page_folio(page); bool ret = false; if (!folio_test_hwpoison(folio)) return false; - if (!folio_test_hugetlb(folio)) - return PageHWPoison(page); - /* * When RawHwpUnreliable is set, kernel lost track of which subpages * are HWPOISON. So return as if ALL subpages are HWPOISONed. -- 2.47.3