[RFC PATCH 18/24] mm/hugetlb: Clear PageHWPoison on the non-error memory page
From: Muchun Song <hidden>
Date: 2020-09-16 00:41:57
Also in:
linux-fsdevel, linux-mm, lkml
Subsystem:
hugetlb subsystem, memory management, the rest · Maintainers:
Muchun Song, Oscar Salvador, Andrew Morton, Linus Torvalds
Because we reuse the first tail page, if we set PageHWPosion on a tail page. It indicates that we may set PageHWPoison on a series of pages. So we need to clear PageHWPoison on the non-error pages. We use the head[3].mapping to record the real error page index and clear non-error page PageHWPoison later. Signed-off-by: Muchun Song <redacted> --- mm/hugetlb.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 34706cec21ec..8666cedf9a7b 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c@@ -1847,6 +1847,21 @@ static inline void free_gigantic_page_comm(struct hstate *h, struct page *page) { free_gigantic_page(page, huge_page_order(h)); } + +static inline bool subpage_hwpoison(struct page *head, struct page *page) +{ + return page_private(head + 4) == page - head; +} + +static inline void set_subpage_hwpoison(struct page *head, struct page *page) +{ + set_page_private(head + 4, page - head); +} + +static inline void clear_subpage_hwpoison(struct page *head) +{ + set_page_private(head + 4, 0); +} #else static inline void hugetlb_vmemmap_init(struct hstate *h) {
@@ -1894,6 +1909,19 @@ static inline void free_gigantic_page_comm(struct hstate *h, struct page *page) free_gigantic_page(page, huge_page_order(h)); spin_lock(&hugetlb_lock); } + +static inline bool subpage_hwpoison(struct page *head, struct page *page) +{ + return true; +} + +static inline void set_subpage_hwpoison(struct page *head, struct page *page) +{ +} + +static inline void clear_subpage_hwpoison(struct page *head) +{ +} #endif static void update_and_free_page(struct hstate *h, struct page *page)
@@ -1918,6 +1946,9 @@ static void __free_hugepage(struct hstate *h, struct page *page) 1 << PG_referenced | 1 << PG_dirty | 1 << PG_active | 1 << PG_private | 1 << PG_writeback); + + if (PageHWPoison(page + i) && !subpage_hwpoison(page, page + i)) + ClearPageHWPoison(page + i); } VM_BUG_ON_PAGE(hugetlb_cgroup_from_page(page), page); VM_BUG_ON_PAGE(hugetlb_cgroup_from_page_rsvd(page), page);
@@ -2107,6 +2138,7 @@ static void prep_new_huge_page(struct hstate *h, struct page *page, int nid) free_huge_page_vmemmap(h, page); /* Must be called before the initialization of @page->lru */ vmemmap_pgtable_free(h, page); + clear_subpage_hwpoison(page); INIT_LIST_HEAD(&page->lru); set_compound_page_dtor(page, HUGETLB_PAGE_DTOR);
@@ -2477,6 +2509,7 @@ int dissolve_free_huge_page(struct page *page) SetPageHWPoison(page); ClearPageHWPoison(head); } + set_subpage_hwpoison(head, page); list_del(&head->lru); h->free_huge_pages--; h->free_huge_pages_node[nid]--;
--
2.20.1