aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel/trap.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/kernel/trap.c')
-rw-r--r--arch/um/kernel/trap.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index dafc94715950..3be60765c0e2 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -30,6 +30,8 @@ int handle_page_fault(unsigned long address, unsigned long ip,
30 pmd_t *pmd; 30 pmd_t *pmd;
31 pte_t *pte; 31 pte_t *pte;
32 int err = -EFAULT; 32 int err = -EFAULT;
33 unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
34 (is_write ? FAULT_FLAG_WRITE : 0);
33 35
34 *code_out = SEGV_MAPERR; 36 *code_out = SEGV_MAPERR;
35 37
@@ -40,6 +42,7 @@ int handle_page_fault(unsigned long address, unsigned long ip,
40 if (in_atomic()) 42 if (in_atomic())
41 goto out_nosemaphore; 43 goto out_nosemaphore;
42 44
45retry:
43 down_read(&mm->mmap_sem); 46 down_read(&mm->mmap_sem);
44 vma = find_vma(mm, address); 47 vma = find_vma(mm, address);
45 if (!vma) 48 if (!vma)
@@ -65,7 +68,11 @@ good_area:
65 do { 68 do {
66 int fault; 69 int fault;
67 70
68 fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0); 71 fault = handle_mm_fault(mm, vma, address, flags);
72
73 if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
74 goto out_nosemaphore;
75
69 if (unlikely(fault & VM_FAULT_ERROR)) { 76 if (unlikely(fault & VM_FAULT_ERROR)) {
70 if (fault & VM_FAULT_OOM) { 77 if (fault & VM_FAULT_OOM) {
71 goto out_of_memory; 78 goto out_of_memory;
@@ -75,10 +82,17 @@ good_area:
75 } 82 }
76 BUG(); 83 BUG();
77 } 84 }
78 if (fault & VM_FAULT_MAJOR) 85 if (flags & FAULT_FLAG_ALLOW_RETRY) {
79 current->maj_flt++; 86 if (fault & VM_FAULT_MAJOR)
80 else 87 current->maj_flt++;
81 current->min_flt++; 88 else
89 current->min_flt++;
90 if (fault & VM_FAULT_RETRY) {
91 flags &= ~FAULT_FLAG_ALLOW_RETRY;
92
93 goto retry;
94 }
95 }
82 96
83 pgd = pgd_offset(mm, address); 97 pgd = pgd_offset(mm, address);
84 pud = pud_offset(pgd, address); 98 pud = pud_offset(pgd, address);