aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorJin Dongming <jin.dongming@np.css.fujitsu.com>2011-02-01 18:52:40 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-02-02 19:03:19 -0500
commita6d30dddae4648837be5a0c0cb2c0ae9ad0377db (patch)
treef04020b0442b8bfce45e159bde01a61f01c39c30 /mm
parentefeda7a41e09efce506a68c3549b60b16dd7dedd (diff)
thp: fix the wrong reported address of hwpoisoned hugepages
When the tail page of THP is poisoned, the head page will be poisoned too. And the wrong address, address of head page, will be sent with sigbus always. So when the poisoned page is used by Guest OS which is running on KVM, after the address changing(hva->gpa) by qemu, the unexpected process on Guest OS will be killed by sigbus. What we expected is that the process using the poisoned tail page could be killed on Guest OS, but not that the process using the healthy head page is killed. Since it is not good to poison the healthy page, avoid poisoning other than the page which is really poisoned. (While we poison all pages in a huge page in case of hugetlb, we can do this for THP thanks to split_huge_page().) Here we fix two parts: 1. Isolate the poisoned page only to make sure the reported address is the address of poisoned page. 2. make the poisoned page work as the poisoned regular page. [akpm@linux-foundation.org: fix spello in comment] Signed-off-by: Jin Dongming <jin.dongming@np.css.fujitsu.com> Reviewed-by: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Andi Kleen <andi@firstfloor.org> 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/huge_memory.c7
-rw-r--r--mm/memory-failure.c27
2 files changed, 28 insertions, 6 deletions
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index e187454d82f6..b6c1ce3c53b5 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1162,7 +1162,12 @@ static void __split_huge_page_refcount(struct page *page)
1162 /* after clearing PageTail the gup refcount can be released */ 1162 /* after clearing PageTail the gup refcount can be released */
1163 smp_mb(); 1163 smp_mb();
1164 1164
1165 page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP; 1165 /*
1166 * retain hwpoison flag of the poisoned tail page:
1167 * fix for the unsuitable process killed on Guest Machine(KVM)
1168 * by the memory-failure.
1169 */
1170 page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP | __PG_HWPOISON;
1166 page_tail->flags |= (page->flags & 1171 page_tail->flags |= (page->flags &
1167 ((1L << PG_referenced) | 1172 ((1L << PG_referenced) |
1168 (1L << PG_swapbacked) | 1173 (1L << PG_swapbacked) |
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);