diff options
author | Jeff Garzik <jgarzik@pretzel.yyz.us> | 2005-06-26 17:11:03 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-06-26 17:11:03 -0400 |
commit | 8b0ee07e108b2eefdab5bb73f33223f18926c3b2 (patch) | |
tree | f68ca04180c5488301a40ec212ef2eb2467cf56c /arch/x86_64/mm/fault.c | |
parent | 4638aef40ba9ebb9734caeed1f373c24015259fd (diff) | |
parent | 8678887e7fb43cd6c9be6c9807b05e77848e0920 (diff) |
Merge upstream (approx. 2.6.12-git8) into 'janitor' branch of netdev-2.6.
Diffstat (limited to 'arch/x86_64/mm/fault.c')
-rw-r--r-- | arch/x86_64/mm/fault.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index e0330921676..2f187986f94 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -74,7 +74,7 @@ static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr, instr = (unsigned char *)convert_rip_to_linear(current, regs); max_instr = instr + 15; - if ((regs->cs & 3) != 0 && instr >= (unsigned char *)TASK_SIZE) + if (user_mode(regs) && instr >= (unsigned char *)TASK_SIZE) return 0; while (scan_more && instr < max_instr) { @@ -106,7 +106,7 @@ static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr, /* Could check the LDT for lm, but for now it's good enough to assume that long mode only uses well known segments or kernel. */ - scan_more = ((regs->cs & 3) == 0) || (regs->cs == __USER_CS); + scan_more = (!user_mode(regs)) || (regs->cs == __USER_CS); break; case 0x60: @@ -234,6 +234,8 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, /* * Handle a fault on the vmalloc or module mapping area + * + * This assumes no large pages in there. */ static int vmalloc_fault(unsigned long address) { @@ -272,7 +274,10 @@ static int vmalloc_fault(unsigned long address) if (!pte_present(*pte_ref)) return -1; pte = pte_offset_kernel(pmd, address); - if (!pte_present(*pte) || pte_page(*pte) != pte_page(*pte_ref)) + /* Don't use pte_page here, because the mappings can point + outside mem_map, and the NUMA hash lookup cannot handle + that. */ + if (!pte_present(*pte) || pte_pfn(*pte) != pte_pfn(*pte_ref)) BUG(); __flush_tlb_all(); return 0; @@ -345,8 +350,10 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) * (error_code & 4) == 0, and that the fault was not a * protection error (error_code & 1) == 0. */ - if (unlikely(address >= TASK_SIZE)) { - if (!(error_code & 5)) { + if (unlikely(address >= TASK_SIZE64)) { + if (!(error_code & 5) && + ((address >= VMALLOC_START && address < VMALLOC_END) || + (address >= MODULES_VADDR && address < MODULES_END))) { if (vmalloc_fault(address) < 0) goto bad_area_nosemaphore; return; |