[PATCH v1 1/3] mm/hwpoison: find subpage in hugetlb HWPOISON list

From: Jiaqi Yan
Date: Wed May 17 2023 - 12:10:10 EST


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