diff options
author | Kautuk Consul <consul.kautuk@gmail.com> | 2012-03-20 17:21:40 +0400 |
---|---|---|
committer | Michal Simek <monstr@monstr.eu> | 2012-05-25 08:34:34 +0400 |
commit | f397c077e114df07bd2b94a16681a04be8d59dff (patch) | |
tree | 2bf5882aa6cc8a9f1e03b792849a1dc6e2216500 /arch/microblaze/mm/fault.c | |
parent | 59516b07b4ffa7e607a5787674ea3c405f1b390c (diff) | |
download | linux-f397c077e114df07bd2b94a16681a04be8d59dff.tar.xz |
microblaze: 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 microblaze.
Signed-off-by: Kautuk Consul <consul.kautuk@gmail.com>
Diffstat (limited to 'arch/microblaze/mm/fault.c')
-rw-r--r-- | arch/microblaze/mm/fault.c | 33 |
1 files changed, 28 insertions, 5 deletions
diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c index c38a265846de..eb365d6795fa 100644 --- a/arch/microblaze/mm/fault.c +++ b/arch/microblaze/mm/fault.c @@ -92,6 +92,8 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, int code = SEGV_MAPERR; int is_write = error_code & ESR_S; int fault; + unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | + (is_write ? FAULT_FLAG_WRITE : 0); regs->ear = address; regs->esr = error_code; @@ -138,6 +140,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, if (kernel_mode(regs) && !search_exception_tables(regs->pc)) goto bad_area_nosemaphore; +retry: down_read(&mm->mmap_sem); } @@ -210,7 +213,11 @@ good_area: * make sure we exit gracefully rather than endlessly redo * the fault. */ - fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0); + fault = handle_mm_fault(mm, vma, address, flags); + + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; @@ -218,11 +225,27 @@ good_area: goto do_sigbus; BUG(); } - if (unlikely(fault & VM_FAULT_MAJOR)) - current->maj_flt++; - else - current->min_flt++; + + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (unlikely(fault & VM_FAULT_MAJOR)) + current->maj_flt++; + else + current->min_flt++; + if (fault & VM_FAULT_RETRY) { + flags &= ~FAULT_FLAG_ALLOW_RETRY; + + /* + * No need to up_read(&mm->mmap_sem) as we would + * have already released it in __lock_page_or_retry + * in mm/filemap.c. + */ + + goto retry; + } + } + up_read(&mm->mmap_sem); + /* * keep track of tlb+htab misses that are good addrs but * just need pte's created via handle_mm_fault() |