diff options
author | Arnd Bergmann <arnd@arndb.de> | 2012-03-15 16:11:36 +0000 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2012-03-15 16:11:40 +0000 |
commit | 86a30bece9ad4cc91c393a829a7b128291e0fb65 (patch) | |
tree | 6cb3e6ad413d74118535f77436056c8d3cfae0eb /arch/mips/mm/fault.c | |
parent | 243d58ec5792299fa212d05a4113c0ebac2df6a3 (diff) | |
parent | a323f66439c04d1c3ae4dc20cc2d44d52ee43c9f (diff) |
Merge branch 'fixes-non-critical' of git://github.com/hzhuang1/linux into next/maintainers
* 'fixes-non-critical' of git://github.com/hzhuang1/linux:
MAINTAINERS: update MAINTAINERS email entry
MAINTAINERS: update maintainer entry for pxa/hx4700
(update to v3.3-rc7)
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/mips/mm/fault.c')
-rw-r--r-- | arch/mips/mm/fault.c | 36 |
1 files changed, 29 insertions, 7 deletions
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index 937cf336816..69ebd586d7f 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -42,6 +42,8 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ const int field = sizeof(unsigned long) * 2; siginfo_t info; int fault; + unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | + (write ? FAULT_FLAG_WRITE : 0); #if 0 printk("Cpu%d[%s:%d:%0*lx:%ld:%0*lx]\n", raw_smp_processor_id(), @@ -91,6 +93,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ if (in_atomic() || !mm) goto bad_area_nosemaphore; +retry: down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) @@ -144,7 +147,11 @@ good_area: * make sure we exit gracefully rather than endlessly redo * the fault. */ - fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0); + fault = handle_mm_fault(mm, vma, address, flags); + + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) + return; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) @@ -153,12 +160,27 @@ good_area: goto do_sigbus; BUG(); } - if (fault & VM_FAULT_MAJOR) { - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, address); - tsk->maj_flt++; - } else { - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address); - tsk->min_flt++; + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) { + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, + regs, address); + tsk->maj_flt++; + } else { + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, + regs, address); + 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); |