|
@@ -983,7 +983,10 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
|
|
|
* We need/can do nothing about count=0 pages.
|
|
|
* 1) it's a free page, and therefore in safe hand:
|
|
|
* prep_new_page() will be the gate keeper.
|
|
|
- * 2) it's part of a non-compound high order page.
|
|
|
+ * 2) it's a free hugepage, which is also safe:
|
|
|
+ * an affected hugepage will be dequeued from hugepage freelist,
|
|
|
+ * so there's no concern about reusing it ever after.
|
|
|
+ * 3) it's part of a non-compound high order page.
|
|
|
* Implies some kernel user: cannot stop them from
|
|
|
* R/W the page; let's pray that the page has been
|
|
|
* used and will be freed some time later.
|
|
@@ -995,6 +998,24 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
|
|
|
if (is_free_buddy_page(p)) {
|
|
|
action_result(pfn, "free buddy", DELAYED);
|
|
|
return 0;
|
|
|
+ } else if (PageHuge(hpage)) {
|
|
|
+ /*
|
|
|
+ * Check "just unpoisoned", "filter hit", and
|
|
|
+ * "race with other subpage."
|
|
|
+ */
|
|
|
+ lock_page_nosync(hpage);
|
|
|
+ if (!PageHWPoison(hpage)
|
|
|
+ || (hwpoison_filter(p) && TestClearPageHWPoison(p))
|
|
|
+ || (p != hpage && TestSetPageHWPoison(hpage))) {
|
|
|
+ atomic_long_sub(nr_pages, &mce_bad_pages);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ set_page_hwpoison_huge_page(hpage);
|
|
|
+ res = dequeue_hwpoisoned_huge_page(hpage);
|
|
|
+ action_result(pfn, "free huge",
|
|
|
+ res ? IGNORED : DELAYED);
|
|
|
+ unlock_page(hpage);
|
|
|
+ return res;
|
|
|
} else {
|
|
|
action_result(pfn, "high order kernel", IGNORED);
|
|
|
return -EBUSY;
|
|
@@ -1156,6 +1177,16 @@ int unpoison_memory(unsigned long pfn)
|
|
|
nr_pages = 1 << compound_order(page);
|
|
|
|
|
|
if (!get_page_unless_zero(page)) {
|
|
|
+ /*
|
|
|
+ * Since HWPoisoned hugepage should have non-zero refcount,
|
|
|
+ * race between memory failure and unpoison seems to happen.
|
|
|
+ * In such case unpoison fails and memory failure runs
|
|
|
+ * to the end.
|
|
|
+ */
|
|
|
+ if (PageHuge(page)) {
|
|
|
+ pr_debug("MCE: Memory failure is now running on free hugepage %#lx\n", pfn);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
if (TestClearPageHWPoison(p))
|
|
|
atomic_long_sub(nr_pages, &mce_bad_pages);
|
|
|
pr_debug("MCE: Software-unpoisoned free page %#lx\n", pfn);
|