diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/cpu.c | 6 | ||||
| -rw-r--r-- | kernel/stop_machine.c | 55 |
2 files changed, 50 insertions, 11 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c index 47fff3b63cbf..30e74dd6d01b 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
| @@ -269,8 +269,11 @@ out_release: | |||
| 269 | 269 | ||
| 270 | int __ref cpu_down(unsigned int cpu) | 270 | int __ref cpu_down(unsigned int cpu) |
| 271 | { | 271 | { |
| 272 | int err = 0; | 272 | int err; |
| 273 | 273 | ||
| 274 | err = stop_machine_create(); | ||
| 275 | if (err) | ||
| 276 | return err; | ||
| 274 | cpu_maps_update_begin(); | 277 | cpu_maps_update_begin(); |
| 275 | 278 | ||
| 276 | if (cpu_hotplug_disabled) { | 279 | if (cpu_hotplug_disabled) { |
| @@ -297,6 +300,7 @@ int __ref cpu_down(unsigned int cpu) | |||
| 297 | 300 | ||
| 298 | out: | 301 | out: |
| 299 | cpu_maps_update_done(); | 302 | cpu_maps_update_done(); |
| 303 | stop_machine_destroy(); | ||
| 300 | return err; | 304 | return err; |
| 301 | } | 305 | } |
| 302 | EXPORT_SYMBOL(cpu_down); | 306 | EXPORT_SYMBOL(cpu_down); |
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); | ||
