diff options
author | Andi Kleen <ak@linux.intel.com> | 2010-09-27 16:05:55 -0400 |
---|---|---|
committer | Andi Kleen <ak@linux.intel.com> | 2010-10-08 03:32:46 -0400 |
commit | f672b49b07a4a152fc4251f2aec6b4d05164c4cd (patch) | |
tree | f2d6ded63009c344dacdc8b138ade6e8fe1ba5db | |
parent | aa50d3a7aa8147b9e14dc9d5972a5d2359db4ef8 (diff) |
x86: HWPOISON: Report correct address granuality for huge hwpoison faults
An earlier patch fixed the hwpoison fault handling to encode the
huge page size in the fault code of the page fault handler.
This is needed to report this information in SIGBUS to user space.
This is a straight forward patch to pass this information
through to the signal handling in the x86 specific fault.c
Cc: x86@kernel.org
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: fengguang.wu@intel.com
Signed-off-by: Andi Kleen <ak@linux.intel.com>
-rw-r--r-- | arch/x86/mm/fault.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 4c4508e8a204..1d15a27dd6ff 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/kprobes.h> /* __kprobes, ... */ | 11 | #include <linux/kprobes.h> /* __kprobes, ... */ |
12 | #include <linux/mmiotrace.h> /* kmmio_handler, ... */ | 12 | #include <linux/mmiotrace.h> /* kmmio_handler, ... */ |
13 | #include <linux/perf_event.h> /* perf_sw_event */ | 13 | #include <linux/perf_event.h> /* perf_sw_event */ |
14 | #include <linux/hugetlb.h> /* hstate_index_to_shift */ | ||
14 | 15 | ||
15 | #include <asm/traps.h> /* dotraplinkage, ... */ | 16 | #include <asm/traps.h> /* dotraplinkage, ... */ |
16 | #include <asm/pgalloc.h> /* pgd_*(), ... */ | 17 | #include <asm/pgalloc.h> /* pgd_*(), ... */ |
@@ -160,15 +161,20 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr) | |||
160 | 161 | ||
161 | static void | 162 | static void |
162 | force_sig_info_fault(int si_signo, int si_code, unsigned long address, | 163 | force_sig_info_fault(int si_signo, int si_code, unsigned long address, |
163 | struct task_struct *tsk) | 164 | struct task_struct *tsk, int fault) |
164 | { | 165 | { |
166 | unsigned lsb = 0; | ||
165 | siginfo_t info; | 167 | siginfo_t info; |
166 | 168 | ||
167 | info.si_signo = si_signo; | 169 | info.si_signo = si_signo; |
168 | info.si_errno = 0; | 170 | info.si_errno = 0; |
169 | info.si_code = si_code; | 171 | info.si_code = si_code; |
170 | info.si_addr = (void __user *)address; | 172 | info.si_addr = (void __user *)address; |
171 | info.si_addr_lsb = si_code == BUS_MCEERR_AR ? PAGE_SHIFT : 0; | 173 | if (fault & VM_FAULT_HWPOISON_LARGE) |
174 | lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); | ||
175 | if (fault & VM_FAULT_HWPOISON) | ||
176 | lsb = PAGE_SHIFT; | ||
177 | info.si_addr_lsb = lsb; | ||
172 | 178 | ||
173 | force_sig_info(si_signo, &info, tsk); | 179 | force_sig_info(si_signo, &info, tsk); |
174 | } | 180 | } |
@@ -731,7 +737,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, | |||
731 | tsk->thread.error_code = error_code | (address >= TASK_SIZE); | 737 | tsk->thread.error_code = error_code | (address >= TASK_SIZE); |
732 | tsk->thread.trap_no = 14; | 738 | tsk->thread.trap_no = 14; |
733 | 739 | ||
734 | force_sig_info_fault(SIGSEGV, si_code, address, tsk); | 740 | force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0); |
735 | 741 | ||
736 | return; | 742 | return; |
737 | } | 743 | } |
@@ -816,14 +822,14 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, | |||
816 | tsk->thread.trap_no = 14; | 822 | tsk->thread.trap_no = 14; |
817 | 823 | ||
818 | #ifdef CONFIG_MEMORY_FAILURE | 824 | #ifdef CONFIG_MEMORY_FAILURE |
819 | if (fault & VM_FAULT_HWPOISON) { | 825 | if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) { |
820 | printk(KERN_ERR | 826 | printk(KERN_ERR |
821 | "MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n", | 827 | "MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n", |
822 | tsk->comm, tsk->pid, address); | 828 | tsk->comm, tsk->pid, address); |
823 | code = BUS_MCEERR_AR; | 829 | code = BUS_MCEERR_AR; |
824 | } | 830 | } |
825 | #endif | 831 | #endif |
826 | force_sig_info_fault(SIGBUS, code, address, tsk); | 832 | force_sig_info_fault(SIGBUS, code, address, tsk, fault); |
827 | } | 833 | } |
828 | 834 | ||
829 | static noinline void | 835 | static noinline void |
@@ -833,7 +839,8 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code, | |||
833 | if (fault & VM_FAULT_OOM) { | 839 | if (fault & VM_FAULT_OOM) { |
834 | out_of_memory(regs, error_code, address); | 840 | out_of_memory(regs, error_code, address); |
835 | } else { | 841 | } else { |
836 | if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON)) | 842 | if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON| |
843 | VM_FAULT_HWPOISON_LARGE)) | ||
837 | do_sigbus(regs, error_code, address, fault); | 844 | do_sigbus(regs, error_code, address, fault); |
838 | else | 845 | else |
839 | BUG(); | 846 | BUG(); |