aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memory-failure.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memory-failure.c')
-rw-r--r--mm/memory-failure.c33
1 files changed, 32 insertions, 1 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 5c7158a11592..333f87da1845 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -983,7 +983,10 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
983 * We need/can do nothing about count=0 pages. 983 * We need/can do nothing about count=0 pages.
984 * 1) it's a free page, and therefore in safe hand: 984 * 1) it's a free page, and therefore in safe hand:
985 * prep_new_page() will be the gate keeper. 985 * prep_new_page() will be the gate keeper.
986 * 2) it's part of a non-compound high order page. 986 * 2) it's a free hugepage, which is also safe:
987 * an affected hugepage will be dequeued from hugepage freelist,
988 * so there's no concern about reusing it ever after.
989 * 3) it's part of a non-compound high order page.
987 * Implies some kernel user: cannot stop them from 990 * Implies some kernel user: cannot stop them from
988 * R/W the page; let's pray that the page has been 991 * R/W the page; let's pray that the page has been
989 * used and will be freed some time later. 992 * used and will be freed some time later.
@@ -995,6 +998,24 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
995 if (is_free_buddy_page(p)) { 998 if (is_free_buddy_page(p)) {
996 action_result(pfn, "free buddy", DELAYED); 999 action_result(pfn, "free buddy", DELAYED);
997 return 0; 1000 return 0;
1001 } else if (PageHuge(hpage)) {
1002 /*
1003 * Check "just unpoisoned", "filter hit", and
1004 * "race with other subpage."
1005 */
1006 lock_page_nosync(hpage);
1007 if (!PageHWPoison(hpage)
1008 || (hwpoison_filter(p) && TestClearPageHWPoison(p))
1009 || (p != hpage && TestSetPageHWPoison(hpage))) {
1010 atomic_long_sub(nr_pages, &mce_bad_pages);
1011 return 0;
1012 }
1013 set_page_hwpoison_huge_page(hpage);
1014 res = dequeue_hwpoisoned_huge_page(hpage);
1015 action_result(pfn, "free huge",
1016 res ? IGNORED : DELAYED);
1017 unlock_page(hpage);
1018 return res;
998 } else { 1019 } else {
999 action_result(pfn, "high order kernel", IGNORED); 1020 action_result(pfn, "high order kernel", IGNORED);
1000 return -EBUSY; 1021 return -EBUSY;
@@ -1156,6 +1177,16 @@ int unpoison_memory(unsigned long pfn)
1156 nr_pages = 1 << compound_order(page); 1177 nr_pages = 1 << compound_order(page);
1157 1178
1158 if (!get_page_unless_zero(page)) { 1179 if (!get_page_unless_zero(page)) {
1180 /*
1181 * Since HWPoisoned hugepage should have non-zero refcount,
1182 * race between memory failure and unpoison seems to happen.
1183 * In such case unpoison fails and memory failure runs
1184 * to the end.
1185 */
1186 if (PageHuge(page)) {
1187 pr_debug("MCE: Memory failure is now running on free hugepage %#lx\n", pfn);
1188 return 0;
1189 }
1159 if (TestClearPageHWPoison(p)) 1190 if (TestClearPageHWPoison(p))
1160 atomic_long_sub(nr_pages, &mce_bad_pages); 1191 atomic_long_sub(nr_pages, &mce_bad_pages);
1161 pr_debug("MCE: Software-unpoisoned free page %#lx\n", pfn); 1192 pr_debug("MCE: Software-unpoisoned free page %#lx\n", pfn);