diff options
author | Andi Kleen <andi@firstfloor.org> | 2009-09-16 05:50:09 -0400 |
---|---|---|
committer | Andi Kleen <ak@linux.intel.com> | 2009-09-16 05:50:09 -0400 |
commit | a6e04aa92965565968573a220a35b4e907385697 (patch) | |
tree | a8f49a97247a0ee14a1442ea2ee4719001785fc7 /arch/x86/mm/fault.c | |
parent | a3b947eacfe783df4ca0fe53ef8a764eebc2d0d6 (diff) |
HWPOISON: x86: Add VM_FAULT_HWPOISON handling to x86 page fault handler v2
Add VM_FAULT_HWPOISON handling to the x86 page fault handler. This is
very similar to VM_FAULT_OOM, the only difference is that a different
si_code is passed to user space and the new addr_lsb field is initialized.
v2: Make the printk more verbose/unique
Cc: x86@kernel.org
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Diffstat (limited to 'arch/x86/mm/fault.c')
-rw-r--r-- | arch/x86/mm/fault.c | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 775a020990a5..8ba562408200 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -167,6 +167,7 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address, | |||
167 | info.si_errno = 0; | 167 | info.si_errno = 0; |
168 | info.si_code = si_code; | 168 | info.si_code = si_code; |
169 | info.si_addr = (void __user *)address; | 169 | info.si_addr = (void __user *)address; |
170 | info.si_addr_lsb = si_code == BUS_MCEERR_AR ? PAGE_SHIFT : 0; | ||
170 | 171 | ||
171 | force_sig_info(si_signo, &info, tsk); | 172 | force_sig_info(si_signo, &info, tsk); |
172 | } | 173 | } |
@@ -790,10 +791,12 @@ out_of_memory(struct pt_regs *regs, unsigned long error_code, | |||
790 | } | 791 | } |
791 | 792 | ||
792 | static void | 793 | static void |
793 | do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address) | 794 | do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, |
795 | unsigned int fault) | ||
794 | { | 796 | { |
795 | struct task_struct *tsk = current; | 797 | struct task_struct *tsk = current; |
796 | struct mm_struct *mm = tsk->mm; | 798 | struct mm_struct *mm = tsk->mm; |
799 | int code = BUS_ADRERR; | ||
797 | 800 | ||
798 | up_read(&mm->mmap_sem); | 801 | up_read(&mm->mmap_sem); |
799 | 802 | ||
@@ -809,7 +812,15 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address) | |||
809 | tsk->thread.error_code = error_code; | 812 | tsk->thread.error_code = error_code; |
810 | tsk->thread.trap_no = 14; | 813 | tsk->thread.trap_no = 14; |
811 | 814 | ||
812 | force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk); | 815 | #ifdef CONFIG_MEMORY_FAILURE |
816 | if (fault & VM_FAULT_HWPOISON) { | ||
817 | printk(KERN_ERR | ||
818 | "MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n", | ||
819 | tsk->comm, tsk->pid, address); | ||
820 | code = BUS_MCEERR_AR; | ||
821 | } | ||
822 | #endif | ||
823 | force_sig_info_fault(SIGBUS, code, address, tsk); | ||
813 | } | 824 | } |
814 | 825 | ||
815 | static noinline void | 826 | static noinline void |
@@ -819,8 +830,8 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code, | |||
819 | if (fault & VM_FAULT_OOM) { | 830 | if (fault & VM_FAULT_OOM) { |
820 | out_of_memory(regs, error_code, address); | 831 | out_of_memory(regs, error_code, address); |
821 | } else { | 832 | } else { |
822 | if (fault & VM_FAULT_SIGBUS) | 833 | if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON)) |
823 | do_sigbus(regs, error_code, address); | 834 | do_sigbus(regs, error_code, address, fault); |
824 | else | 835 | else |
825 | BUG(); | 836 | BUG(); |
826 | } | 837 | } |