aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm/fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/mm/fault.c')
-rw-r--r--arch/s390/mm/fault.c62
1 files changed, 39 insertions, 23 deletions
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index a0f9e730f26a..fe103e891e7a 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -34,7 +34,7 @@
34#include <asm/asm-offsets.h> 34#include <asm/asm-offsets.h>
35#include <asm/system.h> 35#include <asm/system.h>
36#include <asm/pgtable.h> 36#include <asm/pgtable.h>
37#include <asm/s390_ext.h> 37#include <asm/irq.h>
38#include <asm/mmu_context.h> 38#include <asm/mmu_context.h>
39#include <asm/compat.h> 39#include <asm/compat.h>
40#include "../kernel/entry.h" 40#include "../kernel/entry.h"
@@ -245,9 +245,12 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code,
245 do_no_context(regs, int_code, trans_exc_code); 245 do_no_context(regs, int_code, trans_exc_code);
246 break; 246 break;
247 default: /* fault & VM_FAULT_ERROR */ 247 default: /* fault & VM_FAULT_ERROR */
248 if (fault & VM_FAULT_OOM) 248 if (fault & VM_FAULT_OOM) {
249 pagefault_out_of_memory(); 249 if (!(regs->psw.mask & PSW_MASK_PSTATE))
250 else if (fault & VM_FAULT_SIGBUS) { 250 do_no_context(regs, int_code, trans_exc_code);
251 else
252 pagefault_out_of_memory();
253 } else if (fault & VM_FAULT_SIGBUS) {
251 /* Kernel mode? Handle exceptions or die */ 254 /* Kernel mode? Handle exceptions or die */
252 if (!(regs->psw.mask & PSW_MASK_PSTATE)) 255 if (!(regs->psw.mask & PSW_MASK_PSTATE))
253 do_no_context(regs, int_code, trans_exc_code); 256 do_no_context(regs, int_code, trans_exc_code);
@@ -277,7 +280,8 @@ static inline int do_exception(struct pt_regs *regs, int access,
277 struct mm_struct *mm; 280 struct mm_struct *mm;
278 struct vm_area_struct *vma; 281 struct vm_area_struct *vma;
279 unsigned long address; 282 unsigned long address;
280 int fault, write; 283 unsigned int flags;
284 int fault;
281 285
282 if (notify_page_fault(regs)) 286 if (notify_page_fault(regs))
283 return 0; 287 return 0;
@@ -296,6 +300,10 @@ static inline int do_exception(struct pt_regs *regs, int access,
296 300
297 address = trans_exc_code & __FAIL_ADDR_MASK; 301 address = trans_exc_code & __FAIL_ADDR_MASK;
298 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); 302 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
303 flags = FAULT_FLAG_ALLOW_RETRY;
304 if (access == VM_WRITE || (trans_exc_code & store_indication) == 0x400)
305 flags |= FAULT_FLAG_WRITE;
306retry:
299 down_read(&mm->mmap_sem); 307 down_read(&mm->mmap_sem);
300 308
301 fault = VM_FAULT_BADMAP; 309 fault = VM_FAULT_BADMAP;
@@ -325,21 +333,31 @@ static inline int do_exception(struct pt_regs *regs, int access,
325 * make sure we exit gracefully rather than endlessly redo 333 * make sure we exit gracefully rather than endlessly redo
326 * the fault. 334 * the fault.
327 */ 335 */
328 write = (access == VM_WRITE || 336 fault = handle_mm_fault(mm, vma, address, flags);
329 (trans_exc_code & store_indication) == 0x400) ?
330 FAULT_FLAG_WRITE : 0;
331 fault = handle_mm_fault(mm, vma, address, write);
332 if (unlikely(fault & VM_FAULT_ERROR)) 337 if (unlikely(fault & VM_FAULT_ERROR))
333 goto out_up; 338 goto out_up;
334 339
335 if (fault & VM_FAULT_MAJOR) { 340 /*
336 tsk->maj_flt++; 341 * Major/minor page fault accounting is only done on the
337 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, 342 * initial attempt. If we go through a retry, it is extremely
338 regs, address); 343 * likely that the page will be found in page cache at that point.
339 } else { 344 */
340 tsk->min_flt++; 345 if (flags & FAULT_FLAG_ALLOW_RETRY) {
341 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, 346 if (fault & VM_FAULT_MAJOR) {
342 regs, address); 347 tsk->maj_flt++;
348 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
349 regs, address);
350 } else {
351 tsk->min_flt++;
352 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
353 regs, address);
354 }
355 if (fault & VM_FAULT_RETRY) {
356 /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
357 * of starvation. */
358 flags &= ~FAULT_FLAG_ALLOW_RETRY;
359 goto retry;
360 }
343 } 361 }
344 /* 362 /*
345 * The instruction that caused the program check will 363 * The instruction that caused the program check will
@@ -429,10 +447,9 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
429 access = write ? VM_WRITE : VM_READ; 447 access = write ? VM_WRITE : VM_READ;
430 fault = do_exception(&regs, access, uaddr | 2); 448 fault = do_exception(&regs, access, uaddr | 2);
431 if (unlikely(fault)) { 449 if (unlikely(fault)) {
432 if (fault & VM_FAULT_OOM) { 450 if (fault & VM_FAULT_OOM)
433 pagefault_out_of_memory(); 451 return -EFAULT;
434 fault = 0; 452 else if (fault & VM_FAULT_SIGBUS)
435 } else if (fault & VM_FAULT_SIGBUS)
436 do_sigbus(&regs, pgm_int_code, uaddr); 453 do_sigbus(&regs, pgm_int_code, uaddr);
437 } 454 }
438 return fault ? -EFAULT : 0; 455 return fault ? -EFAULT : 0;
@@ -485,7 +502,6 @@ int pfault_init(void)
485 "2:\n" 502 "2:\n"
486 EX_TABLE(0b,1b) 503 EX_TABLE(0b,1b)
487 : "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc"); 504 : "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc");
488 __ctl_set_bit(0, 9);
489 return rc; 505 return rc;
490} 506}
491 507
@@ -500,7 +516,6 @@ void pfault_fini(void)
500 516
501 if (!MACHINE_IS_VM || pfault_disable) 517 if (!MACHINE_IS_VM || pfault_disable)
502 return; 518 return;
503 __ctl_clear_bit(0,9);
504 asm volatile( 519 asm volatile(
505 " diag %0,0,0x258\n" 520 " diag %0,0,0x258\n"
506 "0:\n" 521 "0:\n"
@@ -615,6 +630,7 @@ static int __init pfault_irq_init(void)
615 rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP; 630 rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP;
616 if (rc) 631 if (rc)
617 goto out_pfault; 632 goto out_pfault;
633 service_subclass_irq_register();
618 hotcpu_notifier(pfault_cpu_notify, 0); 634 hotcpu_notifier(pfault_cpu_notify, 0);
619 return 0; 635 return 0;
620 636