sysctl extern cleanup: module
[linux-2.6.git] / kernel / stop_machine.c
index 286c417..9bb9fb1 100644 (file)
@@ -38,11 +38,14 @@ struct stop_machine_data {
 static unsigned int num_threads;
 static atomic_t thread_ack;
 static DEFINE_MUTEX(lock);
-
+/* setup_lock protects refcount, stop_machine_wq and stop_machine_work. */
+static DEFINE_MUTEX(setup_lock);
+/* Users of stop_machine. */
+static int refcount;
 static struct workqueue_struct *stop_machine_wq;
 static struct stop_machine_data active, idle;
-static const cpumask_t *active_cpus;
-static void *stop_machine_work;
+static const struct cpumask *active_cpus;
+static void __percpu *stop_machine_work;
 
 static void set_state(enum stopmachine_state newstate)
 {
@@ -109,6 +112,43 @@ static int chill(void *unused)
        return 0;
 }
 
+int stop_machine_create(void)
+{
+       mutex_lock(&setup_lock);
+       if (refcount)
+               goto done;
+       stop_machine_wq = create_rt_workqueue("kstop");
+       if (!stop_machine_wq)
+               goto err_out;
+       stop_machine_work = alloc_percpu(struct work_struct);
+       if (!stop_machine_work)
+               goto err_out;
+done:
+       refcount++;
+       mutex_unlock(&setup_lock);
+       return 0;
+
+err_out:
+       if (stop_machine_wq)
+               destroy_workqueue(stop_machine_wq);
+       mutex_unlock(&setup_lock);
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(stop_machine_create);
+
+void stop_machine_destroy(void)
+{
+       mutex_lock(&setup_lock);
+       refcount--;
+       if (refcount)
+               goto done;
+       destroy_workqueue(stop_machine_wq);
+       free_percpu(stop_machine_work);
+done:
+       mutex_unlock(&setup_lock);
+}
+EXPORT_SYMBOL_GPL(stop_machine_destroy);
+
 int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus)
 {
        struct work_struct *sm_work;
@@ -130,7 +170,7 @@ int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus)
         * doesn't hit this CPU until we're ready. */
        get_cpu();
        for_each_online_cpu(i) {
-               sm_work = percpu_ptr(stop_machine_work, i);
+               sm_work = per_cpu_ptr(stop_machine_work, i);
                INIT_WORK(sm_work, stop_cpu);
                queue_work_on(i, stop_machine_wq, sm_work);
        }
@@ -146,19 +186,14 @@ int stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus)
 {
        int ret;
 
+       ret = stop_machine_create();
+       if (ret)
+               return ret;
        /* No CPUs can come up or down during this. */
        get_online_cpus();
        ret = __stop_machine(fn, data, cpus);
        put_online_cpus();
-
+       stop_machine_destroy();
        return ret;
 }
 EXPORT_SYMBOL_GPL(stop_machine);
-
-static int __init stop_machine_init(void)
-{
-       stop_machine_wq = create_rt_workqueue("kstop");
-       stop_machine_work = alloc_percpu(struct work_struct);
-       return 0;
-}
-core_initcall(stop_machine_init);