aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/mm/fault.c')
-rw-r--r--arch/x86/mm/fault.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 79b0b372d2d0..852b319edbdc 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
161static void 162static void
162force_sig_info_fault(int si_signo, int si_code, unsigned long address, 163force_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}
@@ -722,7 +728,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
722 tsk->thread.error_code = error_code | (address >= TASK_SIZE); 728 tsk->thread.error_code = error_code | (address >= TASK_SIZE);
723 tsk->thread.trap_no = 14; 729 tsk->thread.trap_no = 14;
724 730
725 force_sig_info_fault(SIGSEGV, si_code, address, tsk); 731 force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0);
726 732
727 return; 733 return;
728 } 734 }
@@ -807,14 +813,14 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
807 tsk->thread.trap_no = 14; 813 tsk->thread.trap_no = 14;
808 814
809#ifdef CONFIG_MEMORY_FAILURE 815#ifdef CONFIG_MEMORY_FAILURE
810 if (fault & VM_FAULT_HWPOISON) { 816 if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
811 printk(KERN_ERR 817 printk(KERN_ERR
812 "MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n", 818 "MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n",
813 tsk->comm, tsk->pid, address); 819 tsk->comm, tsk->pid, address);
814 code = BUS_MCEERR_AR; 820 code = BUS_MCEERR_AR;
815 } 821 }
816#endif 822#endif
817 force_sig_info_fault(SIGBUS, code, address, tsk); 823 force_sig_info_fault(SIGBUS, code, address, tsk, fault);
818} 824}
819 825
820static noinline void 826static noinline void
@@ -824,7 +830,8 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
824 if (fault & VM_FAULT_OOM) { 830 if (fault & VM_FAULT_OOM) {
825 out_of_memory(regs, error_code, address); 831 out_of_memory(regs, error_code, address);
826 } else { 832 } else {
827 if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON)) 833 if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
834 VM_FAULT_HWPOISON_LARGE))
828 do_sigbus(regs, error_code, address, fault); 835 do_sigbus(regs, error_code, address, fault);
829 else 836 else
830 BUG(); 837 BUG();