cpu-hotplug: export cpu_hotplug_enable/cpu_hotplug_disable
[cascardo/linux.git] / kernel / cpu.c
index 9c9c9fa..718ea76 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/suspend.h>
 #include <linux/lockdep.h>
 #include <linux/tick.h>
+#include <linux/irq.h>
 #include <trace/events/power.h>
 
 #include "smpboot.h"
@@ -190,17 +191,18 @@ void cpu_hotplug_done(void)
 void cpu_hotplug_disable(void)
 {
        cpu_maps_update_begin();
-       cpu_hotplug_disabled = 1;
+       cpu_hotplug_disabled++;
        cpu_maps_update_done();
 }
+EXPORT_SYMBOL_GPL(cpu_hotplug_disable);
 
 void cpu_hotplug_enable(void)
 {
        cpu_maps_update_begin();
-       cpu_hotplug_disabled = 0;
+       WARN_ON(--cpu_hotplug_disabled < 0);
        cpu_maps_update_done();
 }
-
+EXPORT_SYMBOL_GPL(cpu_hotplug_enable);
 #endif /* CONFIG_HOTPLUG_CPU */
 
 /* Need to know about CPUs going up/down? */
@@ -392,13 +394,19 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
        smpboot_park_threads(cpu);
 
        /*
-        * So now all preempt/rcu users must observe !cpu_active().
+        * Prevent irq alloc/free while the dying cpu reorganizes the
+        * interrupt affinities.
         */
+       irq_lock_sparse();
 
+       /*
+        * So now all preempt/rcu users must observe !cpu_active().
+        */
        err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu));
        if (err) {
                /* CPU didn't die: tell everyone.  Can't complain. */
                cpu_notify_nofail(CPU_DOWN_FAILED | mod, hcpu);
+               irq_unlock_sparse();
                goto out_release;
        }
        BUG_ON(cpu_online(cpu));
@@ -415,6 +423,9 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
        smp_mb(); /* Read from cpu_dead_idle before __cpu_die(). */
        per_cpu(cpu_dead_idle, cpu) = false;
 
+       /* Interrupts are moved away from the dying cpu, reenable alloc/free */
+       irq_unlock_sparse();
+
        hotplug_cpu__broadcast_tick_pull(cpu);
        /* This actually kills the CPU. */
        __cpu_die(cpu);
@@ -519,6 +530,7 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen)
 
        /* Arch-specific enabling code. */
        ret = __cpu_up(cpu, idle);
+
        if (ret != 0)
                goto out_notify;
        BUG_ON(!cpu_online(cpu));
@@ -597,13 +609,18 @@ int disable_nonboot_cpus(void)
                }
        }
 
-       if (!error) {
+       if (!error)
                BUG_ON(num_online_cpus() > 1);
-               /* Make sure the CPUs won't be enabled by someone else */
-               cpu_hotplug_disabled = 1;
-       } else {
+       else
                pr_err("Non-boot CPUs are not disabled\n");
-       }
+
+       /*
+        * Make sure the CPUs won't be enabled by someone else. We need to do
+        * this even in case of failure as all disable_nonboot_cpus() users are
+        * supposed to do enable_nonboot_cpus() on the failure path.
+        */
+       cpu_hotplug_disabled++;
+
        cpu_maps_update_done();
        return error;
 }
@@ -622,7 +639,7 @@ void __ref enable_nonboot_cpus(void)
 
        /* Allow everyone to use the CPU hotplug again */
        cpu_maps_update_begin();
-       cpu_hotplug_disabled = 0;
+       WARN_ON(--cpu_hotplug_disabled < 0);
        if (cpumask_empty(frozen_cpus))
                goto out;