From 902050bcdece6191565c055539e82c5cc534feed Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 May 2011 09:48:22 +0200 Subject: [S390] pfault: always enable service signal interrupt Always enable the service signal subclass mask bit in cr0, if pfault is available. That way we use the normal cpu hotplug way to propagate the subclass mask bit in cr0 instead of open coding it. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/fault.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/s390/mm/fault.c') diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index a0f9e730f26a..e46ba2927424 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -485,7 +485,6 @@ int pfault_init(void) "2:\n" EX_TABLE(0b,1b) : "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc"); - __ctl_set_bit(0, 9); return rc; } @@ -500,7 +499,6 @@ void pfault_fini(void) if (!MACHINE_IS_VM || pfault_disable) return; - __ctl_clear_bit(0,9); asm volatile( " diag %0,0,0x258\n" "0:\n" @@ -615,6 +613,7 @@ static int __init pfault_irq_init(void) rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP; if (rc) goto out_pfault; + ctl_set_bit(0, 9); hotcpu_notifier(pfault_cpu_notify, 0); return 0; -- cgit v1.2.2 From df7997ab1ca82ae3c37a2f5eb98613fc24527f95 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 May 2011 09:48:23 +0200 Subject: [S390] irq: fix service signal external interrupt handling Interrupt sources like pfault, sclp, dasd_diag and virtio all use the service signal external interrupt subclass mask in control register 0 to enable and disable the corresponding interrupt. Because no reference counting is implemented each subsystem thinks it is the only user of subclass and sets and clears the bit like it wants. This leads to case that unloading the dasd diag module under z/VM causes both sclp and pfault interrupts to be masked. The result will be locked up system sooner or later. Fix this by introducing a new way to set (register) and clear (unregister) the service signal subclass mask bit in cr0. Also convert all drivers. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/fault.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/s390/mm/fault.c') diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index e46ba2927424..6e922b50efa4 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -613,7 +613,7 @@ static int __init pfault_irq_init(void) rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP; if (rc) goto out_pfault; - ctl_set_bit(0, 9); + service_subclass_irq_register(); hotcpu_notifier(pfault_cpu_notify, 0); return 0; -- cgit v1.2.2 From d7b250e2a2d7f3cd23cf8d8d6689285e6f51a98d Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 May 2011 09:48:24 +0200 Subject: [S390] irq: merge irq.c and s390_ext.c Merge irq.c and s390_ext.c into irq.c. That way all external interrupt related functions are together. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/fault.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/s390/mm/fault.c') diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 6e922b50efa4..105fa1071435 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include "../kernel/entry.h" -- cgit v1.2.2 From 99583181cbf2252dd0554eef6f419a6b22cd33ea Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 May 2011 09:48:29 +0200 Subject: [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 --- arch/s390/mm/fault.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'arch/s390/mm/fault.c') diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 105fa1071435..b57723aee848 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; -- cgit v1.2.2 From 33ce614029576b8585e271fd7d90746a37114a15 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 May 2011 09:48:30 +0200 Subject: [S390] mm: add page fault retry handling s390 arch backend for d065bd81 "mm: retry page fault when blocking on disk transfer". Signed-off-by: Heiko Carstens --- arch/s390/mm/fault.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) (limited to 'arch/s390/mm/fault.c') diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index b57723aee848..fe103e891e7a 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -280,7 +280,8 @@ static inline int do_exception(struct pt_regs *regs, int access, struct mm_struct *mm; struct vm_area_struct *vma; unsigned long address; - int fault, write; + unsigned int flags; + int fault; if (notify_page_fault(regs)) return 0; @@ -299,6 +300,10 @@ static inline int do_exception(struct pt_regs *regs, int access, address = trans_exc_code & __FAIL_ADDR_MASK; perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); + flags = FAULT_FLAG_ALLOW_RETRY; + if (access == VM_WRITE || (trans_exc_code & store_indication) == 0x400) + flags |= FAULT_FLAG_WRITE; +retry: down_read(&mm->mmap_sem); fault = VM_FAULT_BADMAP; @@ -328,21 +333,31 @@ static inline int do_exception(struct pt_regs *regs, int access, * make sure we exit gracefully rather than endlessly redo * the fault. */ - write = (access == VM_WRITE || - (trans_exc_code & store_indication) == 0x400) ? - FAULT_FLAG_WRITE : 0; - fault = handle_mm_fault(mm, vma, address, write); + fault = handle_mm_fault(mm, vma, address, flags); if (unlikely(fault & VM_FAULT_ERROR)) goto out_up; - if (fault & VM_FAULT_MAJOR) { - tsk->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, - regs, address); - } else { - tsk->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, - regs, address); + /* + * Major/minor page fault accounting is only done on the + * initial attempt. If we go through a retry, it is extremely + * likely that the page will be found in page cache at that point. + */ + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) { + tsk->maj_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, + regs, address); + } else { + tsk->min_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, + regs, address); + } + if (fault & VM_FAULT_RETRY) { + /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk + * of starvation. */ + flags &= ~FAULT_FLAG_ALLOW_RETRY; + goto retry; + } } /* * The instruction that caused the program check will -- cgit v1.2.2