diff options
author | Tony Luck <tony.luck@intel.com> | 2012-07-11 13:20:47 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2012-07-11 13:20:47 -0400 |
commit | 6751ed65dc6642af64f7b8a440a75563c8aab7ae (patch) | |
tree | 8736d4c2b3aa00c6a4f39d2e6cba4805720c2874 | |
parent | 6887a4131da3adaab011613776d865f4bcfb5678 (diff) |
x86/mce: Fix siginfo_t->si_addr value for non-recoverable memory faults
In commit dad1743e5993f1 ("x86/mce: Only restart instruction after machine
check recovery if it is safe") we fixed mce_notify_process() to force a
signal to the current process if it was not restartable (RIPV bit not
set in MCG_STATUS). But doing it here means that the process doesn't
get told the virtual address of the fault via siginfo_t->si_addr. This
would prevent application level recovery from the fault.
Make a new MF_MUST_KILL flag bit for memory_failure() et al. to use so
that we will provide the right information with the signal.
Signed-off-by: Tony Luck <tony.luck@intel.com>
Acked-by: Borislav Petkov <borislav.petkov@amd.com>
Cc: stable@kernel.org # 3.4+
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 6 | ||||
-rw-r--r-- | include/linux/mm.h | 1 | ||||
-rw-r--r-- | mm/memory-failure.c | 14 |
3 files changed, 13 insertions, 8 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index da27c5d2168..c46ed494f00 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -1186,6 +1186,7 @@ void mce_notify_process(void) | |||
1186 | { | 1186 | { |
1187 | unsigned long pfn; | 1187 | unsigned long pfn; |
1188 | struct mce_info *mi = mce_find_info(); | 1188 | struct mce_info *mi = mce_find_info(); |
1189 | int flags = MF_ACTION_REQUIRED; | ||
1189 | 1190 | ||
1190 | if (!mi) | 1191 | if (!mi) |
1191 | mce_panic("Lost physical address for unconsumed uncorrectable error", NULL, NULL); | 1192 | mce_panic("Lost physical address for unconsumed uncorrectable error", NULL, NULL); |
@@ -1200,8 +1201,9 @@ void mce_notify_process(void) | |||
1200 | * doomed. We still need to mark the page as poisoned and alert any | 1201 | * doomed. We still need to mark the page as poisoned and alert any |
1201 | * other users of the page. | 1202 | * other users of the page. |
1202 | */ | 1203 | */ |
1203 | if (memory_failure(pfn, MCE_VECTOR, MF_ACTION_REQUIRED) < 0 || | 1204 | if (!mi->restartable) |
1204 | mi->restartable == 0) { | 1205 | flags |= MF_MUST_KILL; |
1206 | if (memory_failure(pfn, MCE_VECTOR, flags) < 0) { | ||
1205 | pr_err("Memory error not recovered"); | 1207 | pr_err("Memory error not recovered"); |
1206 | force_sig(SIGBUS, current); | 1208 | force_sig(SIGBUS, current); |
1207 | } | 1209 | } |
diff --git a/include/linux/mm.h b/include/linux/mm.h index b36d08ce5c5..f9f279cf5b1 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -1591,6 +1591,7 @@ void vmemmap_populate_print_last(void); | |||
1591 | enum mf_flags { | 1591 | enum mf_flags { |
1592 | MF_COUNT_INCREASED = 1 << 0, | 1592 | MF_COUNT_INCREASED = 1 << 0, |
1593 | MF_ACTION_REQUIRED = 1 << 1, | 1593 | MF_ACTION_REQUIRED = 1 << 1, |
1594 | MF_MUST_KILL = 1 << 2, | ||
1594 | }; | 1595 | }; |
1595 | extern int memory_failure(unsigned long pfn, int trapno, int flags); | 1596 | extern int memory_failure(unsigned long pfn, int trapno, int flags); |
1596 | extern void memory_failure_queue(unsigned long pfn, int trapno, int flags); | 1597 | extern void memory_failure_queue(unsigned long pfn, int trapno, int flags); |
diff --git a/mm/memory-failure.c b/mm/memory-failure.c index ab1e7145e29..de4ce705845 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c | |||
@@ -345,14 +345,14 @@ static void add_to_kill(struct task_struct *tsk, struct page *p, | |||
345 | * Also when FAIL is set do a force kill because something went | 345 | * Also when FAIL is set do a force kill because something went |
346 | * wrong earlier. | 346 | * wrong earlier. |
347 | */ | 347 | */ |
348 | static void kill_procs(struct list_head *to_kill, int doit, int trapno, | 348 | static void kill_procs(struct list_head *to_kill, int forcekill, int trapno, |
349 | int fail, struct page *page, unsigned long pfn, | 349 | int fail, struct page *page, unsigned long pfn, |
350 | int flags) | 350 | int flags) |
351 | { | 351 | { |
352 | struct to_kill *tk, *next; | 352 | struct to_kill *tk, *next; |
353 | 353 | ||
354 | list_for_each_entry_safe (tk, next, to_kill, nd) { | 354 | list_for_each_entry_safe (tk, next, to_kill, nd) { |
355 | if (doit) { | 355 | if (forcekill) { |
356 | /* | 356 | /* |
357 | * In case something went wrong with munmapping | 357 | * In case something went wrong with munmapping |
358 | * make sure the process doesn't catch the | 358 | * make sure the process doesn't catch the |
@@ -858,7 +858,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
858 | struct address_space *mapping; | 858 | struct address_space *mapping; |
859 | LIST_HEAD(tokill); | 859 | LIST_HEAD(tokill); |
860 | int ret; | 860 | int ret; |
861 | int kill = 1; | 861 | int kill = 1, forcekill; |
862 | struct page *hpage = compound_head(p); | 862 | struct page *hpage = compound_head(p); |
863 | struct page *ppage; | 863 | struct page *ppage; |
864 | 864 | ||
@@ -888,7 +888,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
888 | * be called inside page lock (it's recommended but not enforced). | 888 | * be called inside page lock (it's recommended but not enforced). |
889 | */ | 889 | */ |
890 | mapping = page_mapping(hpage); | 890 | mapping = page_mapping(hpage); |
891 | if (!PageDirty(hpage) && mapping && | 891 | if (!(flags & MF_MUST_KILL) && !PageDirty(hpage) && mapping && |
892 | mapping_cap_writeback_dirty(mapping)) { | 892 | mapping_cap_writeback_dirty(mapping)) { |
893 | if (page_mkclean(hpage)) { | 893 | if (page_mkclean(hpage)) { |
894 | SetPageDirty(hpage); | 894 | SetPageDirty(hpage); |
@@ -965,12 +965,14 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
965 | * Now that the dirty bit has been propagated to the | 965 | * Now that the dirty bit has been propagated to the |
966 | * struct page and all unmaps done we can decide if | 966 | * struct page and all unmaps done we can decide if |
967 | * killing is needed or not. Only kill when the page | 967 | * killing is needed or not. Only kill when the page |
968 | * was dirty, otherwise the tokill list is merely | 968 | * was dirty or the process is not restartable, |
969 | * otherwise the tokill list is merely | ||
969 | * freed. When there was a problem unmapping earlier | 970 | * freed. When there was a problem unmapping earlier |
970 | * use a more force-full uncatchable kill to prevent | 971 | * use a more force-full uncatchable kill to prevent |
971 | * any accesses to the poisoned memory. | 972 | * any accesses to the poisoned memory. |
972 | */ | 973 | */ |
973 | kill_procs(&tokill, !!PageDirty(ppage), trapno, | 974 | forcekill = PageDirty(ppage) || (flags & MF_MUST_KILL); |
975 | kill_procs(&tokill, forcekill, trapno, | ||
974 | ret != SWAP_SUCCESS, p, pfn, flags); | 976 | ret != SWAP_SUCCESS, p, pfn, flags); |
975 | 977 | ||
976 | return ret; | 978 | return ret; |