aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNaoya Horiguchi <n-horiguchi@ah.jp.nec.com>2010-09-07 21:19:38 -0400
committerAndi Kleen <ak@linux.intel.com>2010-10-08 03:32:45 -0400
commit8c6c2ecb44667f7204e9d2b89c4c1f42edc5a196 (patch)
tree82dcfddae57bc34c04be1b044b363534082d8ada
parenta9869b837c098732bad84939015c0eb391b23e41 (diff)
HWPOSION, hugetlb: recover from free hugepage error when !MF_COUNT_INCREASED
Currently error recovery for free hugepage works only for MF_COUNT_INCREASED. This patch enables !MF_COUNT_INCREASED case. Free hugepages can be handled directly by alloc_huge_page() and dequeue_hwpoisoned_huge_page(), and both of them are protected by hugetlb_lock, so there is no race between them. Note that this patch defines the refcount of HWPoisoned hugepage dequeued from freelist is 1, deviated from present 0, thereby we can avoid race between unpoison and memory failure on free hugepage. This is reasonable because unlikely to free buddy pages, free hugepage is governed by hugetlbfs even after error handling finishes. And it also makes unpoison code added in the later patch cleaner. Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com> Acked-by: Mel Gorman <mel@csn.ul.ie> Signed-off-by: Andi Kleen <ak@linux.intel.com>
-rw-r--r--mm/hugetlb.c1
-rw-r--r--mm/memory-failure.c33
2 files changed, 33 insertions, 1 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 636be5d6aadd..7123270bfb38 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -2974,6 +2974,7 @@ int dequeue_hwpoisoned_huge_page(struct page *hpage)
2974 spin_lock(&hugetlb_lock); 2974 spin_lock(&hugetlb_lock);
2975 if (is_hugepage_on_freelist(hpage)) { 2975 if (is_hugepage_on_freelist(hpage)) {
2976 list_del(&hpage->lru); 2976 list_del(&hpage->lru);
2977 set_page_refcounted(hpage);
2977 h->free_huge_pages--; 2978 h->free_huge_pages--;
2978 h->free_huge_pages_node[nid]--; 2979 h->free_huge_pages_node[nid]--;
2979 ret = 0; 2980 ret = 0;
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);