From: Ingo Molnar Date: Wed, 21 Jan 2009 09:39:51 +0000 (+0100) Subject: Merge branch 'x86/mm' into core/percpu X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=198030782cedf25391e67e7c88b04f87a5eb6563;p=linux-2.6-omap-h63xx.git Merge branch 'x86/mm' into core/percpu Conflicts: arch/x86/mm/fault.c --- 198030782cedf25391e67e7c88b04f87a5eb6563 diff --cc arch/x86/mm/fault.c index 37242c405f1,033292dc9e2..65709a6aa6e --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@@ -430,6 -429,190 +430,196 @@@ static noinline void pgtable_bad(struc } #endif + static noinline void no_context(struct pt_regs *regs, + unsigned long error_code, unsigned long address) + { + struct task_struct *tsk = current; ++ unsigned long *stackend; ++ + #ifdef CONFIG_X86_64 + unsigned long flags; + int sig; + #endif + + /* Are we prepared to handle this kernel fault? */ + if (fixup_exception(regs)) + return; + + /* + * X86_32 + * Valid to do another page fault here, because if this fault + * had been triggered by is_prefetch fixup_exception would have + * handled it. + * + * X86_64 + * Hall of shame of CPU/BIOS bugs. + */ + if (is_prefetch(regs, error_code, address)) + return; + + if (is_errata93(regs, address)) + return; + + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + #ifdef CONFIG_X86_32 + bust_spinlocks(1); + #else + flags = oops_begin(); + #endif + + show_fault_oops(regs, error_code, address); + ++ stackend = end_of_stack(tsk); ++ if (*stackend != STACK_END_MAGIC) ++ printk(KERN_ALERT "Thread overran stack, or stack corrupted\n"); ++ + tsk->thread.cr2 = address; + tsk->thread.trap_no = 14; + tsk->thread.error_code = error_code; + + #ifdef CONFIG_X86_32 + die("Oops", regs, error_code); + bust_spinlocks(0); + do_exit(SIGKILL); + #else + sig = SIGKILL; + if (__die("Oops", regs, error_code)) + sig = 0; + /* Executive summary in case the body of the oops scrolled away */ + printk(KERN_EMERG "CR2: %016lx\n", address); + oops_end(flags, regs, sig); + #endif + } + + static void __bad_area_nosemaphore(struct pt_regs *regs, + unsigned long error_code, unsigned long address, + int si_code) + { + struct task_struct *tsk = current; + + /* User mode accesses just cause a SIGSEGV */ + if (error_code & PF_USER) { + /* + * It's possible to have interrupts off here. + */ + local_irq_enable(); + + /* + * Valid to do another page fault here because this one came + * from user space. + */ + if (is_prefetch(regs, error_code, address)) + return; + + if (is_errata100(regs, address)) + return; + + if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && + printk_ratelimit()) { + printk( + "%s%s[%d]: segfault at %lx ip %p sp %p error %lx", + task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, + tsk->comm, task_pid_nr(tsk), address, + (void *) regs->ip, (void *) regs->sp, error_code); + print_vma_addr(" in ", regs->ip); + printk("\n"); + } + + tsk->thread.cr2 = address; + /* Kernel addresses are always protection faults */ + tsk->thread.error_code = error_code | (address >= TASK_SIZE); + tsk->thread.trap_no = 14; + force_sig_info_fault(SIGSEGV, si_code, address, tsk); + return; + } + + if (is_f00f_bug(regs, address)) + return; + + no_context(regs, error_code, address); + } + + static noinline void bad_area_nosemaphore(struct pt_regs *regs, + unsigned long error_code, unsigned long address) + { + __bad_area_nosemaphore(regs, error_code, address, SEGV_MAPERR); + } + + static void __bad_area(struct pt_regs *regs, + unsigned long error_code, unsigned long address, + int si_code) + { + struct mm_struct *mm = current->mm; + + /* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ + up_read(&mm->mmap_sem); + + __bad_area_nosemaphore(regs, error_code, address, si_code); + } + + static noinline void bad_area(struct pt_regs *regs, + unsigned long error_code, unsigned long address) + { + __bad_area(regs, error_code, address, SEGV_MAPERR); + } + + static noinline void bad_area_access_error(struct pt_regs *regs, + unsigned long error_code, unsigned long address) + { + __bad_area(regs, error_code, address, SEGV_ACCERR); + } + + /* TODO: fixup for "mm-invoke-oom-killer-from-page-fault.patch" */ + static void out_of_memory(struct pt_regs *regs, + unsigned long error_code, unsigned long address) + { + /* + * 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(¤t->mm->mmap_sem); + pagefault_out_of_memory(); + } + + static void do_sigbus(struct pt_regs *regs, + unsigned long error_code, unsigned long address) + { + struct task_struct *tsk = current; + struct mm_struct *mm = tsk->mm; + + up_read(&mm->mmap_sem); + + /* Kernel mode? Handle exceptions or die */ + if (!(error_code & PF_USER)) + no_context(regs, error_code, address); + #ifdef CONFIG_X86_32 + /* User space => ok to do another page fault */ + if (is_prefetch(regs, error_code, address)) + return; + #endif + tsk->thread.cr2 = address; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 14; + force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk); + } + + static noinline void mm_fault_error(struct pt_regs *regs, + unsigned long error_code, unsigned long address, unsigned int fault) + { + if (fault & VM_FAULT_OOM) + out_of_memory(regs, error_code, address); + else if (fault & VM_FAULT_SIGBUS) + do_sigbus(regs, error_code, address); + else + BUG(); + } + static int spurious_fault_check(unsigned long error_code, pte_t *pte) { if ((error_code & PF_WRITE) && !pte_write(*pte)) diff --cc arch/x86/mm/tlb.c index b3ca1b94065,8cfea5d1451..72a6d4ebe34 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@@ -42,10 -46,10 +42,10 @@@ union smp_flush_state struct mm_struct *flush_mm; unsigned long flush_va; spinlock_t tlbstate_lock; + DECLARE_BITMAP(flush_cpumask, NR_CPUS); }; - char pad[SMP_CACHE_BYTES]; - } ____cacheline_aligned; + char pad[CONFIG_X86_INTERNODE_CACHE_BYTES]; + } ____cacheline_internodealigned_in_smp; /* State is put into the per CPU data section, but padded to a full cache line because other CPUs can access it and we don't @@@ -135,9 -129,9 +135,9 @@@ void smp_invalidate_interrupt(struct pt * Use that to determine where the sender put the data. */ sender = ~regs->orig_ax - INVALIDATE_TLB_VECTOR_START; - f = &per_cpu(flush_state, sender); + f = &flush_state[sender]; - if (!cpu_isset(cpu, f->flush_cpumask)) + if (!cpumask_test_cpu(cpu, to_cpumask(f->flush_cpumask))) goto out; /* * This was a BUG() but until someone can quote me the