aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memory-failure.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memory-failure.c')
-rw-r--r--mm/memory-failure.c27
1 files changed, 22 insertions, 5 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 1e9c30b241c3..04158d6f44d4 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -854,6 +854,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
854 int ret; 854 int ret;
855 int kill = 1; 855 int kill = 1;
856 struct page *hpage = compound_head(p); 856 struct page *hpage = compound_head(p);
857 struct page *ppage;
857 858
858 if (PageReserved(p) || PageSlab(p)) 859 if (PageReserved(p) || PageSlab(p))
859 return SWAP_SUCCESS; 860 return SWAP_SUCCESS;
@@ -894,6 +895,14 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
894 } 895 }
895 } 896 }
896 897
898 /*
899 * ppage: poisoned page
900 * if p is regular page(4k page)
901 * ppage == real poisoned page;
902 * else p is hugetlb or THP, ppage == head page.
903 */
904 ppage = hpage;
905
897 if (PageTransHuge(hpage)) { 906 if (PageTransHuge(hpage)) {
898 /* 907 /*
899 * Verify that this isn't a hugetlbfs head page, the check for 908 * Verify that this isn't a hugetlbfs head page, the check for
@@ -919,6 +928,8 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
919 BUG_ON(!PageHWPoison(p)); 928 BUG_ON(!PageHWPoison(p));
920 return SWAP_FAIL; 929 return SWAP_FAIL;
921 } 930 }
931 /* THP is split, so ppage should be the real poisoned page. */
932 ppage = p;
922 } 933 }
923 } 934 }
924 935
@@ -931,12 +942,18 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
931 * there's nothing that can be done. 942 * there's nothing that can be done.
932 */ 943 */
933 if (kill) 944 if (kill)
934 collect_procs(hpage, &tokill); 945 collect_procs(ppage, &tokill);
935 946
936 ret = try_to_unmap(hpage, ttu); 947 if (hpage != ppage)
948 lock_page_nosync(ppage);
949
950 ret = try_to_unmap(ppage, ttu);
937 if (ret != SWAP_SUCCESS) 951 if (ret != SWAP_SUCCESS)
938 printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n", 952 printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n",
939 pfn, page_mapcount(hpage)); 953 pfn, page_mapcount(ppage));
954
955 if (hpage != ppage)
956 unlock_page(ppage);
940 957
941 /* 958 /*
942 * Now that the dirty bit has been propagated to the 959 * Now that the dirty bit has been propagated to the
@@ -947,7 +964,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
947 * use a more force-full uncatchable kill to prevent 964 * use a more force-full uncatchable kill to prevent
948 * any accesses to the poisoned memory. 965 * any accesses to the poisoned memory.
949 */ 966 */
950 kill_procs_ao(&tokill, !!PageDirty(hpage), trapno, 967 kill_procs_ao(&tokill, !!PageDirty(ppage), trapno,
951 ret != SWAP_SUCCESS, p, pfn); 968 ret != SWAP_SUCCESS, p, pfn);
952 969
953 return ret; 970 return ret;
@@ -1090,7 +1107,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
1090 * For error on the tail page, we should set PG_hwpoison 1107 * For error on the tail page, we should set PG_hwpoison
1091 * on the head page to show that the hugepage is hwpoisoned 1108 * on the head page to show that the hugepage is hwpoisoned
1092 */ 1109 */
1093 if (PageTail(p) && TestSetPageHWPoison(hpage)) { 1110 if (PageHuge(p) && PageTail(p) && TestSetPageHWPoison(hpage)) {
1094 action_result(pfn, "hugepage already hardware poisoned", 1111 action_result(pfn, "hugepage already hardware poisoned",
1095 IGNORED); 1112 IGNORED);
1096 unlock_page(hpage); 1113 unlock_page(hpage);