diff options
author | Kautuk Consul <consul.kautuk@gmail.com> | 2012-03-25 06:37:48 -0400 |
---|---|---|
committer | Geert Uytterhoeven <geert@linux-m68k.org> | 2012-04-22 14:16:49 -0400 |
commit | b637a6b16731d806ae2c8b9619a5619a2f283f15 (patch) | |
tree | 1f7f86a392b36b6dfb160449736a8a43647e84c4 | |
parent | 107b5d5302b184b72a2f12d9d23f2fcd4ce8a6ec (diff) |
m68k/mm: Port OOM changes to do_page_fault()
Commit d065bd810b6deb67d4897a14bfe21f8eb526ba99
(mm: retry page fault when blocking on disk transfer) and
commit 37b23e0525d393d48a7d59f870b3bc061a30ccdb
(x86,mm: make pagefault killable)
The above commits introduced changes into the x86 pagefault handler
for making the page fault handler retryable as well as killable.
These changes reduce the mmap_sem hold time, which is crucial
during OOM killer invocation.
Port these changes to m68k.
Signed-off-by: Kautuk Consul <consul.kautuk@gmail.com>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
-rw-r--r-- | arch/m68k/mm/fault.c | 42 |
1 files changed, 34 insertions, 8 deletions
diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c index 6b020a8461e7..aeebbb7b30f0 100644 --- a/arch/m68k/mm/fault.c +++ b/arch/m68k/mm/fault.c | |||
@@ -72,7 +72,8 @@ int do_page_fault(struct pt_regs *regs, unsigned long address, | |||
72 | { | 72 | { |
73 | struct mm_struct *mm = current->mm; | 73 | struct mm_struct *mm = current->mm; |
74 | struct vm_area_struct * vma; | 74 | struct vm_area_struct * vma; |
75 | int write, fault; | 75 | int fault; |
76 | unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; | ||
76 | 77 | ||
77 | #ifdef DEBUG | 78 | #ifdef DEBUG |
78 | printk ("do page fault:\nregs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n", | 79 | printk ("do page fault:\nregs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n", |
@@ -87,6 +88,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address, | |||
87 | if (in_atomic() || !mm) | 88 | if (in_atomic() || !mm) |
88 | goto no_context; | 89 | goto no_context; |
89 | 90 | ||
91 | retry: | ||
90 | down_read(&mm->mmap_sem); | 92 | down_read(&mm->mmap_sem); |
91 | 93 | ||
92 | vma = find_vma(mm, address); | 94 | vma = find_vma(mm, address); |
@@ -117,14 +119,13 @@ good_area: | |||
117 | #ifdef DEBUG | 119 | #ifdef DEBUG |
118 | printk("do_page_fault: good_area\n"); | 120 | printk("do_page_fault: good_area\n"); |
119 | #endif | 121 | #endif |
120 | write = 0; | ||
121 | switch (error_code & 3) { | 122 | switch (error_code & 3) { |
122 | default: /* 3: write, present */ | 123 | default: /* 3: write, present */ |
123 | /* fall through */ | 124 | /* fall through */ |
124 | case 2: /* write, not present */ | 125 | case 2: /* write, not present */ |
125 | if (!(vma->vm_flags & VM_WRITE)) | 126 | if (!(vma->vm_flags & VM_WRITE)) |
126 | goto acc_err; | 127 | goto acc_err; |
127 | write++; | 128 | flags |= FAULT_FLAG_WRITE; |
128 | break; | 129 | break; |
129 | case 1: /* read, present */ | 130 | case 1: /* read, present */ |
130 | goto acc_err; | 131 | goto acc_err; |
@@ -139,10 +140,14 @@ good_area: | |||
139 | * the fault. | 140 | * the fault. |
140 | */ | 141 | */ |
141 | 142 | ||
142 | fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0); | 143 | fault = handle_mm_fault(mm, vma, address, flags); |
143 | #ifdef DEBUG | 144 | #ifdef DEBUG |
144 | printk("handle_mm_fault returns %d\n",fault); | 145 | printk("handle_mm_fault returns %d\n",fault); |
145 | #endif | 146 | #endif |
147 | |||
148 | if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) | ||
149 | return 0; | ||
150 | |||
146 | if (unlikely(fault & VM_FAULT_ERROR)) { | 151 | if (unlikely(fault & VM_FAULT_ERROR)) { |
147 | if (fault & VM_FAULT_OOM) | 152 | if (fault & VM_FAULT_OOM) |
148 | goto out_of_memory; | 153 | goto out_of_memory; |
@@ -150,10 +155,31 @@ good_area: | |||
150 | goto bus_err; | 155 | goto bus_err; |
151 | BUG(); | 156 | BUG(); |
152 | } | 157 | } |
153 | if (fault & VM_FAULT_MAJOR) | 158 | |
154 | current->maj_flt++; | 159 | /* |
155 | else | 160 | * Major/minor page fault accounting is only done on the |
156 | current->min_flt++; | 161 | * initial attempt. If we go through a retry, it is extremely |
162 | * likely that the page will be found in page cache at that point. | ||
163 | */ | ||
164 | if (flags & FAULT_FLAG_ALLOW_RETRY) { | ||
165 | if (fault & VM_FAULT_MAJOR) | ||
166 | current->maj_flt++; | ||
167 | else | ||
168 | current->min_flt++; | ||
169 | if (fault & VM_FAULT_RETRY) { | ||
170 | /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk | ||
171 | * of starvation. */ | ||
172 | flags &= ~FAULT_FLAG_ALLOW_RETRY; | ||
173 | |||
174 | /* | ||
175 | * No need to up_read(&mm->mmap_sem) as we would | ||
176 | * have already released it in __lock_page_or_retry | ||
177 | * in mm/filemap.c. | ||
178 | */ | ||
179 | |||
180 | goto retry; | ||
181 | } | ||
182 | } | ||
157 | 183 | ||
158 | up_read(&mm->mmap_sem); | 184 | up_read(&mm->mmap_sem); |
159 | return 0; | 185 | return 0; |