diff options
Diffstat (limited to 'kernel/stop_machine.c')
| -rw-r--r-- | kernel/stop_machine.c | 55 |
1 files changed, 45 insertions, 10 deletions
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 286c41722e8c..0cd415ee62a2 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c | |||
| @@ -38,7 +38,10 @@ struct stop_machine_data { | |||
| 38 | static unsigned int num_threads; | 38 | static unsigned int num_threads; |
| 39 | static atomic_t thread_ack; | 39 | static atomic_t thread_ack; |
| 40 | static DEFINE_MUTEX(lock); | 40 | static DEFINE_MUTEX(lock); |
| 41 | 41 | /* setup_lock protects refcount, stop_machine_wq and stop_machine_work. */ | |
| 42 | static DEFINE_MUTEX(setup_lock); | ||
| 43 | /* Users of stop_machine. */ | ||
| 44 | static int refcount; | ||
| 42 | static struct workqueue_struct *stop_machine_wq; | 45 | static struct workqueue_struct *stop_machine_wq; |
| 43 | static struct stop_machine_data active, idle; | 46 | static struct stop_machine_data active, idle; |
| 44 | static const cpumask_t *active_cpus; | 47 | static const cpumask_t *active_cpus; |
| @@ -109,6 +112,43 @@ static int chill(void *unused) | |||
| 109 | return 0; | 112 | return 0; |
| 110 | } | 113 | } |
| 111 | 114 | ||
| 115 | int stop_machine_create(void) | ||
| 116 | { | ||
| 117 | mutex_lock(&setup_lock); | ||
| 118 | if (refcount) | ||
| 119 | goto done; | ||
| 120 | stop_machine_wq = create_rt_workqueue("kstop"); | ||
| 121 | if (!stop_machine_wq) | ||
| 122 | goto err_out; | ||
| 123 | stop_machine_work = alloc_percpu(struct work_struct); | ||
| 124 | if (!stop_machine_work) | ||
| 125 | goto err_out; | ||
| 126 | done: | ||
| 127 | refcount++; | ||
| 128 | mutex_unlock(&setup_lock); | ||
| 129 | return 0; | ||
| 130 | |||
| 131 | err_out: | ||
| 132 | if (stop_machine_wq) | ||
| 133 | destroy_workqueue(stop_machine_wq); | ||
| 134 | mutex_unlock(&setup_lock); | ||
| 135 | return -ENOMEM; | ||
| 136 | } | ||
| 137 | EXPORT_SYMBOL_GPL(stop_machine_create); | ||
| 138 | |||
| 139 | void stop_machine_destroy(void) | ||
| 140 | { | ||
| 141 | mutex_lock(&setup_lock); | ||
| 142 | refcount--; | ||
| 143 | if (refcount) | ||
| 144 | goto done; | ||
| 145 | destroy_workqueue(stop_machine_wq); | ||
| 146 | free_percpu(stop_machine_work); | ||
| 147 | done: | ||
| 148 | mutex_unlock(&setup_lock); | ||
| 149 | } | ||
| 150 | EXPORT_SYMBOL_GPL(stop_machine_destroy); | ||
| 151 | |||
| 112 | int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus) | 152 | int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus) |
| 113 | { | 153 | { |
| 114 | struct work_struct *sm_work; | 154 | struct work_struct *sm_work; |
| @@ -146,19 +186,14 @@ int stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus) | |||
| 146 | { | 186 | { |
| 147 | int ret; | 187 | int ret; |
| 148 | 188 | ||
| 189 | ret = stop_machine_create(); | ||
| 190 | if (ret) | ||
| 191 | return ret; | ||
| 149 | /* No CPUs can come up or down during this. */ | 192 | /* No CPUs can come up or down during this. */ |
| 150 | get_online_cpus(); | 193 | get_online_cpus(); |
| 151 | ret = __stop_machine(fn, data, cpus); | 194 | ret = __stop_machine(fn, data, cpus); |
| 152 | put_online_cpus(); | 195 | put_online_cpus(); |
| 153 | 196 | stop_machine_destroy(); | |
| 154 | return ret; | 197 | return ret; |
| 155 | } | 198 | } |
| 156 | EXPORT_SYMBOL_GPL(stop_machine); | 199 | EXPORT_SYMBOL_GPL(stop_machine); |
| 157 | |||
| 158 | static int __init stop_machine_init(void) | ||
| 159 | { | ||
| 160 | stop_machine_wq = create_rt_workqueue("kstop"); | ||
| 161 | stop_machine_work = alloc_percpu(struct work_struct); | ||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | core_initcall(stop_machine_init); | ||
