parisc: Add HWPOISON page fault handler code
Commit 24587380f6
("parisc: Add MADV_HWPOISON and MADV_SOFT_OFFLINE") added
the necessary constants to handle hardware-poisoning. Those were needed to
support the page deallocation feature from firmware.
But I completely missed to add the relevant fault handler code. This now
showed up when I ran the madvise07 testcase from the Linux Test Project,
which failed with a kernel BUG at arch/parisc/mm/fault.c:320.
With this patch the parisc kernel now behaves like other platforms and
gives the same kernel syslog warnings when poisoning pages.
Signed-off-by: Helge Deller <deller@gmx.de>
This commit is contained in:
parent
a7e6601f70
commit
606f95e425
|
@ -17,6 +17,7 @@
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/extable.h>
|
#include <linux/extable.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/hugetlb.h>
|
||||||
|
|
||||||
#include <asm/traps.h>
|
#include <asm/traps.h>
|
||||||
|
|
||||||
|
@ -261,7 +262,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
|
||||||
struct task_struct *tsk;
|
struct task_struct *tsk;
|
||||||
struct mm_struct *mm;
|
struct mm_struct *mm;
|
||||||
unsigned long acc_type;
|
unsigned long acc_type;
|
||||||
int fault;
|
int fault = 0;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
|
||||||
if (faulthandler_disabled())
|
if (faulthandler_disabled())
|
||||||
|
@ -315,7 +316,8 @@ good_area:
|
||||||
goto out_of_memory;
|
goto out_of_memory;
|
||||||
else if (fault & VM_FAULT_SIGSEGV)
|
else if (fault & VM_FAULT_SIGSEGV)
|
||||||
goto bad_area;
|
goto bad_area;
|
||||||
else if (fault & VM_FAULT_SIGBUS)
|
else if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
|
||||||
|
VM_FAULT_HWPOISON_LARGE))
|
||||||
goto bad_area;
|
goto bad_area;
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
@ -352,8 +354,7 @@ bad_area:
|
||||||
|
|
||||||
if (user_mode(regs)) {
|
if (user_mode(regs)) {
|
||||||
struct siginfo si;
|
struct siginfo si;
|
||||||
|
unsigned int lsb = 0;
|
||||||
show_signal_msg(regs, code, address, tsk, vma);
|
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 15: /* Data TLB miss fault/Data page fault */
|
case 15: /* Data TLB miss fault/Data page fault */
|
||||||
|
@ -386,6 +387,30 @@ bad_area:
|
||||||
si.si_code = (code == 26) ? SEGV_ACCERR : SEGV_MAPERR;
|
si.si_code = (code == 26) ? SEGV_ACCERR : SEGV_MAPERR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_MEMORY_FAILURE
|
||||||
|
if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
|
||||||
|
printk(KERN_ERR
|
||||||
|
"MCE: Killing %s:%d due to hardware memory corruption fault at %08lx\n",
|
||||||
|
tsk->comm, tsk->pid, address);
|
||||||
|
si.si_signo = SIGBUS;
|
||||||
|
si.si_code = BUS_MCEERR_AR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Either small page or large page may be poisoned.
|
||||||
|
* In other words, VM_FAULT_HWPOISON_LARGE and
|
||||||
|
* VM_FAULT_HWPOISON are mutually exclusive.
|
||||||
|
*/
|
||||||
|
if (fault & VM_FAULT_HWPOISON_LARGE)
|
||||||
|
lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
|
||||||
|
else if (fault & VM_FAULT_HWPOISON)
|
||||||
|
lsb = PAGE_SHIFT;
|
||||||
|
else
|
||||||
|
show_signal_msg(regs, code, address, tsk, vma);
|
||||||
|
si.si_addr_lsb = lsb;
|
||||||
|
|
||||||
si.si_errno = 0;
|
si.si_errno = 0;
|
||||||
si.si_addr = (void __user *) address;
|
si.si_addr = (void __user *) address;
|
||||||
force_sig_info(si.si_signo, &si, current);
|
force_sig_info(si.si_signo, &si, current);
|
||||||
|
|
Loading…
Reference in New Issue