1 From 6751ed65dc6642af64f7b8a440a75563c8aab7ae Mon Sep 17 00:00:00 2001
2 From: Tony Luck <tony.luck@intel.com>
3 Date: Wed, 11 Jul 2012 10:20:47 -0700
4 Subject: x86/mce: Fix siginfo_t->si_addr value for non-recoverable memory faults
6 From: Tony Luck <tony.luck@intel.com>
8 commit 6751ed65dc6642af64f7b8a440a75563c8aab7ae upstream.
10 In commit dad1743e5993f1 ("x86/mce: Only restart instruction after machine
11 check recovery if it is safe") we fixed mce_notify_process() to force a
12 signal to the current process if it was not restartable (RIPV bit not
13 set in MCG_STATUS). But doing it here means that the process doesn't
14 get told the virtual address of the fault via siginfo_t->si_addr. This
15 would prevent application level recovery from the fault.
17 Make a new MF_MUST_KILL flag bit for memory_failure() et al. to use so
18 that we will provide the right information with the signal.
20 Signed-off-by: Tony Luck <tony.luck@intel.com>
21 Acked-by: Borislav Petkov <borislav.petkov@amd.com>
22 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
25 arch/x86/kernel/cpu/mcheck/mce.c | 6 ++++--
26 include/linux/mm.h | 1 +
27 mm/memory-failure.c | 14 ++++++++------
28 3 files changed, 13 insertions(+), 8 deletions(-)
30 --- a/arch/x86/kernel/cpu/mcheck/mce.c
31 +++ b/arch/x86/kernel/cpu/mcheck/mce.c
32 @@ -1186,6 +1186,7 @@ void mce_notify_process(void)
35 struct mce_info *mi = mce_find_info();
36 + int flags = MF_ACTION_REQUIRED;
39 mce_panic("Lost physical address for unconsumed uncorrectable error", NULL, NULL);
40 @@ -1200,8 +1201,9 @@ void mce_notify_process(void)
41 * doomed. We still need to mark the page as poisoned and alert any
42 * other users of the page.
44 - if (memory_failure(pfn, MCE_VECTOR, MF_ACTION_REQUIRED) < 0 ||
45 - mi->restartable == 0) {
46 + if (!mi->restartable)
47 + flags |= MF_MUST_KILL;
48 + if (memory_failure(pfn, MCE_VECTOR, flags) < 0) {
49 pr_err("Memory error not recovered");
50 force_sig(SIGBUS, current);
52 --- a/include/linux/mm.h
53 +++ b/include/linux/mm.h
54 @@ -1591,6 +1591,7 @@ void vmemmap_populate_print_last(void);
56 MF_COUNT_INCREASED = 1 << 0,
57 MF_ACTION_REQUIRED = 1 << 1,
58 + MF_MUST_KILL = 1 << 2,
60 extern int memory_failure(unsigned long pfn, int trapno, int flags);
61 extern void memory_failure_queue(unsigned long pfn, int trapno, int flags);
62 --- a/mm/memory-failure.c
63 +++ b/mm/memory-failure.c
64 @@ -345,14 +345,14 @@ static void add_to_kill(struct task_stru
65 * Also when FAIL is set do a force kill because something went
68 -static void kill_procs(struct list_head *to_kill, int doit, int trapno,
69 +static void kill_procs(struct list_head *to_kill, int forcekill, int trapno,
70 int fail, struct page *page, unsigned long pfn,
73 struct to_kill *tk, *next;
75 list_for_each_entry_safe (tk, next, to_kill, nd) {
79 * In case something went wrong with munmapping
80 * make sure the process doesn't catch the
81 @@ -858,7 +858,7 @@ static int hwpoison_user_mappings(struct
82 struct address_space *mapping;
86 + int kill = 1, forcekill;
87 struct page *hpage = compound_head(p);
90 @@ -888,7 +888,7 @@ static int hwpoison_user_mappings(struct
91 * be called inside page lock (it's recommended but not enforced).
93 mapping = page_mapping(hpage);
94 - if (!PageDirty(hpage) && mapping &&
95 + if (!(flags & MF_MUST_KILL) && !PageDirty(hpage) && mapping &&
96 mapping_cap_writeback_dirty(mapping)) {
97 if (page_mkclean(hpage)) {
99 @@ -965,12 +965,14 @@ static int hwpoison_user_mappings(struct
100 * Now that the dirty bit has been propagated to the
101 * struct page and all unmaps done we can decide if
102 * killing is needed or not. Only kill when the page
103 - * was dirty, otherwise the tokill list is merely
104 + * was dirty or the process is not restartable,
105 + * otherwise the tokill list is merely
106 * freed. When there was a problem unmapping earlier
107 * use a more force-full uncatchable kill to prevent
108 * any accesses to the poisoned memory.
110 - kill_procs(&tokill, !!PageDirty(ppage), trapno,
111 + forcekill = PageDirty(ppage) || (flags & MF_MUST_KILL);
112 + kill_procs(&tokill, forcekill, trapno,
113 ret != SWAP_SUCCESS, p, pfn, flags);