vserver 2.0 rc7
[linux-2.6.git] / arch / sparc64 / mm / fault.c
index 63b989f..3ffee7b 100644 (file)
@@ -144,7 +144,9 @@ static void unhandled_fault(unsigned long address, struct task_struct *tsk,
                       "at virtual address %016lx\n", (unsigned long)address);
        }
        printk(KERN_ALERT "tsk->{mm,active_mm}->context = %016lx\n",
-              (tsk->mm ? tsk->mm->context : tsk->active_mm->context));
+              (tsk->mm ?
+               CTX_HWBITS(tsk->mm->context) :
+               CTX_HWBITS(tsk->active_mm->context)));
        printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n",
               (tsk->mm ? (unsigned long) tsk->mm->pgd :
                          (unsigned long) tsk->active_mm->pgd));
@@ -175,6 +177,7 @@ static void bad_kernel_pc(struct pt_regs *regs)
 static unsigned int get_user_insn(unsigned long tpc)
 {
        pgd_t *pgdp = pgd_offset(current->mm, tpc);
+       pud_t *pudp;
        pmd_t *pmdp;
        pte_t *ptep, pte;
        unsigned long pa;
@@ -183,7 +186,10 @@ static unsigned int get_user_insn(unsigned long tpc)
 
        if (pgd_none(*pgdp))
                goto outret;
-       pmdp = pmd_offset(pgdp, tpc);
+       pudp = pud_offset(pgdp, tpc);
+       if (pud_none(*pudp))
+               goto outret;
+       pmdp = pmd_offset(pudp, tpc);
        if (pmd_none(*pmdp))
                goto outret;
 
@@ -352,7 +358,7 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs)
         * If we're in an interrupt or have no user
         * context, we must not take the fault..
         */
-       if (in_interrupt() || !mm)
+       if (in_atomic() || !mm)
                goto intr_or_no_mm;
 
        if (test_thread_flag(TIF_32BIT)) {
@@ -361,7 +367,15 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs)
                address &= 0xffffffff;
        }
 
-       down_read(&mm->mmap_sem);
+       if (!down_read_trylock(&mm->mmap_sem)) {
+               if ((regs->tstate & TSTATE_PRIV) &&
+                   !search_exception_tables(regs->tpc)) {
+                       insn = get_fault_insn(regs, insn);
+                       goto handle_kernel_fault;
+               }
+               down_read(&mm->mmap_sem);
+       }
+
        vma = find_vma(mm, address);
        if (!vma)
                goto bad_area;
@@ -446,16 +460,18 @@ good_area:
        }
 
        switch (handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE))) {
-       case 1:
+       case VM_FAULT_MINOR:
                current->min_flt++;
                break;
-       case 2:
+       case VM_FAULT_MAJOR:
                current->maj_flt++;
                break;
-       case 0:
+       case VM_FAULT_SIGBUS:
                goto do_sigbus;
-       default:
+       case VM_FAULT_OOM:
                goto out_of_memory;
+       default:
+               BUG();
        }
 
        up_read(&mm->mmap_sem);