aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorChen Yucong <slaoub@gmail.com>2014-05-22 14:54:15 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-05-23 12:37:29 -0400
commitb985194c8c0a130ed155b71662e39f7eaea4876f (patch)
tree8fd7a95f8da83ddbc0c12d919cd86a2c64f74489 /mm
parent4b660a7f5c8099d88d1a43d8ae138965112592c7 (diff)
hwpoison, hugetlb: lock_page/unlock_page does not match for handling a free hugepage
For handling a free hugepage in memory failure, the race will happen if another thread hwpoisoned this hugepage concurrently. So we need to check PageHWPoison instead of !PageHWPoison. If hwpoison_filter(p) returns true or a race happens, then we need to unlock_page(hpage). Signed-off-by: Chen Yucong <slaoub@gmail.com> Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Tested-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Reviewed-by: Andi Kleen <ak@linux.intel.com> Cc: <stable@vger.kernel.org> [2.6.36+] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/memory-failure.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 35ef28acf137..dbf8922216ad 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1081,15 +1081,16 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
1081 return 0; 1081 return 0;
1082 } else if (PageHuge(hpage)) { 1082 } else if (PageHuge(hpage)) {
1083 /* 1083 /*
1084 * Check "just unpoisoned", "filter hit", and 1084 * Check "filter hit" and "race with other subpage."
1085 * "race with other subpage."
1086 */ 1085 */
1087 lock_page(hpage); 1086 lock_page(hpage);
1088 if (!PageHWPoison(hpage) 1087 if (PageHWPoison(hpage)) {
1089 || (hwpoison_filter(p) && TestClearPageHWPoison(p)) 1088 if ((hwpoison_filter(p) && TestClearPageHWPoison(p))
1090 || (p != hpage && TestSetPageHWPoison(hpage))) { 1089 || (p != hpage && TestSetPageHWPoison(hpage))) {
1091 atomic_long_sub(nr_pages, &num_poisoned_pages); 1090 atomic_long_sub(nr_pages, &num_poisoned_pages);
1092 return 0; 1091 unlock_page(hpage);
1092 return 0;
1093 }
1093 } 1094 }
1094 set_page_hwpoison_huge_page(hpage); 1095 set_page_hwpoison_huge_page(hpage);
1095 res = dequeue_hwpoisoned_huge_page(hpage); 1096 res = dequeue_hwpoisoned_huge_page(hpage);