diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2011-05-26 09:48:29 +0200 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2011-05-26 09:48:25 +0200 |
commit | 99583181cbf2252dd0554eef6f419a6b22cd33ea (patch) | |
tree | bb8ff8673b3415318236a6efe0a8c5081ef32815 /arch/s390 | |
parent | b396637841fff79e9520514e8dcbe769c20a2ea0 (diff) |
[S390] mm: handle kernel caused page fault oom situations
If e.g. copy_from_user() generates a page fault and the kernel runs
into an OOM situation the system might lock up.
If the OOM killer sends a SIG_KILL to the current process it can't
handle it since it is stuck in a copy_from_user() - page fault loop.
Fix this by adding the same fix as other architectures have.
E.g. the x86 variant f86268 "x86/mm: Handle mm_fault_error() in kernel
space"
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/mm/fault.c | 16 |
1 files changed, 9 insertions, 7 deletions
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 105fa107143..b57723aee84 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -245,9 +245,12 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code, do_no_context(regs, int_code, trans_exc_code); break; default: /* fault & VM_FAULT_ERROR */ - if (fault & VM_FAULT_OOM) - pagefault_out_of_memory(); - else if (fault & VM_FAULT_SIGBUS) { + if (fault & VM_FAULT_OOM) { + if (!(regs->psw.mask & PSW_MASK_PSTATE)) + do_no_context(regs, int_code, trans_exc_code); + else + pagefault_out_of_memory(); + } else if (fault & VM_FAULT_SIGBUS) { /* Kernel mode? Handle exceptions or die */ if (!(regs->psw.mask & PSW_MASK_PSTATE)) do_no_context(regs, int_code, trans_exc_code); @@ -429,10 +432,9 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write) access = write ? VM_WRITE : VM_READ; fault = do_exception(®s, access, uaddr | 2); if (unlikely(fault)) { - if (fault & VM_FAULT_OOM) { - pagefault_out_of_memory(); - fault = 0; - } else if (fault & VM_FAULT_SIGBUS) + if (fault & VM_FAULT_OOM) + return -EFAULT; + else if (fault & VM_FAULT_SIGBUS) do_sigbus(®s, pgm_int_code, uaddr); } return fault ? -EFAULT : 0; |