netns xfrm: fix "ip xfrm state|policy count" misreport
[safe/jmp/linux-2.6] / kernel / cpu.c
index 5a732c5..1c8ddd6 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 */
+#ifdef CONFIG_SMP
+/* Serializes the updates to cpu_online_mask, cpu_present_mask */
 static DEFINE_MUTEX(cpu_add_remove_lock);
 
 static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
@@ -55,16 +34,11 @@ static struct {
         * 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;
-}
-
-cpumask_t cpu_active_map;
+} cpu_hotplug = {
+       .active_writer = NULL,
+       .lock = __MUTEX_INITIALIZER(cpu_hotplug.lock),
+       .refcount = 0,
+};
 
 #ifdef CONFIG_HOTPLUG_CPU
 
@@ -96,7 +70,7 @@ EXPORT_SYMBOL_GPL(put_online_cpus);
 
 /*
  * The following two API's must be used when attempting
- * to serialize the updates to cpu_online_map, cpu_present_map.
+ * to serialize the updates to cpu_online_mask, cpu_present_mask.
  */
 void cpu_maps_update_begin(void)
 {
@@ -217,7 +191,7 @@ static int __ref take_cpu_down(void *_param)
 static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
 {
        int err, nr_calls = 0;
-       cpumask_t old_allowed, tmp;
+       cpumask_var_t old_allowed;
        void *hcpu = (void *)(long)cpu;
        unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
        struct take_cpu_down_param tcd_param = {
@@ -231,10 +205,16 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
        if (!cpu_online(cpu))
                return -EINVAL;
 
+       if (!alloc_cpumask_var(&old_allowed, GFP_KERNEL))
+               return -ENOMEM;
+
        cpu_hotplug_begin();
+       set_cpu_active(cpu, false);
        err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod,
                                        hcpu, -1, &nr_calls);
        if (err == NOTIFY_BAD) {
+               set_cpu_active(cpu, true);
+
                nr_calls--;
                __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
                                          hcpu, nr_calls, NULL);
@@ -245,14 +225,12 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
        }
 
        /* Ensure that we are not runnable on dying cpu */
-       old_allowed = current->cpus_allowed;
-       cpus_setall(tmp);
-       cpu_clear(cpu, tmp);
-       set_cpus_allowed_ptr(current, &tmp);
-       tmp = cpumask_of_cpu(cpu);
+       cpumask_copy(old_allowed, &current->cpus_allowed);
+       set_cpus_allowed_ptr(current, cpu_active_mask);
 
-       err = __stop_machine(take_cpu_down, &tcd_param, &tmp);
+       err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu));
        if (err) {
+               set_cpu_active(cpu, true);
                /* CPU didn't die: tell everyone.  Can't complain. */
                if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
                                            hcpu) == NOTIFY_BAD)
@@ -277,7 +255,7 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
        check_for_tasks(cpu);
 
 out_allowed:
-       set_cpus_allowed_ptr(current, &old_allowed);
+       set_cpus_allowed_ptr(current, old_allowed);
 out_release:
        cpu_hotplug_done();
        if (!err) {
@@ -285,13 +263,17 @@ out_release:
                                            hcpu) == NOTIFY_BAD)
                        BUG();
        }
+       free_cpumask_var(old_allowed);
        return err;
 }
 
 int __ref cpu_down(unsigned int cpu)
 {
-       int err = 0;
+       int err;
 
+       err = stop_machine_create();
+       if (err)
+               return err;
        cpu_maps_update_begin();
 
        if (cpu_hotplug_disabled) {
@@ -299,25 +281,11 @@ int __ref cpu_down(unsigned int cpu)
                goto out;
        }
 
-       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();
+       stop_machine_destroy();
        return err;
 }
 EXPORT_SYMBOL(cpu_down);
@@ -350,7 +318,7 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
                goto out_notify;
        BUG_ON(!cpu_online(cpu));
 
-       cpu_set(cpu, cpu_active_map);
+       set_cpu_active(cpu, true);
 
        /* Now call notifier in preparation. */
        raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu);
@@ -367,7 +335,7 @@ out_notify:
 int __cpuinit cpu_up(unsigned int cpu)
 {
        int err = 0;
-       if (!cpu_isset(cpu, cpu_possible_map)) {
+       if (!cpu_possible(cpu)) {
                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)
@@ -392,32 +360,37 @@ out:
 }
 
 #ifdef CONFIG_PM_SLEEP_SMP
-static cpumask_t frozen_cpus;
+static cpumask_var_t frozen_cpus;
 
 int disable_nonboot_cpus(void)
 {
-       int cpu, first_cpu, error = 0;
+       int cpu, first_cpu, error;
 
+       error = stop_machine_create();
+       if (error)
+               return error;
        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
+       first_cpu = cpumask_first(cpu_online_mask);
+       /*
+        * 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
         */
-       cpus_clear(frozen_cpus);
+       cpumask_clear(frozen_cpus);
+
        printk("Disabling non-boot CPUs ...\n");
        for_each_online_cpu(cpu) {
                if (cpu == first_cpu)
                        continue;
                error = _cpu_down(cpu, 1);
-               if (!error) {
-                       cpu_set(cpu, frozen_cpus);
-                       printk("CPU%d is down\n", cpu);
-               } else {
+               if (!error)
+                       cpumask_set_cpu(cpu, frozen_cpus);
+               else {
                        printk(KERN_ERR "Error taking CPU%d down: %d\n",
                                cpu, error);
                        break;
                }
        }
+
        if (!error) {
                BUG_ON(num_online_cpus() > 1);
                /* Make sure the CPUs won't be enabled by someone else */
@@ -426,9 +399,18 @@ int disable_nonboot_cpus(void)
                printk(KERN_ERR "Non-boot CPUs are not disabled\n");
        }
        cpu_maps_update_done();
+       stop_machine_destroy();
        return error;
 }
 
+void __weak arch_enable_nonboot_cpus_begin(void)
+{
+}
+
+void __weak arch_enable_nonboot_cpus_end(void)
+{
+}
+
 void __ref enable_nonboot_cpus(void)
 {
        int cpu, error;
@@ -436,11 +418,14 @@ void __ref enable_nonboot_cpus(void)
        /* Allow everyone to use the CPU hotplug again */
        cpu_maps_update_begin();
        cpu_hotplug_disabled = 0;
-       if (cpus_empty(frozen_cpus))
+       if (cpumask_empty(frozen_cpus))
                goto out;
 
        printk("Enabling non-boot CPUs ...\n");
-       for_each_cpu_mask_nr(cpu, frozen_cpus) {
+
+       arch_enable_nonboot_cpus_begin();
+
+       for_each_cpu(cpu, frozen_cpus) {
                error = _cpu_up(cpu, 1);
                if (!error) {
                        printk("CPU%d is up\n", cpu);
@@ -448,10 +433,21 @@ void __ref enable_nonboot_cpus(void)
                }
                printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
        }
-       cpus_clear(frozen_cpus);
+
+       arch_enable_nonboot_cpus_end();
+
+       cpumask_clear(frozen_cpus);
 out:
        cpu_maps_update_done();
 }
+
+static int alloc_frozen_cpus(void)
+{
+       if (!alloc_cpumask_var(&frozen_cpus, GFP_KERNEL|__GFP_ZERO))
+               return -ENOMEM;
+       return 0;
+}
+core_initcall(alloc_frozen_cpus);
 #endif /* CONFIG_PM_SLEEP_SMP */
 
 /**
@@ -462,12 +458,12 @@ out:
  * It must be called by the arch code on the new cpu, before the new cpu
  * enables interrupts and before the "boot" cpu returns from __cpu_up().
  */
-void notify_cpu_starting(unsigned int cpu)
+void __cpuinit notify_cpu_starting(unsigned int cpu)
 {
        unsigned long val = CPU_STARTING;
 
 #ifdef CONFIG_PM_SLEEP_SMP
-       if (cpu_isset(cpu, frozen_cpus))
+       if (frozen_cpus != NULL && cpumask_test_cpu(cpu, frozen_cpus))
                val = CPU_STARTING_FROZEN;
 #endif /* CONFIG_PM_SLEEP_SMP */
        raw_notifier_call_chain(&cpu_chain, val, (void *)(long)cpu);
@@ -479,7 +475,7 @@ void notify_cpu_starting(unsigned int cpu)
  * cpu_bit_bitmap[] is a special, "compressed" data structure that
  * represents all NR_CPUS bits binary values of 1<<nr.
  *
- * It is used by cpumask_of_cpu() to get a constant address to a CPU
+ * It is used by cpumask_of() to get a constant address to a CPU
  * mask value that has a single bit set only.
  */
 
@@ -502,3 +498,71 @@ EXPORT_SYMBOL_GPL(cpu_bit_bitmap);
 
 const DECLARE_BITMAP(cpu_all_bits, NR_CPUS) = CPU_BITS_ALL;
 EXPORT_SYMBOL(cpu_all_bits);
+
+#ifdef CONFIG_INIT_ALL_POSSIBLE
+static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly
+       = CPU_BITS_ALL;
+#else
+static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
+#endif
+const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
+EXPORT_SYMBOL(cpu_possible_mask);
+
+static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly;
+const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits);
+EXPORT_SYMBOL(cpu_online_mask);
+
+static DECLARE_BITMAP(cpu_present_bits, CONFIG_NR_CPUS) __read_mostly;
+const struct cpumask *const cpu_present_mask = to_cpumask(cpu_present_bits);
+EXPORT_SYMBOL(cpu_present_mask);
+
+static DECLARE_BITMAP(cpu_active_bits, CONFIG_NR_CPUS) __read_mostly;
+const struct cpumask *const cpu_active_mask = to_cpumask(cpu_active_bits);
+EXPORT_SYMBOL(cpu_active_mask);
+
+void set_cpu_possible(unsigned int cpu, bool possible)
+{
+       if (possible)
+               cpumask_set_cpu(cpu, to_cpumask(cpu_possible_bits));
+       else
+               cpumask_clear_cpu(cpu, to_cpumask(cpu_possible_bits));
+}
+
+void set_cpu_present(unsigned int cpu, bool present)
+{
+       if (present)
+               cpumask_set_cpu(cpu, to_cpumask(cpu_present_bits));
+       else
+               cpumask_clear_cpu(cpu, to_cpumask(cpu_present_bits));
+}
+
+void set_cpu_online(unsigned int cpu, bool online)
+{
+       if (online)
+               cpumask_set_cpu(cpu, to_cpumask(cpu_online_bits));
+       else
+               cpumask_clear_cpu(cpu, to_cpumask(cpu_online_bits));
+}
+
+void set_cpu_active(unsigned int cpu, bool active)
+{
+       if (active)
+               cpumask_set_cpu(cpu, to_cpumask(cpu_active_bits));
+       else
+               cpumask_clear_cpu(cpu, to_cpumask(cpu_active_bits));
+}
+
+void init_cpu_present(const struct cpumask *src)
+{
+       cpumask_copy(to_cpumask(cpu_present_bits), src);
+}
+
+void init_cpu_possible(const struct cpumask *src)
+{
+       cpumask_copy(to_cpumask(cpu_possible_bits), src);
+}
+
+void init_cpu_online(const struct cpumask *src)
+{
+       cpumask_copy(to_cpumask(cpu_online_bits), src);
+}