Skip to content

Commit 415c64c

Browse files
Naoya Horiguchitorvalds
authored andcommitted
mm/memory-failure: split thp earlier in memory error handling
memory_failure() doesn't handle thp itself at this time and need to split it before doing isolation. Currently thp is split in the middle of hwpoison_user_mappings(), but there're corner cases where memory_failure() wrongly tries to handle thp without splitting. 1) "non anonymous" thp, which is not a normal operating mode of thp, but a memory error could hit a thp before anon_vma is initialized. In such case, split_huge_page() fails and me_huge_page() (intended for hugetlb) is called for thp, which triggers BUG_ON in page_hstate(). 2) !PageLRU case, where hwpoison_user_mappings() returns with SWAP_SUCCESS and the result is the same as case 1. memory_failure() can't avoid splitting, so let's split it more earlier, which also reduces code which are prepared for both of normal page and thp. Signed-off-by: Naoya Horiguchi <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Tony Luck <[email protected]> Cc: "Kirill A. Shutemov" <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 95bbc0c commit 415c64c

File tree

1 file changed

+25
-63
lines changed

1 file changed

+25
-63
lines changed

mm/memory-failure.c

Lines changed: 25 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -928,7 +928,6 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
928928
int ret;
929929
int kill = 1, forcekill;
930930
struct page *hpage = *hpagep;
931-
struct page *ppage;
932931

933932
/*
934933
* Here we are interested only in user-mapped pages, so skip any
@@ -977,59 +976,6 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
977976
}
978977
}
979978

980-
/*
981-
* ppage: poisoned page
982-
* if p is regular page(4k page)
983-
* ppage == real poisoned page;
984-
* else p is hugetlb or THP, ppage == head page.
985-
*/
986-
ppage = hpage;
987-
988-
if (PageTransHuge(hpage)) {
989-
/*
990-
* Verify that this isn't a hugetlbfs head page, the check for
991-
* PageAnon is just for avoid tripping a split_huge_page
992-
* internal debug check, as split_huge_page refuses to deal with
993-
* anything that isn't an anon page. PageAnon can't go away fro
994-
* under us because we hold a refcount on the hpage, without a
995-
* refcount on the hpage. split_huge_page can't be safely called
996-
* in the first place, having a refcount on the tail isn't
997-
* enough * to be safe.
998-
*/
999-
if (!PageHuge(hpage) && PageAnon(hpage)) {
1000-
if (unlikely(split_huge_page(hpage))) {
1001-
/*
1002-
* FIXME: if splitting THP is failed, it is
1003-
* better to stop the following operation rather
1004-
* than causing panic by unmapping. System might
1005-
* survive if the page is freed later.
1006-
*/
1007-
printk(KERN_INFO
1008-
"MCE %#lx: failed to split THP\n", pfn);
1009-
1010-
BUG_ON(!PageHWPoison(p));
1011-
return SWAP_FAIL;
1012-
}
1013-
/*
1014-
* We pinned the head page for hwpoison handling,
1015-
* now we split the thp and we are interested in
1016-
* the hwpoisoned raw page, so move the refcount
1017-
* to it. Similarly, page lock is shifted.
1018-
*/
1019-
if (hpage != p) {
1020-
if (!(flags & MF_COUNT_INCREASED)) {
1021-
put_page(hpage);
1022-
get_page(p);
1023-
}
1024-
lock_page(p);
1025-
unlock_page(hpage);
1026-
*hpagep = p;
1027-
}
1028-
/* THP is split, so ppage should be the real poisoned page. */
1029-
ppage = p;
1030-
}
1031-
}
1032-
1033979
/*
1034980
* First collect all the processes that have the page
1035981
* mapped in dirty form. This has to be done before try_to_unmap,
@@ -1039,12 +985,12 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
1039985
* there's nothing that can be done.
1040986
*/
1041987
if (kill)
1042-
collect_procs(ppage, &tokill, flags & MF_ACTION_REQUIRED);
988+
collect_procs(hpage, &tokill, flags & MF_ACTION_REQUIRED);
1043989

1044-
ret = try_to_unmap(ppage, ttu);
990+
ret = try_to_unmap(hpage, ttu);
1045991
if (ret != SWAP_SUCCESS)
1046992
printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n",
1047-
pfn, page_mapcount(ppage));
993+
pfn, page_mapcount(hpage));
1048994

1049995
/*
1050996
* Now that the dirty bit has been propagated to the
@@ -1056,7 +1002,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
10561002
* use a more force-full uncatchable kill to prevent
10571003
* any accesses to the poisoned memory.
10581004
*/
1059-
forcekill = PageDirty(ppage) || (flags & MF_MUST_KILL);
1005+
forcekill = PageDirty(hpage) || (flags & MF_MUST_KILL);
10601006
kill_procs(&tokill, forcekill, trapno,
10611007
ret != SWAP_SUCCESS, p, pfn, flags);
10621008

@@ -1102,6 +1048,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
11021048
struct page_state *ps;
11031049
struct page *p;
11041050
struct page *hpage;
1051+
struct page *orig_head;
11051052
int res;
11061053
unsigned int nr_pages;
11071054
unsigned long page_flags;
@@ -1117,7 +1064,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
11171064
}
11181065

11191066
p = pfn_to_page(pfn);
1120-
hpage = compound_head(p);
1067+
orig_head = hpage = compound_head(p);
11211068
if (TestSetPageHWPoison(p)) {
11221069
printk(KERN_ERR "MCE %#lx: already hardware poisoned\n", pfn);
11231070
return 0;
@@ -1180,6 +1127,21 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
11801127
}
11811128
}
11821129

1130+
if (!PageHuge(p) && PageTransHuge(hpage)) {
1131+
if (!PageAnon(hpage)) {
1132+
pr_err("MCE: %#lx: non anonymous thp\n", pfn);
1133+
put_page(p);
1134+
return -EBUSY;
1135+
}
1136+
if (unlikely(split_huge_page(hpage))) {
1137+
pr_err("MCE: %#lx: thp split failed\n", pfn);
1138+
put_page(p);
1139+
return -EBUSY;
1140+
}
1141+
VM_BUG_ON_PAGE(!page_count(p), p);
1142+
hpage = compound_head(p);
1143+
}
1144+
11831145
/*
11841146
* We ignore non-LRU pages for good reasons.
11851147
* - PG_locked is only well defined for LRU pages and a few others
@@ -1189,9 +1151,9 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
11891151
* walked by the page reclaim code, however that's not a big loss.
11901152
*/
11911153
if (!PageHuge(p)) {
1192-
if (!PageLRU(hpage))
1193-
shake_page(hpage, 0);
1194-
if (!PageLRU(hpage)) {
1154+
if (!PageLRU(p))
1155+
shake_page(p, 0);
1156+
if (!PageLRU(p)) {
11951157
/*
11961158
* shake_page could have turned it free.
11971159
*/
@@ -1212,7 +1174,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
12121174
* The page could have changed compound pages during the locking.
12131175
* If this happens just bail out.
12141176
*/
1215-
if (compound_head(p) != hpage) {
1177+
if (PageCompound(p) && compound_head(p) != orig_head) {
12161178
action_result(pfn, MSG_DIFFERENT_COMPOUND, IGNORED);
12171179
res = -EBUSY;
12181180
goto out;

0 commit comments

Comments
 (0)