From 516d1ecdea33b6c05919452aceed708be832a924 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Wed, 8 Sep 2010 10:19:38 +0900 Subject: [PATCH] --- yaml --- r: 217347 b: refs/heads/master c: 8c6c2ecb44667f7204e9d2b89c4c1f42edc5a196 h: refs/heads/master i: 217345: a812adb6a4388ab945fc2babc11c6b6f8bc7a9bb 217343: 76ec01a2a5ae56cda07bb0727d29e737b47ae80c v: v3 --- [refs] | 2 +- trunk/mm/hugetlb.c | 1 + trunk/mm/memory-failure.c | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/[refs] b/[refs] index b292dbd79e46..88d1a6c1421e 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: a9869b837c098732bad84939015c0eb391b23e41 +refs/heads/master: 8c6c2ecb44667f7204e9d2b89c4c1f42edc5a196 diff --git a/trunk/mm/hugetlb.c b/trunk/mm/hugetlb.c index 636be5d6aadd..7123270bfb38 100644 --- a/trunk/mm/hugetlb.c +++ b/trunk/mm/hugetlb.c @@ -2974,6 +2974,7 @@ int dequeue_hwpoisoned_huge_page(struct page *hpage) spin_lock(&hugetlb_lock); if (is_hugepage_on_freelist(hpage)) { list_del(&hpage->lru); + set_page_refcounted(hpage); h->free_huge_pages--; h->free_huge_pages_node[nid]--; ret = 0; diff --git a/trunk/mm/memory-failure.c b/trunk/mm/memory-failure.c index 5c7158a11592..333f87da1845 100644 --- a/trunk/mm/memory-failure.c +++ b/trunk/mm/memory-failure.c @@ -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);