]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/ia64/mm/fault.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-2.6-omap-h63xx.git] / arch / ia64 / mm / fault.c
index b87f785c24161f2a8c4fc6061d89429ff5fd46ba..7571076a16a1991742af9f502b2113f7d9bd35a4 100644 (file)
@@ -80,6 +80,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
        struct mm_struct *mm = current->mm;
        struct siginfo si;
        unsigned long mask;
+       int fault;
 
        /* mmap_sem is performance critical.... */
        prefetchw(&mm->mmap_sem);
@@ -111,11 +112,17 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
        down_read(&mm->mmap_sem);
 
        vma = find_vma_prev(mm, address, &prev_vma);
-       if (!vma)
+       if (!vma && !prev_vma )
                goto bad_area;
 
-       /* find_vma_prev() returns vma such that address < vma->vm_end or NULL */
-       if (address < vma->vm_start)
+        /*
+         * find_vma_prev() returns vma such that address < vma->vm_end or NULL
+         *
+         * May find no vma, but could be that the last vm area is the
+         * register backing store that needs to expand upwards, in
+         * this case vma will be null, but prev_vma will ne non-null
+         */
+        if (( !vma && prev_vma ) || (address < vma->vm_start) )
                goto check_expansion;
 
   good_area:
@@ -147,31 +154,32 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
         * sure we exit gracefully rather than endlessly redo the
         * fault.
         */
-       switch (handle_mm_fault(mm, vma, address, (mask & VM_WRITE) != 0)) {
-             case VM_FAULT_MINOR:
-               ++current->min_flt;
-               break;
-             case VM_FAULT_MAJOR:
-               ++current->maj_flt;
-               break;
-             case VM_FAULT_SIGBUS:
+       fault = handle_mm_fault(mm, vma, address, (mask & VM_WRITE) != 0);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
                /*
                 * We ran out of memory, or some other thing happened
                 * to us that made us unable to handle the page fault
                 * gracefully.
                 */
-               signal = SIGBUS;
-               goto bad_area;
-             case VM_FAULT_OOM:
-               goto out_of_memory;
-             default:
+               if (fault & VM_FAULT_OOM) {
+                       goto out_of_memory;
+               } else if (fault & VM_FAULT_SIGBUS) {
+                       signal = SIGBUS;
+                       goto bad_area;
+               }
                BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
        up_read(&mm->mmap_sem);
        return;
 
   check_expansion:
        if (!(prev_vma && (prev_vma->vm_flags & VM_GROWSUP) && (address == prev_vma->vm_end))) {
+               if (!vma)
+                       goto bad_area;
                if (!(vma->vm_flags & VM_GROWSDOWN))
                        goto bad_area;
                if (REGION_NUMBER(address) != REGION_NUMBER(vma->vm_start)
@@ -266,13 +274,13 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
 
   out_of_memory:
        up_read(&mm->mmap_sem);
-       if (is_init(current)) {
+       if (is_global_init(current)) {
                yield();
                down_read(&mm->mmap_sem);
                goto survive;
        }
        printk(KERN_CRIT "VM: killing process %s\n", current->comm);
        if (user_mode(regs))
-               do_exit(SIGKILL);
+               do_group_exit(SIGKILL);
        goto no_context;
 }