cpumask: export cpumask_of_cpu_map
[safe/jmp/linux-2.6] / kernel / cpu.c
index a21f71a..a35d899 100644 (file)
 #include <linux/stop_machine.h>
 #include <linux/mutex.h>
 
-/* This protects CPUs going up and down... */
+/*
+ * 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);
-static DEFINE_MUTEX(cpu_bitmask_lock);
 
 static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
 
@@ -26,52 +47,115 @@ static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
  */
 static int cpu_hotplug_disabled;
 
-#ifdef CONFIG_HOTPLUG_CPU
+static struct {
+       struct task_struct *active_writer;
+       struct mutex lock; /* Synchronizes accesses to refcount, */
+       /*
+        * Also blocks the new readers during
+        * an ongoing cpu hotplug operation.
+        */
+       int refcount;
+} cpu_hotplug;
+
+void __init cpu_hotplug_init(void)
+{
+       cpu_hotplug.active_writer = NULL;
+       mutex_init(&cpu_hotplug.lock);
+       cpu_hotplug.refcount = 0;
+}
 
-/* Crappy recursive lock-takers in cpufreq! Complain loudly about idiots */
-static struct task_struct *recursive;
-static int recursive_depth;
+cpumask_t cpu_active_map;
 
-void lock_cpu_hotplug(void)
+#ifdef CONFIG_HOTPLUG_CPU
+
+void get_online_cpus(void)
 {
-       struct task_struct *tsk = current;
-
-       if (tsk == recursive) {
-               static int warnings = 10;
-               if (warnings) {
-                       printk(KERN_ERR "Lukewarm IQ detected in hotplug locking\n");
-                       WARN_ON(1);
-                       warnings--;
-               }
-               recursive_depth++;
+       might_sleep();
+       if (cpu_hotplug.active_writer == current)
                return;
-       }
-       mutex_lock(&cpu_bitmask_lock);
-       recursive = tsk;
+       mutex_lock(&cpu_hotplug.lock);
+       cpu_hotplug.refcount++;
+       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)
 {
-       WARN_ON(recursive != current);
-       if (recursive_depth) {
-               recursive_depth--;
+       if (cpu_hotplug.active_writer == current)
                return;
-       }
-       recursive = NULL;
-       mutex_unlock(&cpu_bitmask_lock);
+       mutex_lock(&cpu_hotplug.lock);
+       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 */
 
+/*
+ * The following two API's must be used when attempting
+ * to serialize the updates to cpu_online_map, cpu_present_map.
+ */
+void cpu_maps_update_begin(void)
+{
+       mutex_lock(&cpu_add_remove_lock);
+}
+
+void cpu_maps_update_done(void)
+{
+       mutex_unlock(&cpu_add_remove_lock);
+}
+
+/*
+ * This ensures that the hotplug operation can begin only when the
+ * refcount goes to zero.
+ *
+ * Note that during a cpu-hotplug operation, the new readers, if any,
+ * will be blocked by the cpu_hotplug.lock
+ *
+ * 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
+ *   writer.
+ * - Last reader unlocks the cpu_hotplug.lock.
+ * - A new reader arrives at this moment, bumps up the refcount.
+ * - The writer acquires the cpu_hotplug.lock finds the refcount
+ *   non zero and goes to sleep again.
+ *
+ * However, this is very difficult to achieve in practice since
+ * get_online_cpus() not an api which is called all that often.
+ *
+ */
+static void cpu_hotplug_begin(void)
+{
+       cpu_hotplug.active_writer = current;
+
+       for (;;) {
+               mutex_lock(&cpu_hotplug.lock);
+               if (likely(!cpu_hotplug.refcount))
+                       break;
+               __set_current_state(TASK_UNINTERRUPTIBLE);
+               mutex_unlock(&cpu_hotplug.lock);
+               schedule();
+       }
+}
+
+static void cpu_hotplug_done(void)
+{
+       cpu_hotplug.active_writer = NULL;
+       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;
-       mutex_lock(&cpu_add_remove_lock);
+       cpu_maps_update_begin();
        ret = raw_notifier_chain_register(&cpu_chain, nb);
-       mutex_unlock(&cpu_add_remove_lock);
+       cpu_maps_update_done();
        return ret;
 }
 
@@ -79,11 +163,11 @@ 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)
 {
-       mutex_lock(&cpu_add_remove_lock);
+       cpu_maps_update_begin();
        raw_notifier_chain_unregister(&cpu_chain, nb);
-       mutex_unlock(&cpu_add_remove_lock);
+       cpu_maps_update_done();
 }
 EXPORT_SYMBOL(unregister_cpu_notifier);
 
@@ -98,7 +182,8 @@ static inline void check_for_tasks(int cpu)
                     !cputime_eq(p->stime, cputime_zero)))
                        printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d\
                                (state = %ld, flags = %x) \n",
-                                p->comm, p->pid, cpu, p->state, p->flags);
+                                p->comm, task_pid_nr(p), cpu,
+                                p->state, p->flags);
        }
        write_unlock_irq(&tasklist_lock);
 }
@@ -109,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;
@@ -128,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;
@@ -146,7 +231,7 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen)
        if (!cpu_online(cpu))
                return -EINVAL;
 
-       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
+       cpu_hotplug_begin();
        err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod,
                                        hcpu, -1, &nr_calls);
        if (err == NOTIFY_BAD) {
@@ -154,20 +239,18 @@ 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);
 
-       mutex_lock(&cpu_bitmask_lock);
        p = __stop_machine_run(take_cpu_down, &tcd_param, cpu);
-       mutex_unlock(&cpu_bitmask_lock);
 
        if (IS_ERR(p) || cpu_online(cpu)) {
                /* CPU didn't die: tell everyone.  Can't complain. */
@@ -199,25 +282,50 @@ 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();
+       if (!err) {
+               if (raw_notifier_call_chain(&cpu_chain, CPU_POST_DEAD | mod,
+                                           hcpu) == NOTIFY_BAD)
+                       BUG();
+       }
        return err;
 }
 
-int cpu_down(unsigned int cpu)
+int __ref cpu_down(unsigned int cpu)
 {
        int err = 0;
 
-       mutex_lock(&cpu_add_remove_lock);
-       if (cpu_hotplug_disabled)
+       cpu_maps_update_begin();
+
+       if (cpu_hotplug_disabled) {
                err = -EBUSY;
-       else
-               err = _cpu_down(cpu, 0);
+               goto out;
+       }
 
-       mutex_unlock(&cpu_add_remove_lock);
+       cpu_clear(cpu, cpu_active_map);
+
+       /*
+        * Make sure the all cpus did the reschedule and are not
+        * using stale version of the cpu_active_map.
+        * This is not strictly necessary becuase stop_machine()
+        * that we run down the line already provides the required
+        * synchronization. But it's really a side effect and we do not
+        * want to depend on the innards of the stop_machine here.
+        */
+       synchronize_sched();
+
+       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 */
@@ -230,21 +338,19 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
        if (cpu_online(cpu) || !cpu_present(cpu))
                return -EINVAL;
 
-       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
+       cpu_hotplug_begin();
        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;
        }
 
        /* Arch-specific enabling code. */
-       mutex_lock(&cpu_bitmask_lock);
        ret = __cpu_up(cpu);
-       mutex_unlock(&cpu_bitmask_lock);
        if (ret != 0)
                goto out_notify;
        BUG_ON(!cpu_online(cpu));
@@ -256,7 +362,7 @@ 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;
 }
@@ -264,14 +370,30 @@ out_notify:
 int __cpuinit cpu_up(unsigned int cpu)
 {
        int err = 0;
+       if (!cpu_isset(cpu, cpu_possible_map)) {
+               printk(KERN_ERR "can't online cpu %d because it is not "
+                       "configured as may-hotadd at boot time\n", cpu);
+#if defined(CONFIG_IA64) || defined(CONFIG_X86_64) || defined(CONFIG_S390)
+               printk(KERN_ERR "please check additional_cpus= boot "
+                               "parameter\n");
+#endif
+               return -EINVAL;
+       }
 
-       mutex_lock(&cpu_add_remove_lock);
-       if (cpu_hotplug_disabled)
+       cpu_maps_update_begin();
+
+       if (cpu_hotplug_disabled) {
                err = -EBUSY;
-       else
-               err = _cpu_up(cpu, 0);
+               goto out;
+       }
 
-       mutex_unlock(&cpu_add_remove_lock);
+       err = _cpu_up(cpu, 0);
+
+       if (cpu_online(cpu))
+               cpu_set(cpu, cpu_active_map);
+
+out:
+       cpu_maps_update_done();
        return err;
 }
 
@@ -282,7 +404,7 @@ int disable_nonboot_cpus(void)
 {
        int cpu, first_cpu, error = 0;
 
-       mutex_lock(&cpu_add_remove_lock);
+       cpu_maps_update_begin();
        first_cpu = first_cpu(cpu_online_map);
        /* We take down all of the non-boot CPUs in one shot to avoid races
         * with the userspace trying to use the CPU hotplug at the same time
@@ -309,22 +431,22 @@ int disable_nonboot_cpus(void)
        } else {
                printk(KERN_ERR "Non-boot CPUs are not disabled\n");
        }
-       mutex_unlock(&cpu_add_remove_lock);
+       cpu_maps_update_done();
        return error;
 }
 
-void enable_nonboot_cpus(void)
+void __ref enable_nonboot_cpus(void)
 {
        int cpu, error;
 
        /* Allow everyone to use the CPU hotplug again */
-       mutex_lock(&cpu_add_remove_lock);
+       cpu_maps_update_begin();
        cpu_hotplug_disabled = 0;
        if (cpus_empty(frozen_cpus))
                goto out;
 
        printk("Enabling non-boot CPUs ...\n");
-       for_each_cpu_mask(cpu, frozen_cpus) {
+       for_each_cpu_mask_nr(cpu, frozen_cpus) {
                error = _cpu_up(cpu, 1);
                if (!error) {
                        printk("CPU%d is up\n", cpu);
@@ -334,6 +456,121 @@ void enable_nonboot_cpus(void)
        }
        cpus_clear(frozen_cpus);
 out:
-       mutex_unlock(&cpu_add_remove_lock);
+       cpu_maps_update_done();
 }
 #endif /* CONFIG_PM_SLEEP_SMP */
+
+#endif /* CONFIG_SMP */
+
+/* 64 bits of zeros, for initializers. */
+#if BITS_PER_LONG == 32
+#define Z64 0, 0
+#else
+#define Z64 0
+#endif
+
+/* Initializer macros. */
+#define CMI0(n) { .bits = { 1UL << (n) } }
+#define CMI(n, ...) { .bits = { __VA_ARGS__, 1UL << ((n) % BITS_PER_LONG) } }
+
+#define CMI8(n, ...)                                           \
+       CMI((n), __VA_ARGS__), CMI((n)+1, __VA_ARGS__),         \
+       CMI((n)+2, __VA_ARGS__), CMI((n)+3, __VA_ARGS__),       \
+       CMI((n)+4, __VA_ARGS__), CMI((n)+5, __VA_ARGS__),       \
+       CMI((n)+6, __VA_ARGS__), CMI((n)+7, __VA_ARGS__)
+
+#if BITS_PER_LONG == 32
+#define CMI64(n, ...)                                                  \
+       CMI8((n), __VA_ARGS__), CMI8((n)+8, __VA_ARGS__),               \
+       CMI8((n)+16, __VA_ARGS__), CMI8((n)+24, __VA_ARGS__),           \
+       CMI8((n)+32, 0, __VA_ARGS__), CMI8((n)+40, 0, __VA_ARGS__),     \
+       CMI8((n)+48, 0, __VA_ARGS__), CMI8((n)+56, 0, __VA_ARGS__)
+#else
+#define CMI64(n, ...)                                                  \
+       CMI8((n), __VA_ARGS__), CMI8((n)+8, __VA_ARGS__),               \
+       CMI8((n)+16, __VA_ARGS__), CMI8((n)+24, __VA_ARGS__),           \
+       CMI8((n)+32, __VA_ARGS__), CMI8((n)+40, __VA_ARGS__),   \
+       CMI8((n)+48, __VA_ARGS__), CMI8((n)+56, __VA_ARGS__)
+#endif
+
+#define CMI256(n, ...)                                                 \
+       CMI64((n), __VA_ARGS__), CMI64((n)+64, Z64, __VA_ARGS__),       \
+       CMI64((n)+128, Z64, Z64, __VA_ARGS__),                          \
+       CMI64((n)+192, Z64, Z64, Z64, __VA_ARGS__)
+#define Z256 Z64, Z64, Z64, Z64
+
+#define CMI1024(n, ...)                                        \
+       CMI256((n), __VA_ARGS__),                       \
+       CMI256((n)+256, Z256, __VA_ARGS__),             \
+       CMI256((n)+512, Z256, Z256, __VA_ARGS__),       \
+       CMI256((n)+768, Z256, Z256, Z256, __VA_ARGS__)
+#define Z1024 Z256, Z256, Z256, Z256
+
+/* We want this statically initialized, just to be safe.  We try not
+ * to waste too much space, either. */
+static const cpumask_t cpumask_map[]
+#ifdef CONFIG_HAVE_CPUMASK_OF_CPU_MAP
+__initdata
+#endif
+= {
+       CMI0(0), CMI0(1), CMI0(2), CMI0(3),
+#if NR_CPUS > 4
+       CMI0(4), CMI0(5), CMI0(6), CMI0(7),
+#endif
+#if NR_CPUS > 8
+       CMI0(8), CMI0(9), CMI0(10), CMI0(11),
+       CMI0(12), CMI0(13), CMI0(14), CMI0(15),
+#endif
+#if NR_CPUS > 16
+       CMI0(16), CMI0(17), CMI0(18), CMI0(19),
+       CMI0(20), CMI0(21), CMI0(22), CMI0(23),
+       CMI0(24), CMI0(25), CMI0(26), CMI0(27),
+       CMI0(28), CMI0(29), CMI0(30), CMI0(31),
+#endif
+#if NR_CPUS > 32
+#if BITS_PER_LONG == 32
+       CMI(32, 0), CMI(33, 0), CMI(34, 0), CMI(35, 0),
+       CMI(36, 0), CMI(37, 0), CMI(38, 0), CMI(39, 0),
+       CMI(40, 0), CMI(41, 0), CMI(42, 0), CMI(43, 0),
+       CMI(44, 0), CMI(45, 0), CMI(46, 0), CMI(47, 0),
+       CMI(48, 0), CMI(49, 0), CMI(50, 0), CMI(51, 0),
+       CMI(52, 0), CMI(53, 0), CMI(54, 0), CMI(55, 0),
+       CMI(56, 0), CMI(57, 0), CMI(58, 0), CMI(59, 0),
+       CMI(60, 0), CMI(61, 0), CMI(62, 0), CMI(63, 0),
+#else
+       CMI0(32), CMI0(33), CMI0(34), CMI0(35),
+       CMI0(36), CMI0(37), CMI0(38), CMI0(39),
+       CMI0(40), CMI0(41), CMI0(42), CMI0(43),
+       CMI0(44), CMI0(45), CMI0(46), CMI0(47),
+       CMI0(48), CMI0(49), CMI0(50), CMI0(51),
+       CMI0(52), CMI0(53), CMI0(54), CMI0(55),
+       CMI0(56), CMI0(57), CMI0(58), CMI0(59),
+       CMI0(60), CMI0(61), CMI0(62), CMI0(63),
+#endif /* BITS_PER_LONG == 64 */
+#endif
+#if NR_CPUS > 64
+       CMI64(64, Z64),
+#endif
+#if NR_CPUS > 128
+       CMI64(128, Z64, Z64), CMI64(192, Z64, Z64, Z64),
+#endif
+#if NR_CPUS > 256
+       CMI256(256, Z256),
+#endif
+#if NR_CPUS > 512
+       CMI256(512, Z256, Z256), CMI256(768, Z256, Z256, Z256),
+#endif
+#if NR_CPUS > 1024
+       CMI1024(1024, Z1024),
+#endif
+#if NR_CPUS > 2048
+       CMI1024(2048, Z1024, Z1024), CMI1024(3072, Z1024, Z1024, Z1024),
+#endif
+#if NR_CPUS > 4096
+#error NR_CPUS too big.  Fix initializers or set CONFIG_HAVE_CPUMASK_OF_CPU_MAP
+#endif
+};
+
+const cpumask_t *cpumask_of_cpu_map = cpumask_map;
+
+EXPORT_SYMBOL_GPL(cpumask_of_cpu_map);