microblaze: uaccess: fix put_user and get_user macros
[linux-2.6.git] / kernel / stop_machine.c
index 0e688c6..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)
 {
@@ -66,12 +69,13 @@ static void stop_cpu(struct work_struct *unused)
        enum stopmachine_state curstate = STOPMACHINE_NONE;
        struct stop_machine_data *smdata = &idle;
        int cpu = smp_processor_id();
+       int err;
 
        if (!active_cpus) {
-               if (cpu == first_cpu(cpu_online_map))
+               if (cpu == cpumask_first(cpu_online_mask))
                        smdata = &active;
        } else {
-               if (cpu_isset(cpu, *active_cpus))
+               if (cpumask_test_cpu(cpu, active_cpus))
                        smdata = &active;
        }
        /* Simple state machine */
@@ -86,9 +90,11 @@ static void stop_cpu(struct work_struct *unused)
                                hard_irq_disable();
                                break;
                        case STOPMACHINE_RUN:
-                               /* |= allows error detection if functions on
-                                * multiple CPUs. */
-                               smdata->fnret |= smdata->fn(smdata->data);
+                               /* On multiple CPUs only a single error code
+                                * is needed to tell that something failed. */
+                               err = smdata->fn(smdata->data);
+                               if (err)
+                                       smdata->fnret = err;
                                break;
                        default:
                                break;
@@ -106,10 +112,47 @@ static int chill(void *unused)
        return 0;
 }
 
-int __stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus)
+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;
-       int i;
+       int i, ret;
 
        /* Set up initial state. */
        mutex_lock(&lock);
@@ -127,34 +170,30 @@ int __stop_machine(int (*fn)(void *), void *data, const cpumask_t *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);
        }
        /* This will release the thread on our CPU. */
        put_cpu();
        flush_workqueue(stop_machine_wq);
+       ret = active.fnret;
        mutex_unlock(&lock);
-       return active.fnret;
+       return ret;
 }
 
-int stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus)
+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;
-}
-early_initcall(stop_machine_init);