]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/mm/fault.c
Merge current mainline tree into linux-omap tree
[linux-2.6-omap-h63xx.git] / arch / x86 / mm / fault.c
index ad8b9733d6b3fee4d2f90e2981e54dc2b71299e4..fdc667422df9913f2f5d861a3e80fad14eab7f4d 100644 (file)
@@ -186,7 +186,7 @@ static int bad_address(void *p)
 }
 #endif
 
-void dump_pagetable(unsigned long address)
+static void dump_pagetable(unsigned long address)
 {
 #ifdef CONFIG_X86_32
        __typeof__(pte_val(__pte(0))) page;
@@ -428,6 +428,16 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
 }
 #endif
 
+static int spurious_fault_check(unsigned long error_code, pte_t *pte)
+{
+       if ((error_code & PF_WRITE) && !pte_write(*pte))
+               return 0;
+       if ((error_code & PF_INSTR) && !pte_exec(*pte))
+               return 0;
+
+       return 1;
+}
+
 /*
  * Handle a spurious fault caused by a stale TLB entry.  This allows
  * us to lazily refresh the TLB when increasing the permissions of a
@@ -457,20 +467,21 @@ static int spurious_fault(unsigned long address,
        if (!pud_present(*pud))
                return 0;
 
+       if (pud_large(*pud))
+               return spurious_fault_check(error_code, (pte_t *) pud);
+
        pmd = pmd_offset(pud, address);
        if (!pmd_present(*pmd))
                return 0;
 
+       if (pmd_large(*pmd))
+               return spurious_fault_check(error_code, (pte_t *) pmd);
+
        pte = pte_offset_kernel(pmd, address);
        if (!pte_present(*pte))
                return 0;
 
-       if ((error_code & PF_WRITE) && !pte_write(*pte))
-               return 0;
-       if ((error_code & PF_INSTR) && !pte_exec(*pte))
-               return 0;
-
-       return 1;
+       return spurious_fault_check(error_code, pte);
 }
 
 /*
@@ -947,11 +958,12 @@ void vmalloc_sync_all(void)
        for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) {
                if (!test_bit(pgd_index(address), insync)) {
                        const pgd_t *pgd_ref = pgd_offset_k(address);
+                       unsigned long flags;
                        struct page *page;
 
                        if (pgd_none(*pgd_ref))
                                continue;
-                       spin_lock(&pgd_lock);
+                       spin_lock_irqsave(&pgd_lock, flags);
                        list_for_each_entry(page, &pgd_list, lru) {
                                pgd_t *pgd;
                                pgd = (pgd_t *)page_address(page) + pgd_index(address);
@@ -960,7 +972,7 @@ void vmalloc_sync_all(void)
                                else
                                        BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
                        }
-                       spin_unlock(&pgd_lock);
+                       spin_unlock_irqrestore(&pgd_lock, flags);
                        set_bit(pgd_index(address), insync);
                }
                if (address == start)