Adds the functionality to search a subpage's corresponding raw_hwp_page in hugetlb page's HWPOISON list. This functionality can also tell if a subpage is a raw HWPOISON page. Exports this functionality to be immediately used in the read operation for hugetlbfs. Signed-off-by: Jiaqi Yan <jiaqiyan@xxxxxxxxxx> --- include/linux/mm.h | 23 +++++++++++++++++++++++ mm/memory-failure.c | 26 ++++++++++++++++---------- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 27ce77080c79..f191a4119719 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3683,6 +3683,29 @@ enum mf_action_page_type { */ extern const struct attribute_group memory_failure_attr_group; +#ifdef CONFIG_HUGETLB_PAGE +/* + * Struct raw_hwp_page represents information about "raw error page", + * constructing singly linked list from ->_hugetlb_hwpoison field of folio. + */ +struct raw_hwp_page { + struct llist_node node; + struct page *page; +}; + +static inline struct llist_head *raw_hwp_list_head(struct folio *folio) +{ + return (struct llist_head *)&folio->_hugetlb_hwpoison; +} + +/* + * Given @subpage, a raw page in a hugepage, find its location in @folio's + * _hugetlb_hwpoison list. Return NULL if @subpage is not in the list. + */ +struct raw_hwp_page *find_raw_hwp_page(struct folio *folio, + struct page *subpage); +#endif + #if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_HUGETLBFS) extern void clear_huge_page(struct page *page, unsigned long addr_hint, diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 5b663eca1f29..c49e6c2d1f07 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1818,18 +1818,24 @@ EXPORT_SYMBOL_GPL(mf_dax_kill_procs); #endif /* CONFIG_FS_DAX */ #ifdef CONFIG_HUGETLB_PAGE -/* - * Struct raw_hwp_page represents information about "raw error page", - * constructing singly linked list from ->_hugetlb_hwpoison field of folio. - */ -struct raw_hwp_page { - struct llist_node node; - struct page *page; -}; -static inline struct llist_head *raw_hwp_list_head(struct folio *folio) +struct raw_hwp_page *find_raw_hwp_page(struct folio *folio, + struct page *subpage) { - return (struct llist_head *)&folio->_hugetlb_hwpoison; + struct llist_node *t, *tnode; + struct llist_head *raw_hwp_head = raw_hwp_list_head(folio); + struct raw_hwp_page *hwp_page = NULL; + struct raw_hwp_page *p; + + llist_for_each_safe(tnode, t, raw_hwp_head->first) { + p = container_of(tnode, struct raw_hwp_page, node); + if (subpage == p->page) { + hwp_page = p; + break; + } + } + + return hwp_page; } static unsigned long __folio_free_raw_hwp(struct folio *folio, bool move_flag) -- 2.40.1.606.ga4b1b128d6-goog