diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-09-07 15:07:55 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-09-07 15:07:55 -0400 |
commit | fac805f8c198092de9a2842efd7f5022e2937b18 (patch) | |
tree | 7557809c373f97a343c427d8fded0696060394ce /arch/avr32/mm/fault.c | |
parent | 2461c7d60f9f3821274e4acf9019cba8b82c94b5 (diff) | |
parent | f10723841e624c0726c70356b31d91befed01dd6 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
Diffstat (limited to 'arch/avr32/mm/fault.c')
-rw-r--r-- | arch/avr32/mm/fault.c | 33 |
1 files changed, 25 insertions, 8 deletions
diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c index f7040a1e399f..b92e60958617 100644 --- a/arch/avr32/mm/fault.c +++ b/arch/avr32/mm/fault.c @@ -61,10 +61,10 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) const struct exception_table_entry *fixup; unsigned long address; unsigned long page; - int writeaccess; long signr; int code; int fault; + unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; if (notify_page_fault(regs, ecr)) return; @@ -86,6 +86,7 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) local_irq_enable(); +retry: down_read(&mm->mmap_sem); vma = find_vma(mm, address); @@ -104,7 +105,6 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) */ good_area: code = SEGV_ACCERR; - writeaccess = 0; switch (ecr) { case ECR_PROTECTION_X: @@ -121,7 +121,7 @@ good_area: case ECR_TLB_MISS_W: if (!(vma->vm_flags & VM_WRITE)) goto bad_area; - writeaccess = 1; + flags |= FAULT_FLAG_WRITE; break; default: panic("Unhandled case %lu in do_page_fault!", ecr); @@ -132,7 +132,11 @@ good_area: * sure we exit gracefully rather than endlessly redo the * fault. */ - fault = handle_mm_fault(mm, vma, address, writeaccess ? 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; @@ -140,10 +144,23 @@ good_area: goto do_sigbus; BUG(); } - if (fault & VM_FAULT_MAJOR) - tsk->maj_flt++; - else - tsk->min_flt++; + + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) + tsk->maj_flt++; + else + tsk->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); return; |