diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-05-12 13:06:08 +0100 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-05-12 13:06:08 +0100 |
commit | 25061d285747f20aafa4b50df1b0b5665fef29cd (patch) | |
tree | c302ac93e3476788a4671ee556a902fce2592f3a /arch/sparc/mm/fault_64.c | |
parent | 7a6476143270d947924f5bbbc124accb0e558bf4 (diff) | |
parent | 6560ffd1ccd688152393dc7c35dbdcc33140633b (diff) |
Merge tag 'regmap-3.4' into regmap-stride
regmap: Last minute bug fix for 3.4
This is a last minute bug fix that was only just noticed since the code
path that's being exercised here is one that is fairly rarely used. The
changelog for the change itself is extremely clear and the code itself
is obvious to inspection so should be pretty safe.
Conflicts:
drivers/base/regmap/regmap.c (overlap between the fix and stride code)
Diffstat (limited to 'arch/sparc/mm/fault_64.c')
-rw-r--r-- | arch/sparc/mm/fault_64.c | 37 |
1 files changed, 30 insertions, 7 deletions
diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index 504c0622f72..1fe0429b631 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c @@ -279,6 +279,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) unsigned int insn = 0; int si_code, fault_code, fault; unsigned long address, mm_rss; + unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; fault_code = get_thread_fault_code(); @@ -333,6 +334,8 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) insn = get_fault_insn(regs, insn); goto handle_kernel_fault; } + +retry: down_read(&mm->mmap_sem); } @@ -423,7 +426,12 @@ good_area: goto bad_area; } - fault = handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE) ? FAULT_FLAG_WRITE : 0); + flags |= ((fault_code & FAULT_CODE_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; @@ -431,12 +439,27 @@ good_area: goto do_sigbus; BUG(); } - if (fault & VM_FAULT_MAJOR) { - current->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, address); - } else { - current->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address); + + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) { + current->maj_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, + 1, regs, address); + } else { + current->min_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, + 1, regs, address); + } + 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); |