diff options
author | Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> | 2010-05-27 20:29:18 -0400 |
---|---|---|
committer | Andi Kleen <ak@linux.intel.com> | 2010-08-11 03:22:12 -0400 |
commit | 7013febc8940960eaaba039bac0f80910f679ce1 (patch) | |
tree | 27a61a69ae8c1df5149ba9ac98cc573e8bf19b95 /mm | |
parent | 7af446a841a264a1a9675001005b29ce01d1fc57 (diff) |
HWPOISON, hugetlb: set/clear PG_hwpoison bits on hugepage
To avoid race condition between concurrent memory errors on identified
hugepage, we atomically test and set PG_hwpoison bit on the head page.
All pages in the error hugepage are considered as hwpoisoned
for now, so set and clear all PG_hwpoison bits in the hugepage
with page lock of the head page held.
Dependency:
"HWPOISON, hugetlb: enable error handling path for hugepage"
Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/memory-failure.c | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 1ec68c80788..fee648b9d39 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c | |||
@@ -920,6 +920,22 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
920 | return ret; | 920 | return ret; |
921 | } | 921 | } |
922 | 922 | ||
923 | static void set_page_hwpoison_huge_page(struct page *hpage) | ||
924 | { | ||
925 | int i; | ||
926 | int nr_pages = 1 << compound_order(hpage); | ||
927 | for (i = 0; i < nr_pages; i++) | ||
928 | SetPageHWPoison(hpage + i); | ||
929 | } | ||
930 | |||
931 | static void clear_page_hwpoison_huge_page(struct page *hpage) | ||
932 | { | ||
933 | int i; | ||
934 | int nr_pages = 1 << compound_order(hpage); | ||
935 | for (i = 0; i < nr_pages; i++) | ||
936 | ClearPageHWPoison(hpage + i); | ||
937 | } | ||
938 | |||
923 | int __memory_failure(unsigned long pfn, int trapno, int flags) | 939 | int __memory_failure(unsigned long pfn, int trapno, int flags) |
924 | { | 940 | { |
925 | struct page_state *ps; | 941 | struct page_state *ps; |
@@ -1014,6 +1030,26 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) | |||
1014 | return 0; | 1030 | return 0; |
1015 | } | 1031 | } |
1016 | 1032 | ||
1033 | /* | ||
1034 | * For error on the tail page, we should set PG_hwpoison | ||
1035 | * on the head page to show that the hugepage is hwpoisoned | ||
1036 | */ | ||
1037 | if (PageTail(p) && TestSetPageHWPoison(hpage)) { | ||
1038 | action_result(pfn, "hugepage already hardware poisoned", | ||
1039 | IGNORED); | ||
1040 | unlock_page(hpage); | ||
1041 | put_page(hpage); | ||
1042 | return 0; | ||
1043 | } | ||
1044 | /* | ||
1045 | * Set PG_hwpoison on all pages in an error hugepage, | ||
1046 | * because containment is done in hugepage unit for now. | ||
1047 | * Since we have done TestSetPageHWPoison() for the head page with | ||
1048 | * page lock held, we can safely set PG_hwpoison bits on tail pages. | ||
1049 | */ | ||
1050 | if (PageHuge(p)) | ||
1051 | set_page_hwpoison_huge_page(hpage); | ||
1052 | |||
1017 | wait_on_page_writeback(p); | 1053 | wait_on_page_writeback(p); |
1018 | 1054 | ||
1019 | /* | 1055 | /* |
@@ -1118,6 +1154,8 @@ int unpoison_memory(unsigned long pfn) | |||
1118 | atomic_long_dec(&mce_bad_pages); | 1154 | atomic_long_dec(&mce_bad_pages); |
1119 | freeit = 1; | 1155 | freeit = 1; |
1120 | } | 1156 | } |
1157 | if (PageHuge(p)) | ||
1158 | clear_page_hwpoison_huge_page(page); | ||
1121 | unlock_page(page); | 1159 | unlock_page(page); |
1122 | 1160 | ||
1123 | put_page(page); | 1161 | put_page(page); |