aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-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 e4683459ab26..8f13b26a5b93 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1021,6 +1021,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
1021 struct page *hpage; 1021 struct page *hpage;
1022 int res; 1022 int res;
1023 unsigned int nr_pages; 1023 unsigned int nr_pages;
1024 unsigned long page_flags;
1024 1025
1025 if (!sysctl_memory_failure_recovery) 1026 if (!sysctl_memory_failure_recovery)
1026 panic("Memory failure from trap %d on page %lx", trapno, pfn); 1027 panic("Memory failure from trap %d on page %lx", trapno, pfn);
@@ -1129,6 +1130,15 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
1129 lock_page(hpage); 1130 lock_page(hpage);
1130 1131
1131 /* 1132 /*
1133 * We use page flags to determine what action should be taken, but
1134 * the flags can be modified by the error containment action. One
1135 * example is an mlocked page, where PG_mlocked is cleared by
1136 * page_remove_rmap() in try_to_unmap_one(). So to determine page status
1137 * correctly, we save a copy of the page flags at this time.
1138 */
1139 page_flags = p->flags;
1140
1141 /*
1132 * unpoison always clear PG_hwpoison inside page lock 1142 * unpoison always clear PG_hwpoison inside page lock
1133 */ 1143 */
1134 if (!PageHWPoison(p)) { 1144 if (!PageHWPoison(p)) {
@@ -1186,12 +1196,19 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
1186 } 1196 }
1187 1197
1188 res = -EBUSY; 1198 res = -EBUSY;
1189 for (ps = error_states;; ps++) { 1199 /*
1190 if ((p->flags & ps->mask) == ps->res) { 1200 * The first check uses the current page flags which may not have any
1191 res = page_action(ps, p, pfn); 1201 * relevant information. The second check with the saved page flagss is
1202 * carried out only if the first check can't determine the page status.
1203 */
1204 for (ps = error_states;; ps++)
1205 if ((p->flags & ps->mask) == ps->res)
1192 break; 1206 break;
1193 } 1207 if (!ps->mask)
1194 } 1208 for (ps = error_states;; ps++)
1209 if ((page_flags & ps->mask) == ps->res)
1210 break;
1211 res = page_action(ps, p, pfn);
1195out: 1212out:
1196 unlock_page(hpage); 1213 unlock_page(hpage);
1197 return res; 1214 return res;