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 <songmuchun@xxxxxxxxxxxxx> --- mm/hugetlb.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index e3209fd2e6b2..7198bd9bdce5 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -1806,6 +1806,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) { @@ -1853,6 +1868,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) @@ -1877,6 +1905,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); @@ -2066,6 +2097,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); @@ -2436,6 +2468,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