X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fx86_64%2Fkernel%2Fprocess.c;h=818ab9e66aed256ea3b854547b277be28e888417;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=051ad1117ff85c291c3967dc33c14157491ddf23;hpb=f7ed79d23a47594e7834d66a8f14449796d4f3e6;p=linux-2.6.git diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 051ad1117..818ab9e66 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -35,8 +35,8 @@ #include #include #include -#include #include +#include #include #include @@ -66,17 +66,24 @@ EXPORT_SYMBOL(boot_option_idle_override); void (*pm_idle)(void); static DEFINE_PER_CPU(unsigned int, cpu_idle_state); -static ATOMIC_NOTIFIER_HEAD(idle_notifier); +static struct notifier_block *idle_notifier; +static DEFINE_SPINLOCK(idle_notifier_lock); void idle_notifier_register(struct notifier_block *n) { - atomic_notifier_chain_register(&idle_notifier, n); + unsigned long flags; + spin_lock_irqsave(&idle_notifier_lock, flags); + notifier_chain_register(&idle_notifier, n); + spin_unlock_irqrestore(&idle_notifier_lock, flags); } EXPORT_SYMBOL_GPL(idle_notifier_register); void idle_notifier_unregister(struct notifier_block *n) { - atomic_notifier_chain_unregister(&idle_notifier, n); + unsigned long flags; + spin_lock_irqsave(&idle_notifier_lock, flags); + notifier_chain_unregister(&idle_notifier, n); + spin_unlock_irqrestore(&idle_notifier_lock, flags); } EXPORT_SYMBOL(idle_notifier_unregister); @@ -86,13 +93,13 @@ static DEFINE_PER_CPU(enum idle_state, idle_state) = CPU_NOT_IDLE; void enter_idle(void) { __get_cpu_var(idle_state) = CPU_IDLE; - atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); + notifier_call_chain(&idle_notifier, IDLE_START, NULL); } static void __exit_idle(void) { __get_cpu_var(idle_state) = CPU_NOT_IDLE; - atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); + notifier_call_chain(&idle_notifier, IDLE_END, NULL); } /* Called from interrupts to signify idle end */ @@ -107,7 +114,7 @@ void exit_idle(void) * We use this if we don't have any better * idle routine.. */ -static void default_idle(void) +void default_idle(void) { local_irq_enable(); @@ -346,6 +353,13 @@ void exit_thread(void) struct task_struct *me = current; struct thread_struct *t = &me->thread; + /* + * Remove function-return probe instances associated with this task + * and put them back on the free list. Do not insert an exit probe for + * this function, it will be disabled by kprobe_flush_task if you do. + */ + kprobe_flush_task(me); + if (me->thread.io_bitmap_ptr) { struct tss_struct *tss = &per_cpu(init_tss, get_cpu()); @@ -494,7 +508,7 @@ out: /* * This special macro can be used to load a debugging register */ -#define loaddebug(thread,r) set_debugreg(thread->debugreg ## r, r) +#define loaddebug(thread,r) set_debug(thread->debugreg ## r, r) /* * switch_to(x,y) should switch tasks from x to y. @@ -570,16 +584,17 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) } /* - * Switch the PDA and FPU contexts. + * Switch the PDA context. */ prev->userrsp = read_pda(oldrsp); write_pda(oldrsp, next->userrsp); write_pda(pcurrent, next_p); - /* This must be here to ensure both math_state_restore() and - kernel_fpu_begin() work consistently. + /* This must be here to ensure both math_state_restore() and + kernel_fpu_begin() work consistently. And the AMD workaround requires it to be after DS reload. */ unlazy_fpu(prev_p); + write_pda(kernelstack, task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET); @@ -649,6 +664,12 @@ void set_personality_64bit(void) /* Make sure to be in 64bit mode */ clear_thread_flag(TIF_IA32); + + /* TBD: overwrites user setup. Should have two bits. + But 64bit processes have always behaved this way, + so it's not too bad. The main problem is just that + 32bit childs are affected again. */ + current->personality &= ~READ_IMPLIES_EXEC; } asmlinkage long sys_fork(struct pt_regs *regs) @@ -777,16 +798,10 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) } case ARCH_GET_GS: { unsigned long base; - unsigned gsindex; if (task->thread.gsindex == GS_TLS_SEL) base = read_32bit_tls(task, GS_TLS); - else if (doit) { - asm("movl %%gs,%0" : "=r" (gsindex)); - if (gsindex) - rdmsrl(MSR_KERNEL_GS_BASE, base); - else - base = task->thread.gs; - } + else if (doit) + rdmsrl(MSR_KERNEL_GS_BASE, base); else base = task->thread.gs; ret = put_user(base, (unsigned long __user *)addr);