[S390] fix SIGBUS handling
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 25 Oct 2010 14:10:35 +0000 (16:10 +0200)
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>
Mon, 25 Oct 2010 14:10:19 +0000 (16:10 +0200)
Raise SIGBUS with a siginfo structure. Deliver BUS_ADRERR as si_code and
the address of the fault in the si_addr field.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/mm/fault.c

index b49d12073f1046b062876ae2a79edc0faa8c3940..bae2c282221cf14ed225e7037b85434d94c26c86 100644 (file)
@@ -212,14 +212,21 @@ static noinline void do_sigbus(struct pt_regs *regs, long int_code,
                               unsigned long trans_exc_code)
 {
        struct task_struct *tsk = current;
+       unsigned long address;
+       struct siginfo si;
 
        /*
         * Send a sigbus, regardless of whether we were in kernel
         * or user mode.
         */
-       tsk->thread.prot_addr = trans_exc_code & __FAIL_ADDR_MASK;
+       address = trans_exc_code & __FAIL_ADDR_MASK;
+       tsk->thread.prot_addr = address;
        tsk->thread.trap_no = int_code;
-       force_sig(SIGBUS, tsk);
+       si.si_signo = SIGBUS;
+       si.si_errno = 0;
+       si.si_code = BUS_ADRERR;
+       si.si_addr = (void __user *) address;
+       force_sig_info(SIGBUS, &si, tsk);
 }
 
 #ifdef CONFIG_S390_EXEC_PROTECT
@@ -279,10 +286,11 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code,
                if (fault & VM_FAULT_OOM)
                        pagefault_out_of_memory();
                else if (fault & VM_FAULT_SIGBUS) {
-                       do_sigbus(regs, int_code, trans_exc_code);
                        /* Kernel mode? Handle exceptions or die */
                        if (!(regs->psw.mask & PSW_MASK_PSTATE))
                                do_no_context(regs, int_code, trans_exc_code);
+                       else
+                               do_sigbus(regs, int_code, trans_exc_code);
                } else
                        BUG();
                break;