aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Luck <tony.luck@intel.com>2012-07-11 13:20:47 -0400
committerTony Luck <tony.luck@intel.com>2012-07-11 13:20:47 -0400
commit6751ed65dc6642af64f7b8a440a75563c8aab7ae (patch)
tree8736d4c2b3aa00c6a4f39d2e6cba4805720c2874
parent6887a4131da3adaab011613776d865f4bcfb5678 (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.c6
-rw-r--r--include/linux/mm.h1
-rw-r--r--mm/memory-failure.c14
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);
1591enum mf_flags { 1591enum 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};
1595extern int memory_failure(unsigned long pfn, int trapno, int flags); 1596extern int memory_failure(unsigned long pfn, int trapno, int flags);
1596extern void memory_failure_queue(unsigned long pfn, int trapno, int flags); 1597extern 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 */
348static void kill_procs(struct list_head *to_kill, int doit, int trapno, 348static 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;