Skip to content

Commit 606f95e

Browse files
committed
parisc: Add HWPOISON page fault handler code
Commit 2458738 ("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 <[email protected]>
1 parent a7e6601 commit 606f95e

File tree

1 file changed

+29
-4
lines changed

1 file changed

+29
-4
lines changed

arch/parisc/mm/fault.c

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/interrupt.h>
1818
#include <linux/extable.h>
1919
#include <linux/uaccess.h>
20+
#include <linux/hugetlb.h>
2021

2122
#include <asm/traps.h>
2223

@@ -261,7 +262,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
261262
struct task_struct *tsk;
262263
struct mm_struct *mm;
263264
unsigned long acc_type;
264-
int fault;
265+
int fault = 0;
265266
unsigned int flags;
266267

267268
if (faulthandler_disabled())
@@ -315,7 +316,8 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
315316
goto out_of_memory;
316317
else if (fault & VM_FAULT_SIGSEGV)
317318
goto bad_area;
318-
else if (fault & VM_FAULT_SIGBUS)
319+
else if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
320+
VM_FAULT_HWPOISON_LARGE))
319321
goto bad_area;
320322
BUG();
321323
}
@@ -352,8 +354,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
352354

353355
if (user_mode(regs)) {
354356
struct siginfo si;
355-
356-
show_signal_msg(regs, code, address, tsk, vma);
357+
unsigned int lsb = 0;
357358

358359
switch (code) {
359360
case 15: /* Data TLB miss fault/Data page fault */
@@ -386,6 +387,30 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
386387
si.si_code = (code == 26) ? SEGV_ACCERR : SEGV_MAPERR;
387388
break;
388389
}
390+
391+
#ifdef CONFIG_MEMORY_FAILURE
392+
if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
393+
printk(KERN_ERR
394+
"MCE: Killing %s:%d due to hardware memory corruption fault at %08lx\n",
395+
tsk->comm, tsk->pid, address);
396+
si.si_signo = SIGBUS;
397+
si.si_code = BUS_MCEERR_AR;
398+
}
399+
#endif
400+
401+
/*
402+
* Either small page or large page may be poisoned.
403+
* In other words, VM_FAULT_HWPOISON_LARGE and
404+
* VM_FAULT_HWPOISON are mutually exclusive.
405+
*/
406+
if (fault & VM_FAULT_HWPOISON_LARGE)
407+
lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
408+
else if (fault & VM_FAULT_HWPOISON)
409+
lsb = PAGE_SHIFT;
410+
else
411+
show_signal_msg(regs, code, address, tsk, vma);
412+
si.si_addr_lsb = lsb;
413+
389414
si.si_errno = 0;
390415
si.si_addr = (void __user *) address;
391416
force_sig_info(si.si_signo, &si, current);

0 commit comments

Comments
 (0)