diff options
Diffstat (limited to 'kernel/stop_machine.c')
-rw-r--r-- | kernel/stop_machine.c | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 912823e2a11b..22d1d77f9a62 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c | |||
@@ -40,6 +40,8 @@ static atomic_t thread_ack; | |||
40 | static DEFINE_MUTEX(lock); | 40 | static DEFINE_MUTEX(lock); |
41 | /* setup_lock protects refcount, stop_machine_wq and stop_machine_work. */ | 41 | /* setup_lock protects refcount, stop_machine_wq and stop_machine_work. */ |
42 | static DEFINE_MUTEX(setup_lock); | 42 | static DEFINE_MUTEX(setup_lock); |
43 | /* do not start up until all worklets have been placed: */ | ||
44 | static DEFINE_MUTEX(startup_lock); | ||
43 | /* Users of stop_machine. */ | 45 | /* Users of stop_machine. */ |
44 | static int refcount; | 46 | static int refcount; |
45 | static struct workqueue_struct *stop_machine_wq; | 47 | static struct workqueue_struct *stop_machine_wq; |
@@ -71,6 +73,15 @@ static void stop_cpu(struct work_struct *unused) | |||
71 | int cpu = smp_processor_id(); | 73 | int cpu = smp_processor_id(); |
72 | int err; | 74 | int err; |
73 | 75 | ||
76 | /* | ||
77 | * Wait for the startup loop to finish: | ||
78 | */ | ||
79 | mutex_lock(&startup_lock); | ||
80 | /* | ||
81 | * Let other threads continue too: | ||
82 | */ | ||
83 | mutex_unlock(&startup_lock); | ||
84 | |||
74 | if (!active_cpus) { | 85 | if (!active_cpus) { |
75 | if (cpu == cpumask_first(cpu_online_mask)) | 86 | if (cpu == cpumask_first(cpu_online_mask)) |
76 | smdata = &active; | 87 | smdata = &active; |
@@ -166,16 +177,21 @@ int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus) | |||
166 | 177 | ||
167 | set_state(STOPMACHINE_PREPARE); | 178 | set_state(STOPMACHINE_PREPARE); |
168 | 179 | ||
169 | /* Schedule the stop_cpu work on all cpus: hold this CPU so one | 180 | /* |
170 | * doesn't hit this CPU until we're ready. */ | 181 | * Schedule the stop_cpu work on all cpus before allowing any |
171 | get_cpu(); | 182 | * of the CPUs to execute it: |
183 | */ | ||
184 | mutex_lock(&startup_lock); | ||
185 | |||
172 | for_each_online_cpu(i) { | 186 | for_each_online_cpu(i) { |
173 | sm_work = per_cpu_ptr(stop_machine_work, i); | 187 | sm_work = per_cpu_ptr(stop_machine_work, i); |
174 | INIT_WORK(sm_work, stop_cpu); | 188 | INIT_WORK(sm_work, stop_cpu); |
175 | queue_work_on(i, stop_machine_wq, sm_work); | 189 | queue_work_on(i, stop_machine_wq, sm_work); |
176 | } | 190 | } |
177 | /* This will release the thread on our CPU. */ | 191 | |
178 | put_cpu(); | 192 | /* This will release the thread on all CPUs: */ |
193 | mutex_unlock(&startup_lock); | ||
194 | |||
179 | flush_workqueue(stop_machine_wq); | 195 | flush_workqueue(stop_machine_wq); |
180 | ret = active.fnret; | 196 | ret = active.fnret; |
181 | mutex_unlock(&lock); | 197 | mutex_unlock(&lock); |