summaryrefslogtreecommitdiff
path: root/arch/xtensa/mm/fault.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2012-08-01 08:49:13 +0400
committerPaul Mundt <lethal@linux-sh.org>2012-08-01 08:49:13 +0400
commit91ba548cfd5cc8ee93b9435527efb8fa4caf5c5e (patch)
treec96ed92413044a28d17783e84a8824bfd2437af1 /arch/xtensa/mm/fault.c
parentb9ccfda293ee6fca9a89a1584f0900e0627b975e (diff)
parent4dc4c51675c137c30838425ecc8d471ff5eb138b (diff)
downloadlinux-91ba548cfd5cc8ee93b9435527efb8fa4caf5c5e.tar.xz
Merge branch 'sh/dmaengine' into sh-latest
Diffstat (limited to 'arch/xtensa/mm/fault.c')
-rw-r--r--arch/xtensa/mm/fault.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
index b17885a0b508..5a74c53bc69c 100644
--- a/arch/xtensa/mm/fault.c
+++ b/arch/xtensa/mm/fault.c
@@ -44,6 +44,7 @@ void do_page_fault(struct pt_regs *regs)
int is_write, is_exec;
int fault;
+ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
info.si_code = SEGV_MAPERR;
@@ -71,6 +72,7 @@ void do_page_fault(struct pt_regs *regs)
address, exccause, regs->pc, is_write? "w":"", is_exec? "x":"");
#endif
+retry:
down_read(&mm->mmap_sem);
vma = find_vma(mm, address);
@@ -93,6 +95,7 @@ good_area:
if (is_write) {
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
+ flags |= FAULT_FLAG_WRITE;
} else if (is_exec) {
if (!(vma->vm_flags & VM_EXEC))
goto bad_area;
@@ -104,7 +107,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;
@@ -112,10 +119,22 @@ good_area:
goto do_sigbus;
BUG();
}
- if (fault & VM_FAULT_MAJOR)
- current->maj_flt++;
- else
- current->min_flt++;
+ if (flags & FAULT_FLAG_ALLOW_RETRY) {
+ if (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);
return;