]> err.no Git - linux-2.6/blobdiff - arch/arm/mm/fault.c
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee13...
[linux-2.6] / arch / arm / mm / fault.c
index 65bfe84b6d672e8989f0d8141b5781093147cf74..5e658a8744984688ee171e16b67a44aee65c1331 100644 (file)
@@ -8,7 +8,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/signal.h>
 #include <linux/ptrace.h>
@@ -132,10 +131,11 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
        force_sig_info(sig, &si, tsk);
 }
 
-void
-do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr,
-           unsigned int fsr, struct pt_regs *regs)
+void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
+       struct task_struct *tsk = current;
+       struct mm_struct *mm = tsk->active_mm;
+
        /*
         * If we are in kernel mode at this point, we
         * have no context to handle this fault with.
@@ -171,7 +171,7 @@ good_area:
        if (fsr & (1 << 11)) /* write? */
                mask = VM_WRITE;
        else
-               mask = VM_READ|VM_EXEC;
+               mask = VM_READ|VM_EXEC|VM_WRITE;
 
        fault = VM_FAULT_BADACCESS;
        if (!(vma->vm_flags & mask))
@@ -198,7 +198,7 @@ survive:
                return fault;
        }
 
-       if (tsk->pid != 1)
+       if (!is_init(tsk))
                goto out;
 
        /*
@@ -233,14 +233,24 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        if (in_interrupt() || !mm)
                goto no_context;
 
-       down_read(&mm->mmap_sem);
+       /*
+        * As per x86, we may deadlock here.  However, since the kernel only
+        * validly references user space from well defined areas of the code,
+        * we can bug out early if this is from code which shouldn't.
+        */
+       if (!down_read_trylock(&mm->mmap_sem)) {
+               if (!user_mode(regs) && !search_exception_tables(regs->ARM_pc))
+                       goto no_context;
+               down_read(&mm->mmap_sem);
+       }
+
        fault = __do_page_fault(mm, addr, fsr, tsk);
        up_read(&mm->mmap_sem);
 
        /*
-        * Handle the "normal" case first
+        * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR
         */
-       if (fault > 0)
+       if (fault >= VM_FAULT_MINOR)
                return 0;
 
        /*
@@ -261,7 +271,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
                do_exit(SIGKILL);
                return 0;
 
-       case 0:
+       case VM_FAULT_SIGBUS:
                /*
                 * We had some memory, but were unable to
                 * successfully fix up this page fault.
@@ -310,7 +320,6 @@ static int
 do_translation_fault(unsigned long addr, unsigned int fsr,
                     struct pt_regs *regs)
 {
-       struct task_struct *tsk;
        unsigned int index;
        pgd_t *pgd, *pgd_k;
        pmd_t *pmd, *pmd_k;
@@ -342,9 +351,7 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
        return 0;
 
 bad_area:
-       tsk = current;
-
-       do_bad_area(tsk, tsk->active_mm, addr, fsr, regs);
+       do_bad_area(addr, fsr, regs);
        return 0;
 }
 
@@ -355,8 +362,7 @@ bad_area:
 static int
 do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
-       struct task_struct *tsk = current;
-       do_bad_area(tsk, tsk->active_mm, addr, fsr, regs);
+       do_bad_area(addr, fsr, regs);
        return 0;
 }