|
@@ -854,6 +854,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
|
|
|
int ret;
|
|
|
int kill = 1;
|
|
|
struct page *hpage = compound_head(p);
|
|
|
+ struct page *ppage;
|
|
|
|
|
|
if (PageReserved(p) || PageSlab(p))
|
|
|
return SWAP_SUCCESS;
|
|
@@ -894,6 +895,14 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * ppage: poisoned page
|
|
|
+ * if p is regular page(4k page)
|
|
|
+ * ppage == real poisoned page;
|
|
|
+ * else p is hugetlb or THP, ppage == head page.
|
|
|
+ */
|
|
|
+ ppage = hpage;
|
|
|
+
|
|
|
if (PageTransHuge(hpage)) {
|
|
|
/*
|
|
|
* 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,
|
|
|
BUG_ON(!PageHWPoison(p));
|
|
|
return SWAP_FAIL;
|
|
|
}
|
|
|
+ /* THP is split, so ppage should be the real poisoned page. */
|
|
|
+ ppage = p;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -931,12 +942,18 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
|
|
|
* there's nothing that can be done.
|
|
|
*/
|
|
|
if (kill)
|
|
|
- collect_procs(hpage, &tokill);
|
|
|
+ collect_procs(ppage, &tokill);
|
|
|
|
|
|
- ret = try_to_unmap(hpage, ttu);
|
|
|
+ if (hpage != ppage)
|
|
|
+ lock_page_nosync(ppage);
|
|
|
+
|
|
|
+ ret = try_to_unmap(ppage, ttu);
|
|
|
if (ret != SWAP_SUCCESS)
|
|
|
printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n",
|
|
|
- pfn, page_mapcount(hpage));
|
|
|
+ pfn, page_mapcount(ppage));
|
|
|
+
|
|
|
+ if (hpage != ppage)
|
|
|
+ unlock_page(ppage);
|
|
|
|
|
|
/*
|
|
|
* 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,
|
|
|
* use a more force-full uncatchable kill to prevent
|
|
|
* any accesses to the poisoned memory.
|
|
|
*/
|
|
|
- kill_procs_ao(&tokill, !!PageDirty(hpage), trapno,
|
|
|
+ kill_procs_ao(&tokill, !!PageDirty(ppage), trapno,
|
|
|
ret != SWAP_SUCCESS, p, pfn);
|
|
|
|
|
|
return ret;
|
|
@@ -1090,7 +1107,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
|
|
|
* For error on the tail page, we should set PG_hwpoison
|
|
|
* on the head page to show that the hugepage is hwpoisoned
|
|
|
*/
|
|
|
- if (PageTail(p) && TestSetPageHWPoison(hpage)) {
|
|
|
+ if (PageHuge(p) && PageTail(p) && TestSetPageHWPoison(hpage)) {
|
|
|
action_result(pfn, "hugepage already hardware poisoned",
|
|
|
IGNORED);
|
|
|
unlock_page(hpage);
|