aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/stop_machine.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/stop_machine.c')
-rw-r--r--kernel/stop_machine.c26
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;
40static DEFINE_MUTEX(lock); 40static 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. */
42static DEFINE_MUTEX(setup_lock); 42static DEFINE_MUTEX(setup_lock);
43/* do not start up until all worklets have been placed: */
44static DEFINE_MUTEX(startup_lock);
43/* Users of stop_machine. */ 45/* Users of stop_machine. */
44static int refcount; 46static int refcount;
45static struct workqueue_struct *stop_machine_wq; 47static 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);