aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNaoya Horiguchi <[email protected]>2021-08-19 19:04:24 -0700
committerLinus Torvalds <[email protected]>2021-08-20 11:31:42 -0700
commitfcc00621d88b274b5dffd8daeea71d0e4c28b84e (patch)
tree202aae1cb1efbe12e4c794fff6588b543a730b57
parentf56ce412a59d7d938b81de8878faef128812482c (diff)
mm/hwpoison: retry with shake_page() for unhandlable pages
HWPoisonHandlable() sometimes returns false for typical user pages due to races with average memory events like transfers over LRU lists. This causes failures in hwpoison handling. There's retry code for such a case but does not work because the retry loop reaches the retry limit too quickly before the page settles down to handlable state. Let get_any_page() call shake_page() to fix it. [[email protected]: get_any_page(): return -EIO when retry limit reached] Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Fixes: 25182f05ffed ("mm,hwpoison: fix race with hugetlb page allocation") Signed-off-by: Naoya Horiguchi <[email protected]> Reported-by: Tony Luck <[email protected]> Reviewed-by: Yang Shi <[email protected]> Cc: Oscar Salvador <[email protected]> Cc: Muchun Song <[email protected]> Cc: Mike Kravetz <[email protected]> Cc: Michal Hocko <[email protected]> Cc: <[email protected]> [5.13+] Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
-rw-r--r--mm/memory-failure.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index eefd823deb67..470400cc7513 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1146,7 +1146,7 @@ static int __get_hwpoison_page(struct page *page)
* unexpected races caused by taking a page refcount.
*/
if (!HWPoisonHandlable(head))
- return 0;
+ return -EBUSY;
if (PageTransHuge(head)) {
/*
@@ -1199,9 +1199,15 @@ try_again:
}
goto out;
} else if (ret == -EBUSY) {
- /* We raced with freeing huge page to buddy, retry. */
- if (pass++ < 3)
+ /*
+ * We raced with (possibly temporary) unhandlable
+ * page, retry.
+ */
+ if (pass++ < 3) {
+ shake_page(p, 1);
goto try_again;
+ }
+ ret = -EIO;
goto out;
}
}