From: Greg Kroah-Hartman Date: Mon, 8 Nov 2021 08:06:34 +0000 (+0100) Subject: 5.10-stable patches X-Git-Tag: v4.4.292~31 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7c73b0c0eefadba48fa3fb273ec4d54c4dc034e6;p=thirdparty%2Fkernel%2Fstable-queue.git 5.10-stable patches added patches: mm-filemap-check-if-thp-has-hwpoisoned-subpage-for-pmd-page-fault.patch mm-hwpoison-remove-the-unnecessary-thp-check.patch --- diff --git a/queue-5.10/mm-filemap-check-if-thp-has-hwpoisoned-subpage-for-pmd-page-fault.patch b/queue-5.10/mm-filemap-check-if-thp-has-hwpoisoned-subpage-for-pmd-page-fault.patch new file mode 100644 index 00000000000..8190dca6365 --- /dev/null +++ b/queue-5.10/mm-filemap-check-if-thp-has-hwpoisoned-subpage-for-pmd-page-fault.patch @@ -0,0 +1,166 @@ +From eac96c3efdb593df1a57bb5b95dbe037bfa9a522 Mon Sep 17 00:00:00 2001 +From: Yang Shi +Date: Thu, 28 Oct 2021 14:36:11 -0700 +Subject: mm: filemap: check if THP has hwpoisoned subpage for PMD page fault + +From: Yang Shi + +commit eac96c3efdb593df1a57bb5b95dbe037bfa9a522 upstream. + +When handling shmem page fault the THP with corrupted subpage could be +PMD mapped if certain conditions are satisfied. But kernel is supposed +to send SIGBUS when trying to map hwpoisoned page. + +There are two paths which may do PMD map: fault around and regular +fault. + +Before commit f9ce0be71d1f ("mm: Cleanup faultaround and finish_fault() +codepaths") the thing was even worse in fault around path. The THP +could be PMD mapped as long as the VMA fits regardless what subpage is +accessed and corrupted. After this commit as long as head page is not +corrupted the THP could be PMD mapped. + +In the regular fault path the THP could be PMD mapped as long as the +corrupted page is not accessed and the VMA fits. + +This loophole could be fixed by iterating every subpage to check if any +of them is hwpoisoned or not, but it is somewhat costly in page fault +path. + +So introduce a new page flag called HasHWPoisoned on the first tail +page. It indicates the THP has hwpoisoned subpage(s). It is set if any +subpage of THP is found hwpoisoned by memory failure and after the +refcount is bumped successfully, then cleared when the THP is freed or +split. + +The soft offline path doesn't need this since soft offline handler just +marks a subpage hwpoisoned when the subpage is migrated successfully. +But shmem THP didn't get split then migrated at all. + +Link: https://lkml.kernel.org/r/20211020210755.23964-3-shy828301@gmail.com +Fixes: 800d8c63b2e9 ("shmem: add huge pages support") +Signed-off-by: Yang Shi +Reviewed-by: Naoya Horiguchi +Suggested-by: Kirill A. Shutemov +Cc: Hugh Dickins +Cc: Matthew Wilcox +Cc: Oscar Salvador +Cc: Peter Xu +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/page-flags.h | 23 +++++++++++++++++++++++ + mm/huge_memory.c | 2 ++ + mm/memory-failure.c | 14 ++++++++++++++ + mm/memory.c | 9 +++++++++ + mm/page_alloc.c | 4 +++- + 5 files changed, 51 insertions(+), 1 deletion(-) + +--- a/include/linux/page-flags.h ++++ b/include/linux/page-flags.h +@@ -169,6 +169,15 @@ enum pageflags { + /* Compound pages. Stored in first tail page's flags */ + PG_double_map = PG_workingset, + ++#ifdef CONFIG_MEMORY_FAILURE ++ /* ++ * Compound pages. Stored in first tail page's flags. ++ * Indicates that at least one subpage is hwpoisoned in the ++ * THP. ++ */ ++ PG_has_hwpoisoned = PG_mappedtodisk, ++#endif ++ + /* non-lru isolated movable page */ + PG_isolated = PG_reclaim, + +@@ -701,6 +710,20 @@ PAGEFLAG_FALSE(DoubleMap) + TESTSCFLAG_FALSE(DoubleMap) + #endif + ++#if defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_TRANSPARENT_HUGEPAGE) ++/* ++ * PageHasHWPoisoned indicates that at least one subpage is hwpoisoned in the ++ * compound page. ++ * ++ * This flag is set by hwpoison handler. Cleared by THP split or free page. ++ */ ++PAGEFLAG(HasHWPoisoned, has_hwpoisoned, PF_SECOND) ++ TESTSCFLAG(HasHWPoisoned, has_hwpoisoned, PF_SECOND) ++#else ++PAGEFLAG_FALSE(HasHWPoisoned) ++ TESTSCFLAG_FALSE(HasHWPoisoned) ++#endif ++ + /* + * For pages that are never mapped to userspace (and aren't PageSlab), + * page_type may be used. Because it is initialised to -1, we invert the +--- a/mm/huge_memory.c ++++ b/mm/huge_memory.c +@@ -2464,6 +2464,8 @@ static void __split_huge_page(struct pag + xa_lock(&swap_cache->i_pages); + } + ++ ClearPageHasHWPoisoned(head); ++ + for (i = nr - 1; i >= 1; i--) { + __split_huge_page_tail(head, i, lruvec, list); + /* Some pages can be beyond i_size: drop them from page cache */ +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -1367,6 +1367,20 @@ int memory_failure(unsigned long pfn, in + } + + if (PageTransHuge(hpage)) { ++ /* ++ * The flag must be set after the refcount is bumped ++ * otherwise it may race with THP split. ++ * And the flag can't be set in get_hwpoison_page() since ++ * it is called by soft offline too and it is just called ++ * for !MF_COUNT_INCREASE. So here seems to be the best ++ * place. ++ * ++ * Don't need care about the above error handling paths for ++ * get_hwpoison_page() since they handle either free page ++ * or unhandlable page. The refcount is bumped iff the ++ * page is a valid handlable page. ++ */ ++ SetPageHasHWPoisoned(hpage); + if (try_to_split_thp_page(p, "Memory Failure") < 0) { + action_result(pfn, MF_MSG_UNSPLIT_THP, MF_IGNORED); + return -EBUSY; +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -3921,6 +3921,15 @@ vm_fault_t finish_fault(struct vm_fault + page = vmf->page; + + /* ++ * Just backoff if any subpage of a THP is corrupted otherwise ++ * the corrupted page may mapped by PMD silently to escape the ++ * check. This kind of THP just can be PTE mapped. Access to ++ * the corrupted subpage should trigger SIGBUS as expected. ++ */ ++ if (unlikely(PageHasHWPoisoned(page))) ++ return ret; ++ ++ /* + * check even for read faults because we might have lost our CoWed + * page + */ +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -1232,8 +1232,10 @@ static __always_inline bool free_pages_p + + VM_BUG_ON_PAGE(compound && compound_order(page) != order, page); + +- if (compound) ++ if (compound) { + ClearPageDoubleMap(page); ++ ClearPageHasHWPoisoned(page); ++ } + for (i = 1; i < (1 << order); i++) { + if (compound) + bad += free_tail_pages_check(page, page + i); diff --git a/queue-5.10/mm-hwpoison-remove-the-unnecessary-thp-check.patch b/queue-5.10/mm-hwpoison-remove-the-unnecessary-thp-check.patch new file mode 100644 index 00000000000..361af1626f9 --- /dev/null +++ b/queue-5.10/mm-hwpoison-remove-the-unnecessary-thp-check.patch @@ -0,0 +1,63 @@ +From c7cb42e94473aafe553c0f2a3d8ca904599399ed Mon Sep 17 00:00:00 2001 +From: Yang Shi +Date: Thu, 28 Oct 2021 14:36:07 -0700 +Subject: mm: hwpoison: remove the unnecessary THP check + +From: Yang Shi + +commit c7cb42e94473aafe553c0f2a3d8ca904599399ed upstream. + +When handling THP hwpoison checked if the THP is in allocation or free +stage since hwpoison may mistreat it as hugetlb page. After commit +415c64c1453a ("mm/memory-failure: split thp earlier in memory error +handling") the problem has been fixed, so this check is no longer +needed. Remove it. The side effect of the removal is hwpoison may +report unsplit THP instead of unknown error for shmem THP. It seems not +like a big deal. + +The following patch "mm: filemap: check if THP has hwpoisoned subpage +for PMD page fault" depends on this, which fixes shmem THP with +hwpoisoned subpage(s) are mapped PMD wrongly. So this patch needs to be +backported to -stable as well. + +Link: https://lkml.kernel.org/r/20211020210755.23964-2-shy828301@gmail.com +Signed-off-by: Yang Shi +Suggested-by: Naoya Horiguchi +Acked-by: Naoya Horiguchi +Cc: Hugh Dickins +Cc: Kirill A. Shutemov +Cc: Matthew Wilcox +Cc: Oscar Salvador +Cc: Peter Xu +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/memory-failure.c | 14 -------------- + 1 file changed, 14 deletions(-) + +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -956,20 +956,6 @@ static int get_hwpoison_page(struct page + { + struct page *head = compound_head(page); + +- if (!PageHuge(head) && PageTransHuge(head)) { +- /* +- * Non anonymous thp exists only in allocation/free time. We +- * can't handle such a case correctly, so let's give it up. +- * This should be better than triggering BUG_ON when kernel +- * tries to touch the "partially handled" page. +- */ +- if (!PageAnon(head)) { +- pr_err("Memory failure: %#lx: non anonymous thp\n", +- page_to_pfn(page)); +- return 0; +- } +- } +- + if (get_page_unless_zero(head)) { + if (head == compound_head(page)) + return 1; diff --git a/queue-5.10/series b/queue-5.10/series index cedac7bfc5b..eb055a5ff66 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -1,3 +1,5 @@ kvm-x86-avoid-warning-with-wbitwise-instead-of-logical.patch revert-x86-kvm-fix-vcpu-id-indexed-array-sizes.patch usb-ehci-handshake-cmd_run-instead-of-sts_halt.patch +mm-hwpoison-remove-the-unnecessary-thp-check.patch +mm-filemap-check-if-thp-has-hwpoisoned-subpage-for-pmd-page-fault.patch