X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Fcpu.c;h=e882c6babf414854a53b615229e49005d3cc4d75;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=72b984c67eb32ddf78733e56025951eef4a84dc0;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/kernel/cpu.c b/kernel/cpu.c index 72b984c67..e882c6bab 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -11,42 +11,81 @@ #include #include #include -#include /* for hotplug_path */ #include #include #include /* This protects CPUs going up and down... */ -DECLARE_MUTEX(cpucontrol); +static DECLARE_MUTEX(cpucontrol); static struct notifier_block *cpu_chain; -/* - * Represents all cpu's present in the system - * In systems capable of hotplug, this map could dynamically grow - * as new cpu's are detected in the system via any platform specific - * method, such as ACPI for e.g. - */ -cpumask_t cpu_present_map; -EXPORT_SYMBOL(cpu_present_map); + +#ifdef CONFIG_HOTPLUG_CPU +static struct task_struct *lock_cpu_hotplug_owner; +static int lock_cpu_hotplug_depth; + +static int __lock_cpu_hotplug(int interruptible) +{ + int ret = 0; + + if (lock_cpu_hotplug_owner != current) { + if (interruptible) + ret = down_interruptible(&cpucontrol); + else + down(&cpucontrol); + } + + /* + * Set only if we succeed in locking + */ + if (!ret) { + lock_cpu_hotplug_depth++; + lock_cpu_hotplug_owner = current; + } + + return ret; +} + +void lock_cpu_hotplug(void) +{ + __lock_cpu_hotplug(0); +} +EXPORT_SYMBOL_GPL(lock_cpu_hotplug); + +void unlock_cpu_hotplug(void) +{ + if (--lock_cpu_hotplug_depth == 0) { + lock_cpu_hotplug_owner = NULL; + up(&cpucontrol); + } +} +EXPORT_SYMBOL_GPL(unlock_cpu_hotplug); + +int lock_cpu_hotplug_interruptible(void) +{ + return __lock_cpu_hotplug(1); +} +EXPORT_SYMBOL_GPL(lock_cpu_hotplug_interruptible); +#endif /* CONFIG_HOTPLUG_CPU */ /* Need to know about CPUs going up/down? */ int register_cpu_notifier(struct notifier_block *nb) { int ret; - if ((ret = down_interruptible(&cpucontrol)) != 0) + if ((ret = lock_cpu_hotplug_interruptible()) != 0) return ret; ret = notifier_chain_register(&cpu_chain, nb); - up(&cpucontrol); + unlock_cpu_hotplug(); return ret; } EXPORT_SYMBOL(register_cpu_notifier); void unregister_cpu_notifier(struct notifier_block *nb) { - down(&cpucontrol); + lock_cpu_hotplug(); notifier_chain_unregister(&cpu_chain, nb); - up(&cpucontrol); + unlock_cpu_hotplug(); } EXPORT_SYMBOL(unregister_cpu_notifier); @@ -57,7 +96,9 @@ static inline void check_for_tasks(int cpu) write_lock_irq(&tasklist_lock); for_each_process(p) { - if (task_cpu(p) == cpu && (p->utime != 0 || p->stime != 0)) + if (task_cpu(p) == cpu && + (!cputime_eq(p->utime, cputime_zero) || + !cputime_eq(p->stime, cputime_zero))) printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d\ (state = %ld, flags = %lx) \n", p->comm, p->pid, cpu, p->state, p->flags); @@ -65,51 +106,20 @@ static inline void check_for_tasks(int cpu) write_unlock_irq(&tasklist_lock); } -/* Notify userspace when a cpu event occurs, by running '/sbin/hotplug - * cpu' with certain environment variables set. */ -static int cpu_run_sbin_hotplug(unsigned int cpu, const char *action) -{ - char *argv[3], *envp[5], cpu_str[12], action_str[32]; - int i; - - sprintf(cpu_str, "CPU=%d", cpu); - sprintf(action_str, "ACTION=%s", action); - /* FIXME: Add DEVPATH. --RR */ - - i = 0; - argv[i++] = hotplug_path; - argv[i++] = "cpu"; - argv[i] = NULL; - - i = 0; - /* minimal command environment */ - envp[i++] = "HOME=/"; - envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; - envp[i++] = cpu_str; - envp[i++] = action_str; - envp[i] = NULL; - - return call_usermodehelper(argv[0], argv, envp, 0); -} - /* Take this CPU down. */ static int take_cpu_down(void *unused) { int err; - /* Take offline: makes arch_cpu_down somewhat easier. */ - cpu_clear(smp_processor_id(), cpu_online_map); - /* Ensure this CPU doesn't handle any more interrupts. */ err = __cpu_disable(); if (err < 0) - cpu_set(smp_processor_id(), cpu_online_map); - else - /* Force idle task to run as soon as we yield: it should - immediately notice cpu is offline and die quickly. */ - sched_idle_next(); + return err; - return err; + /* Force idle task to run as soon as we yield: it should + immediately notice cpu is offline and die quickly. */ + sched_idle_next(); + return 0; } int cpu_down(unsigned int cpu) @@ -131,6 +141,15 @@ int cpu_down(unsigned int cpu) goto out; } + err = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, + (void *)(long)cpu); + if (err == NOTIFY_BAD) { + printk("%s: attempt to take down CPU %u failed\n", + __FUNCTION__, cpu); + err = -EINVAL; + goto out; + } + /* Ensure that we are not runnable on dying cpu */ old_allowed = current->cpus_allowed; tmp = CPU_MASK_ALL; @@ -139,6 +158,11 @@ int cpu_down(unsigned int cpu) p = __stop_machine_run(take_cpu_down, NULL, cpu); if (IS_ERR(p)) { + /* CPU didn't die: tell everyone. Can't complain. */ + if (notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, + (void *)(long)cpu) == NOTIFY_BAD) + BUG(); + err = PTR_ERR(p); goto out_allowed; } @@ -154,7 +178,8 @@ int cpu_down(unsigned int cpu) __cpu_die(cpu); /* Move it here so it can run. */ - kthread_bind(p, smp_processor_id()); + kthread_bind(p, get_cpu()); + put_cpu(); /* CPU is completely dead: tell everyone. Too late to complain. */ if (notifier_call_chain(&cpu_chain, CPU_DEAD, (void *)(long)cpu) @@ -163,8 +188,6 @@ int cpu_down(unsigned int cpu) check_for_tasks(cpu); - cpu_run_sbin_hotplug(cpu, "offline"); - out_thread: err = kthread_stop(p); out_allowed: @@ -173,11 +196,6 @@ out: unlock_cpu_hotplug(); return err; } -#else -static inline int cpu_run_sbin_hotplug(unsigned int cpu, const char *action) -{ - return 0; -} #endif /*CONFIG_HOTPLUG_CPU*/ int __devinit cpu_up(unsigned int cpu) @@ -185,13 +203,14 @@ int __devinit cpu_up(unsigned int cpu) int ret; void *hcpu = (void *)(long)cpu; - if ((ret = down_interruptible(&cpucontrol)) != 0) + if ((ret = lock_cpu_hotplug_interruptible()) != 0) return ret; if (cpu_online(cpu) || !cpu_present(cpu)) { ret = -EINVAL; goto out; } + ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); if (ret == NOTIFY_BAD) { printk("%s: attempt to bring up CPU %u failed\n", @@ -214,6 +233,6 @@ out_notify: if (ret != 0) notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu); out: - up(&cpucontrol); + unlock_cpu_hotplug(); return ret; }