aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mm
diff options
context:
space:
mode:
authorKautuk Consul <consul.kautuk@gmail.com>2011-11-27 11:49:50 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-12-06 06:15:26 -0500
commit8878a539ff19a43cf3729e7562cd528f490246ae (patch)
treebca1af3437f43cf8318b18d0b0b63adb653a6685 /arch/arm/mm
parentdf0e74da6df1568e3722466f85f2f08324bc767e (diff)
ARM: 7178/1: fault.c: Port OOM changes into 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 ARM. Without these changes, my ARM board encounters many hang and livelock scenarios. After applying this patch, OOM feature performance improves according to my testing. Signed-off-by: Kautuk Consul <consul.kautuk@gmail.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mm')
-rw-r--r--arch/arm/mm/fault.c58
1 files changed, 39 insertions, 19 deletions
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index aa33949fef60..4aabeaec25df 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -231,7 +231,7 @@ static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma)
231 231
232static int __kprobes 232static int __kprobes
233__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, 233__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
234 struct task_struct *tsk) 234 unsigned int flags, struct task_struct *tsk)
235{ 235{
236 struct vm_area_struct *vma; 236 struct vm_area_struct *vma;
237 int fault; 237 int fault;
@@ -253,18 +253,7 @@ good_area:
253 goto out; 253 goto out;
254 } 254 }
255 255
256 /* 256 return handle_mm_fault(mm, vma, addr & PAGE_MASK, flags);
257 * If for any reason at all we couldn't handle the fault, make
258 * sure we exit gracefully rather than endlessly redo the fault.
259 */
260 fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, (fsr & FSR_WRITE) ? FAULT_FLAG_WRITE : 0);
261 if (unlikely(fault & VM_FAULT_ERROR))
262 return fault;
263 if (fault & VM_FAULT_MAJOR)
264 tsk->maj_flt++;
265 else
266 tsk->min_flt++;
267 return fault;
268 257
269check_stack: 258check_stack:
270 if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) 259 if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr))
@@ -279,6 +268,9 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
279 struct task_struct *tsk; 268 struct task_struct *tsk;
280 struct mm_struct *mm; 269 struct mm_struct *mm;
281 int fault, sig, code; 270 int fault, sig, code;
271 int write = fsr & FSR_WRITE;
272 unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
273 (write ? FAULT_FLAG_WRITE : 0);
282 274
283 if (notify_page_fault(regs, fsr)) 275 if (notify_page_fault(regs, fsr))
284 return 0; 276 return 0;
@@ -305,6 +297,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
305 if (!down_read_trylock(&mm->mmap_sem)) { 297 if (!down_read_trylock(&mm->mmap_sem)) {
306 if (!user_mode(regs) && !search_exception_tables(regs->ARM_pc)) 298 if (!user_mode(regs) && !search_exception_tables(regs->ARM_pc))
307 goto no_context; 299 goto no_context;
300retry:
308 down_read(&mm->mmap_sem); 301 down_read(&mm->mmap_sem);
309 } else { 302 } else {
310 /* 303 /*
@@ -320,14 +313,41 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
320#endif 313#endif
321 } 314 }
322 315
323 fault = __do_page_fault(mm, addr, fsr, tsk); 316 fault = __do_page_fault(mm, addr, fsr, flags, tsk);
324 up_read(&mm->mmap_sem); 317
318 /* If we need to retry but a fatal signal is pending, handle the
319 * signal first. We do not need to release the mmap_sem because
320 * it would already be released in __lock_page_or_retry in
321 * mm/filemap.c. */
322 if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
323 return 0;
324
325 /*
326 * Major/minor page fault accounting is only done on the
327 * initial attempt. If we go through a retry, it is extremely
328 * likely that the page will be found in page cache at that point.
329 */
325 330
326 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); 331 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
327 if (fault & VM_FAULT_MAJOR) 332 if (flags & FAULT_FLAG_ALLOW_RETRY) {
328 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, addr); 333 if (fault & VM_FAULT_MAJOR) {
329 else if (fault & VM_FAULT_MINOR) 334 tsk->maj_flt++;
330 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, addr); 335 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
336 regs, addr);
337 } else {
338 tsk->min_flt++;
339 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
340 regs, addr);
341 }
342 if (fault & VM_FAULT_RETRY) {
343 /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
344 * of starvation. */
345 flags &= ~FAULT_FLAG_ALLOW_RETRY;
346 goto retry;
347 }
348 }
349
350 up_read(&mm->mmap_sem);
331 351
332 /* 352 /*
333 * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR 353 * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR