cpu hotplug, sched: Introduce cpu_active_map and redo sched domain managment (take 2)
[safe/jmp/linux-2.6] / kernel / cpu.c
index 656dc3f..a1ac7ea 100644 (file)
 #include <linux/stop_machine.h>
 #include <linux/mutex.h>
 
+/*
+ * 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 __read_mostly;
+EXPORT_SYMBOL(cpu_present_map);
+
+#ifndef CONFIG_SMP
+
+/*
+ * Represents all cpu's that are currently online.
+ */
+cpumask_t cpu_online_map __read_mostly = CPU_MASK_ALL;
+EXPORT_SYMBOL(cpu_online_map);
+
+cpumask_t cpu_possible_map __read_mostly = CPU_MASK_ALL;
+EXPORT_SYMBOL(cpu_possible_map);
+
+#else /* CONFIG_SMP */
+
 /* Serializes the updates to cpu_online_map, cpu_present_map */
 static DEFINE_MUTEX(cpu_add_remove_lock);
 
@@ -33,22 +55,20 @@ static struct {
         * an ongoing cpu hotplug operation.
         */
        int refcount;
-       wait_queue_head_t writer_queue;
 } cpu_hotplug;
 
-#define writer_exists() (cpu_hotplug.active_writer != NULL)
-
 void __init cpu_hotplug_init(void)
 {
        cpu_hotplug.active_writer = NULL;
        mutex_init(&cpu_hotplug.lock);
        cpu_hotplug.refcount = 0;
-       init_waitqueue_head(&cpu_hotplug.writer_queue);
 }
 
+cpumask_t cpu_active_map;
+
 #ifdef CONFIG_HOTPLUG_CPU
 
-void lock_cpu_hotplug(void)
+void get_online_cpus(void)
 {
        might_sleep();
        if (cpu_hotplug.active_writer == current)
@@ -58,22 +78,19 @@ void lock_cpu_hotplug(void)
        mutex_unlock(&cpu_hotplug.lock);
 
 }
-EXPORT_SYMBOL_GPL(lock_cpu_hotplug);
+EXPORT_SYMBOL_GPL(get_online_cpus);
 
-void unlock_cpu_hotplug(void)
+void put_online_cpus(void)
 {
        if (cpu_hotplug.active_writer == current)
                return;
        mutex_lock(&cpu_hotplug.lock);
-       cpu_hotplug.refcount--;
-
-       if (unlikely(writer_exists()) && !cpu_hotplug.refcount)
-               wake_up(&cpu_hotplug.writer_queue);
-
+       if (!--cpu_hotplug.refcount && unlikely(cpu_hotplug.active_writer))
+               wake_up_process(cpu_hotplug.active_writer);
        mutex_unlock(&cpu_hotplug.lock);
 
 }
-EXPORT_SYMBOL_GPL(unlock_cpu_hotplug);
+EXPORT_SYMBOL_GPL(put_online_cpus);
 
 #endif /* CONFIG_HOTPLUG_CPU */
 
@@ -98,8 +115,8 @@ void cpu_maps_update_done(void)
  * Note that during a cpu-hotplug operation, the new readers, if any,
  * will be blocked by the cpu_hotplug.lock
  *
- * Since cpu_maps_update_begin is always called after invoking
- * cpu_maps_update_begin, we can be sure that only one writer is active.
+ * Since cpu_hotplug_begin() is always called after invoking
+ * cpu_maps_update_begin(), we can be sure that only one writer is active.
  *
  * Note that theoretically, there is a possibility of a livelock:
  * - Refcount goes to zero, last reader wakes up the sleeping
@@ -110,24 +127,21 @@ void cpu_maps_update_done(void)
  *   non zero and goes to sleep again.
  *
  * However, this is very difficult to achieve in practice since
- * lock_cpu_hotplug() not an api which is called all that often.
+ * get_online_cpus() not an api which is called all that often.
  *
  */
 static void cpu_hotplug_begin(void)
 {
-       DECLARE_WAITQUEUE(wait, current);
-
-       mutex_lock(&cpu_hotplug.lock);
-
        cpu_hotplug.active_writer = current;
-       add_wait_queue_exclusive(&cpu_hotplug.writer_queue, &wait);
-       while (cpu_hotplug.refcount) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
+
+       for (;;) {
+               mutex_lock(&cpu_hotplug.lock);
+               if (likely(!cpu_hotplug.refcount))
+                       break;
+               __set_current_state(TASK_UNINTERRUPTIBLE);
                mutex_unlock(&cpu_hotplug.lock);
                schedule();
-               mutex_lock(&cpu_hotplug.lock);
        }
-       remove_wait_queue_locked(&cpu_hotplug.writer_queue, &wait);
 }
 
 static void cpu_hotplug_done(void)
@@ -136,7 +150,7 @@ static void cpu_hotplug_done(void)
        mutex_unlock(&cpu_hotplug.lock);
 }
 /* Need to know about CPUs going up/down? */
-int __cpuinit register_cpu_notifier(struct notifier_block *nb)
+int __ref register_cpu_notifier(struct notifier_block *nb)
 {
        int ret;
        cpu_maps_update_begin();
@@ -149,7 +163,7 @@ int __cpuinit register_cpu_notifier(struct notifier_block *nb)
 
 EXPORT_SYMBOL(register_cpu_notifier);
 
-void unregister_cpu_notifier(struct notifier_block *nb)
+void __ref unregister_cpu_notifier(struct notifier_block *nb)
 {
        cpu_maps_update_begin();
        raw_notifier_chain_unregister(&cpu_chain, nb);
@@ -180,7 +194,7 @@ struct take_cpu_down_param {
 };
 
 /* Take this CPU down. */
-static int take_cpu_down(void *_param)
+static int __ref take_cpu_down(void *_param)
 {
        struct take_cpu_down_param *param = _param;
        int err;
@@ -199,7 +213,7 @@ static int take_cpu_down(void *_param)
 }
 
 /* Requires cpu_add_remove_lock to be held */
-static int _cpu_down(unsigned int cpu, int tasks_frozen)
+static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
 {
        int err, nr_calls = 0;
        struct task_struct *p;
@@ -218,7 +232,6 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen)
                return -EINVAL;
 
        cpu_hotplug_begin();
-       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
        err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod,
                                        hcpu, -1, &nr_calls);
        if (err == NOTIFY_BAD) {
@@ -226,16 +239,16 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen)
                __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
                                          hcpu, nr_calls, NULL);
                printk("%s: attempt to take down CPU %u failed\n",
-                               __FUNCTION__, cpu);
+                               __func__, cpu);
                err = -EINVAL;
                goto out_release;
        }
 
        /* Ensure that we are not runnable on dying cpu */
        old_allowed = current->cpus_allowed;
-       tmp = CPU_MASK_ALL;
+       cpus_setall(tmp);
        cpu_clear(cpu, tmp);
-       set_cpus_allowed(current, tmp);
+       set_cpus_allowed_ptr(current, &tmp);
 
        p = __stop_machine_run(take_cpu_down, &tcd_param, cpu);
 
@@ -269,26 +282,35 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen)
 out_thread:
        err = kthread_stop(p);
 out_allowed:
-       set_cpus_allowed(current, old_allowed);
+       set_cpus_allowed_ptr(current, &old_allowed);
 out_release:
-       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu);
        cpu_hotplug_done();
        return err;
 }
 
-int cpu_down(unsigned int cpu)
+int __ref cpu_down(unsigned int cpu)
 {
        int err = 0;
 
        cpu_maps_update_begin();
-       if (cpu_hotplug_disabled)
+
+       if (cpu_hotplug_disabled) {
                err = -EBUSY;
-       else
-               err = _cpu_down(cpu, 0);
+               goto out;
+       }
+
+       cpu_clear(cpu, cpu_active_map);
+
+       err = _cpu_down(cpu, 0);
+
+       if (cpu_online(cpu))
+               cpu_set(cpu, cpu_active_map);
 
+out:
        cpu_maps_update_done();
        return err;
 }
+EXPORT_SYMBOL(cpu_down);
 #endif /*CONFIG_HOTPLUG_CPU*/
 
 /* Requires cpu_add_remove_lock to be held */
@@ -302,13 +324,12 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
                return -EINVAL;
 
        cpu_hotplug_begin();
-       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
        ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu,
                                                        -1, &nr_calls);
        if (ret == NOTIFY_BAD) {
                nr_calls--;
                printk("%s: attempt to bring up CPU %u failed\n",
-                               __FUNCTION__, cpu);
+                               __func__, cpu);
                ret = -EINVAL;
                goto out_notify;
        }
@@ -326,7 +347,6 @@ out_notify:
        if (ret != 0)
                __raw_notifier_call_chain(&cpu_chain,
                                CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
-       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu);
        cpu_hotplug_done();
 
        return ret;
@@ -346,11 +366,18 @@ int __cpuinit cpu_up(unsigned int cpu)
        }
 
        cpu_maps_update_begin();
-       if (cpu_hotplug_disabled)
+
+       if (cpu_hotplug_disabled) {
                err = -EBUSY;
-       else
-               err = _cpu_up(cpu, 0);
+               goto out;
+       }
 
+       err = _cpu_up(cpu, 0);
+
+       if (cpu_online(cpu))
+               cpu_set(cpu, cpu_active_map);
+
+out:
        cpu_maps_update_done();
        return err;
 }
@@ -393,7 +420,7 @@ int disable_nonboot_cpus(void)
        return error;
 }
 
-void enable_nonboot_cpus(void)
+void __ref enable_nonboot_cpus(void)
 {
        int cpu, error;
 
@@ -417,3 +444,5 @@ out:
        cpu_maps_update_done();
 }
 #endif /* CONFIG_PM_SLEEP_SMP */
+
+#endif /* CONFIG_SMP */