Skip to content

Commit 761ad8d

Browse files
Naoya Horiguchitorvalds
authored andcommitted
mm: hwpoison: introduce memory_failure_hugetlb()
memory_failure() is a big function and hard to maintain. Handling hugetlb- and non-hugetlb- case in a single function is not good, so this patch separates PageHuge() branch into a new function, which saves many PageHuge() check. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Naoya Horiguchi <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent d4a3a60 commit 761ad8d

File tree

1 file changed

+82
-52
lines changed

1 file changed

+82
-52
lines changed

mm/memory-failure.c

Lines changed: 82 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,76 @@ static bool hwpoison_user_mappings(struct page *p, unsigned long pfn,
10091009
return unmap_success;
10101010
}
10111011

1012+
static int memory_failure_hugetlb(unsigned long pfn, int trapno, int flags)
1013+
{
1014+
struct page_state *ps;
1015+
struct page *p = pfn_to_page(pfn);
1016+
struct page *head = compound_head(p);
1017+
int res;
1018+
unsigned long page_flags;
1019+
1020+
if (TestSetPageHWPoison(head)) {
1021+
pr_err("Memory failure: %#lx: already hardware poisoned\n",
1022+
pfn);
1023+
return 0;
1024+
}
1025+
1026+
num_poisoned_pages_inc();
1027+
1028+
if (!(flags & MF_COUNT_INCREASED) && !get_hwpoison_page(p)) {
1029+
/*
1030+
* Check "filter hit" and "race with other subpage."
1031+
*/
1032+
lock_page(head);
1033+
if (PageHWPoison(head)) {
1034+
if ((hwpoison_filter(p) && TestClearPageHWPoison(p))
1035+
|| (p != head && TestSetPageHWPoison(head))) {
1036+
num_poisoned_pages_dec();
1037+
unlock_page(head);
1038+
return 0;
1039+
}
1040+
}
1041+
unlock_page(head);
1042+
dissolve_free_huge_page(p);
1043+
action_result(pfn, MF_MSG_FREE_HUGE, MF_DELAYED);
1044+
return 0;
1045+
}
1046+
1047+
lock_page(head);
1048+
page_flags = head->flags;
1049+
1050+
if (!PageHWPoison(head)) {
1051+
pr_err("Memory failure: %#lx: just unpoisoned\n", pfn);
1052+
num_poisoned_pages_dec();
1053+
unlock_page(head);
1054+
put_hwpoison_page(head);
1055+
return 0;
1056+
}
1057+
1058+
if (!hwpoison_user_mappings(p, pfn, trapno, flags, &head)) {
1059+
action_result(pfn, MF_MSG_UNMAP_FAILED, MF_IGNORED);
1060+
res = -EBUSY;
1061+
goto out;
1062+
}
1063+
1064+
res = -EBUSY;
1065+
1066+
for (ps = error_states;; ps++)
1067+
if ((p->flags & ps->mask) == ps->res)
1068+
break;
1069+
1070+
page_flags |= (p->flags & (1UL << PG_dirty));
1071+
1072+
if (!ps->mask)
1073+
for (ps = error_states;; ps++)
1074+
if ((page_flags & ps->mask) == ps->res)
1075+
break;
1076+
res = page_action(ps, p, pfn);
1077+
out:
1078+
unlock_page(head);
1079+
return res;
1080+
}
1081+
10121082
/**
10131083
* memory_failure - Handle memory failure of a page.
10141084
* @pfn: Page Number of the corrupted page
@@ -1046,33 +1116,22 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
10461116
}
10471117

10481118
p = pfn_to_page(pfn);
1049-
orig_head = hpage = compound_head(p);
1050-
1051-
/* tmporary check code, to be updated in later patches */
1052-
if (PageHuge(p)) {
1053-
if (TestSetPageHWPoison(hpage)) {
1054-
pr_err("Memory failure: %#lx: already hardware poisoned\n", pfn);
1055-
return 0;
1056-
}
1057-
goto tmp;
1058-
}
1119+
if (PageHuge(p))
1120+
return memory_failure_hugetlb(pfn, trapno, flags);
10591121
if (TestSetPageHWPoison(p)) {
10601122
pr_err("Memory failure: %#lx: already hardware poisoned\n",
10611123
pfn);
10621124
return 0;
10631125
}
10641126

1065-
tmp:
1127+
orig_head = hpage = compound_head(p);
10661128
num_poisoned_pages_inc();
10671129

10681130
/*
10691131
* We need/can do nothing about count=0 pages.
10701132
* 1) it's a free page, and therefore in safe hand:
10711133
* prep_new_page() will be the gate keeper.
1072-
* 2) it's a free hugepage, which is also safe:
1073-
* an affected hugepage will be dequeued from hugepage freelist,
1074-
* so there's no concern about reusing it ever after.
1075-
* 3) it's part of a non-compound high order page.
1134+
* 2) it's part of a non-compound high order page.
10761135
* Implies some kernel user: cannot stop them from
10771136
* R/W the page; let's pray that the page has been
10781137
* used and will be freed some time later.
@@ -1083,31 +1142,13 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
10831142
if (is_free_buddy_page(p)) {
10841143
action_result(pfn, MF_MSG_BUDDY, MF_DELAYED);
10851144
return 0;
1086-
} else if (PageHuge(hpage)) {
1087-
/*
1088-
* Check "filter hit" and "race with other subpage."
1089-
*/
1090-
lock_page(hpage);
1091-
if (PageHWPoison(hpage)) {
1092-
if ((hwpoison_filter(p) && TestClearPageHWPoison(p))
1093-
|| (p != hpage && TestSetPageHWPoison(hpage))) {
1094-
num_poisoned_pages_dec();
1095-
unlock_page(hpage);
1096-
return 0;
1097-
}
1098-
}
1099-
res = dequeue_hwpoisoned_huge_page(hpage);
1100-
action_result(pfn, MF_MSG_FREE_HUGE,
1101-
res ? MF_IGNORED : MF_DELAYED);
1102-
unlock_page(hpage);
1103-
return res;
11041145
} else {
11051146
action_result(pfn, MF_MSG_KERNEL_HIGH_ORDER, MF_IGNORED);
11061147
return -EBUSY;
11071148
}
11081149
}
11091150

1110-
if (!PageHuge(p) && PageTransHuge(hpage)) {
1151+
if (PageTransHuge(hpage)) {
11111152
lock_page(p);
11121153
if (!PageAnon(p) || unlikely(split_huge_page(p))) {
11131154
unlock_page(p);
@@ -1145,7 +1186,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
11451186
return 0;
11461187
}
11471188

1148-
lock_page(hpage);
1189+
lock_page(p);
11491190

11501191
/*
11511192
* The page could have changed compound pages during the locking.
@@ -1175,32 +1216,21 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
11751216
if (!PageHWPoison(p)) {
11761217
pr_err("Memory failure: %#lx: just unpoisoned\n", pfn);
11771218
num_poisoned_pages_dec();
1178-
unlock_page(hpage);
1179-
put_hwpoison_page(hpage);
1219+
unlock_page(p);
1220+
put_hwpoison_page(p);
11801221
return 0;
11811222
}
11821223
if (hwpoison_filter(p)) {
11831224
if (TestClearPageHWPoison(p))
11841225
num_poisoned_pages_dec();
1185-
unlock_page(hpage);
1186-
put_hwpoison_page(hpage);
1226+
unlock_page(p);
1227+
put_hwpoison_page(p);
11871228
return 0;
11881229
}
11891230

1190-
if (!PageHuge(p) && !PageTransTail(p) && !PageLRU(p))
1231+
if (!PageTransTail(p) && !PageLRU(p))
11911232
goto identify_page_state;
11921233

1193-
/*
1194-
* For error on the tail page, we should set PG_hwpoison
1195-
* on the head page to show that the hugepage is hwpoisoned
1196-
*/
1197-
if (PageHuge(p) && PageTail(p) && TestSetPageHWPoison(hpage)) {
1198-
action_result(pfn, MF_MSG_POISONED_HUGE, MF_IGNORED);
1199-
unlock_page(hpage);
1200-
put_hwpoison_page(hpage);
1201-
return 0;
1202-
}
1203-
12041234
/*
12051235
* It's very difficult to mess with pages currently under IO
12061236
* and in many cases impossible, so we just avoid it here.
@@ -1248,7 +1278,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
12481278
break;
12491279
res = page_action(ps, p, pfn);
12501280
out:
1251-
unlock_page(hpage);
1281+
unlock_page(p);
12521282
return res;
12531283
}
12541284
EXPORT_SYMBOL_GPL(memory_failure);

0 commit comments

Comments
 (0)