Merge branch 'timers-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[safe/jmp/linux-2.6] / arch / x86 / mm / fault.c
index 356ed2d..c76ef1d 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/tlbflush.h>
 #include <asm/proto.h>
 #include <asm-generic/sections.h>
+#include <asm/traps.h>
 
 /*
  * Page fault error code bits
@@ -52,7 +53,7 @@
 
 static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr)
 {
-#ifdef CONFIG_MMIOTRACE_HOOKS
+#ifdef CONFIG_MMIOTRACE
        if (unlikely(is_kmmio_active()))
                if (kmmio_handler(regs, addr) == 1)
                        return -1;
@@ -357,8 +358,6 @@ static int is_errata100(struct pt_regs *regs, unsigned long address)
        return 0;
 }
 
-void do_invalid_op(struct pt_regs *, unsigned long);
-
 static int is_f00f_bug(struct pt_regs *regs, unsigned long address)
 {
 #ifdef CONFIG_X86_F00F_BUG
@@ -394,7 +393,7 @@ static void show_fault_oops(struct pt_regs *regs, unsigned long error_code,
                if (pte && pte_present(*pte) && !pte_exec(*pte))
                        printk(KERN_CRIT "kernel tried to execute "
                                "NX-protected page - exploit attempt? "
-                               "(uid: %d)\n", current->uid);
+                               "(uid: %d)\n", current_uid());
        }
 #endif
 
@@ -414,6 +413,7 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
                                 unsigned long error_code)
 {
        unsigned long flags = oops_begin();
+       int sig = SIGKILL;
        struct task_struct *tsk;
 
        printk(KERN_ALERT "%s: Corrupted page table at address %lx\n",
@@ -424,8 +424,8 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
        tsk->thread.trap_no = 14;
        tsk->thread.error_code = error_code;
        if (__die("Bad pagetable", regs, error_code))
-               regs = NULL;
-       oops_end(flags, regs, SIGKILL);
+               sig = 0;
+       oops_end(flags, regs, sig);
 }
 #endif
 
@@ -534,7 +534,7 @@ static int vmalloc_fault(unsigned long address)
           happen within a race in page table update. In the later
           case just flush. */
 
-       pgd = pgd_offset(current->mm ?: &init_mm, address);
+       pgd = pgd_offset(current->active_mm, address);
        pgd_ref = pgd_offset_k(address);
        if (pgd_none(*pgd_ref))
                return -1;
@@ -591,13 +591,9 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
        int fault;
 #ifdef CONFIG_X86_64
        unsigned long flags;
+       int sig;
 #endif
 
-       /*
-        * We can fault from pretty much anywhere, with unknown IRQ state.
-        */
-       trace_hardirqs_fixup();
-
        tsk = current;
        mm = tsk->mm;
        prefetchw(&mm->mmap_sem);
@@ -607,8 +603,6 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
 
        si_code = SEGV_MAPERR;
 
-       if (notify_page_fault(regs))
-               return;
        if (unlikely(kmmio_fault(regs, address)))
                return;
 
@@ -638,6 +632,9 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
                if (spurious_fault(address, error_code))
                        return;
 
+               /* kprobes don't want to hook the spurious faults. */
+               if (notify_page_fault(regs))
+                       return;
                /*
                 * Don't take the mm semaphore here. If we fixup a prefetch
                 * fault we could otherwise deadlock.
@@ -645,25 +642,27 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
                goto bad_area_nosemaphore;
        }
 
-
-#ifdef CONFIG_X86_32
-       /* It's safe to allow irq's after cr2 has been saved and the vmalloc
-          fault has been handled. */
-       if (regs->flags & (X86_EFLAGS_IF | X86_VM_MASK))
-               local_irq_enable();
+       /* kprobes don't want to hook the spurious faults. */
+       if (notify_page_fault(regs))
+               return;
 
        /*
-        * If we're in an interrupt, have no user context or are running in an
-        * atomic region then we must not take the fault.
+        * It's safe to allow irq's after cr2 has been saved and the
+        * vmalloc fault has been handled.
+        *
+        * User-mode registers count as a user access even for any
+        * potential system fault or CPU buglet.
         */
-       if (in_atomic() || !mm)
-               goto bad_area_nosemaphore;
-#else /* CONFIG_X86_64 */
-       if (likely(regs->flags & X86_EFLAGS_IF))
+       if (user_mode_vm(regs)) {
+               local_irq_enable();
+               error_code |= PF_USER;
+       } else if (regs->flags & X86_EFLAGS_IF)
                local_irq_enable();
 
+#ifdef CONFIG_X86_64
        if (unlikely(error_code & PF_RSVD))
                pgtable_bad(address, regs, error_code);
+#endif
 
        /*
         * If we're in an interrupt, have no user context or are running in an
@@ -673,14 +672,7 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
                goto bad_area_nosemaphore;
 
        /*
-        * User-mode registers count as a user access even for any
-        * potential system fault or CPU buglet.
-        */
-       if (user_mode_vm(regs))
-               error_code |= PF_USER;
-again:
-#endif
-       /* When running in the kernel we expect faults to occur only to
+        * When running in the kernel we expect faults to occur only to
         * addresses in user space.  All other faults represent errors in the
         * kernel and should generate an OOPS.  Unfortunately, in the case of an
         * erroneous fault occurring in a code path which already holds mmap_sem
@@ -743,9 +735,6 @@ good_area:
                        goto bad_area;
        }
 
-#ifdef CONFIG_X86_32
-survive:
-#endif
        /*
         * If for any reason at all we couldn't handle the fault,
         * make sure we exit gracefully rather than endlessly redo
@@ -865,33 +854,22 @@ no_context:
        bust_spinlocks(0);
        do_exit(SIGKILL);
 #else
+       sig = SIGKILL;
        if (__die("Oops", regs, error_code))
-               regs = NULL;
+               sig = 0;
        /* Executive summary in case the body of the oops scrolled away */
        printk(KERN_EMERG "CR2: %016lx\n", address);
-       oops_end(flags, regs, SIGKILL);
+       oops_end(flags, regs, sig);
 #endif
 
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
 out_of_memory:
+       /*
+        * We ran out of memory, call the OOM killer, and return the userspace
+        * (which will retry the fault, or kill us if we got oom-killed).
+        */
        up_read(&mm->mmap_sem);
-       if (is_global_init(tsk)) {
-               yield();
-#ifdef CONFIG_X86_32
-               down_read(&mm->mmap_sem);
-               goto survive;
-#else
-               goto again;
-#endif
-       }
-
-       printk("VM: killing process %s\n", tsk->comm);
-       if (error_code & PF_USER)
-               do_group_exit(SIGKILL);
-       goto no_context;
+       pagefault_out_of_memory();
+       return;
 
 do_sigbus:
        up_read(&mm->mmap_sem);