aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/stop_machine.h8
-rw-r--r--kernel/stop_machine.c32
2 files changed, 32 insertions, 8 deletions
diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h
index 5bfc553bdb21..18af011c13af 100644
--- a/include/linux/stop_machine.h
+++ b/include/linux/stop_machine.h
@@ -8,11 +8,17 @@
8#include <asm/system.h> 8#include <asm/system.h>
9 9
10#if defined(CONFIG_STOP_MACHINE) && defined(CONFIG_SMP) 10#if defined(CONFIG_STOP_MACHINE) && defined(CONFIG_SMP)
11
12#define ALL_CPUS ~0U
13
11/** 14/**
12 * stop_machine_run: freeze the machine on all CPUs and run this function 15 * stop_machine_run: freeze the machine on all CPUs and run this function
13 * @fn: the function to run 16 * @fn: the function to run
14 * @data: the data ptr for the @fn() 17 * @data: the data ptr for the @fn()
15 * @cpu: the cpu to run @fn() on (or any, if @cpu == NR_CPUS. 18 * @cpu: if @cpu == n, run @fn() on cpu n
19 * if @cpu == NR_CPUS, run @fn() on any cpu
20 * if @cpu == ALL_CPUS, run @fn() first on the calling cpu, and then
21 * concurrently on all the other cpus
16 * 22 *
17 * Description: This causes a thread to be scheduled on every other cpu, 23 * Description: This causes a thread to be scheduled on every other cpu,
18 * each of which disables interrupts, and finally interrupts are disabled 24 * each of which disables interrupts, and finally interrupts are disabled
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index 738b411ff2d3..a473bd0cb71b 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -22,9 +22,17 @@ enum stopmachine_state {
22 STOPMACHINE_WAIT, 22 STOPMACHINE_WAIT,
23 STOPMACHINE_PREPARE, 23 STOPMACHINE_PREPARE,
24 STOPMACHINE_DISABLE_IRQ, 24 STOPMACHINE_DISABLE_IRQ,
25 STOPMACHINE_RUN,
25 STOPMACHINE_EXIT, 26 STOPMACHINE_EXIT,
26}; 27};
27 28
29struct stop_machine_data {
30 int (*fn)(void *);
31 void *data;
32 struct completion done;
33 int run_all;
34} smdata;
35
28static enum stopmachine_state stopmachine_state; 36static enum stopmachine_state stopmachine_state;
29static unsigned int stopmachine_num_threads; 37static unsigned int stopmachine_num_threads;
30static atomic_t stopmachine_thread_ack; 38static atomic_t stopmachine_thread_ack;
@@ -33,6 +41,7 @@ static int stopmachine(void *cpu)
33{ 41{
34 int irqs_disabled = 0; 42 int irqs_disabled = 0;
35 int prepared = 0; 43 int prepared = 0;
44 int ran = 0;
36 cpumask_of_cpu_ptr(cpumask, (int)(long)cpu); 45 cpumask_of_cpu_ptr(cpumask, (int)(long)cpu);
37 46
38 set_cpus_allowed_ptr(current, cpumask); 47 set_cpus_allowed_ptr(current, cpumask);
@@ -58,6 +67,11 @@ static int stopmachine(void *cpu)
58 prepared = 1; 67 prepared = 1;
59 smp_mb(); /* Must read state first. */ 68 smp_mb(); /* Must read state first. */
60 atomic_inc(&stopmachine_thread_ack); 69 atomic_inc(&stopmachine_thread_ack);
70 } else if (stopmachine_state == STOPMACHINE_RUN && !ran) {
71 smdata.fn(smdata.data);
72 ran = 1;
73 smp_mb(); /* Must read state first. */
74 atomic_inc(&stopmachine_thread_ack);
61 } 75 }
62 /* Yield in first stage: migration threads need to 76 /* Yield in first stage: migration threads need to
63 * help our sisters onto their CPUs. */ 77 * help our sisters onto their CPUs. */
@@ -136,11 +150,10 @@ static void restart_machine(void)
136 preempt_enable_no_resched(); 150 preempt_enable_no_resched();
137} 151}
138 152
139struct stop_machine_data { 153static void run_other_cpus(void)
140 int (*fn)(void *); 154{
141 void *data; 155 stopmachine_set_state(STOPMACHINE_RUN);
142 struct completion done; 156}
143};
144 157
145static int do_stop(void *_smdata) 158static int do_stop(void *_smdata)
146{ 159{
@@ -150,6 +163,8 @@ static int do_stop(void *_smdata)
150 ret = stop_machine(); 163 ret = stop_machine();
151 if (ret == 0) { 164 if (ret == 0) {
152 ret = smdata->fn(smdata->data); 165 ret = smdata->fn(smdata->data);
166 if (smdata->run_all)
167 run_other_cpus();
153 restart_machine(); 168 restart_machine();
154 } 169 }
155 170
@@ -173,14 +188,17 @@ struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
173 struct stop_machine_data smdata; 188 struct stop_machine_data smdata;
174 struct task_struct *p; 189 struct task_struct *p;
175 190
191 mutex_lock(&stopmachine_mutex);
192
176 smdata.fn = fn; 193 smdata.fn = fn;
177 smdata.data = data; 194 smdata.data = data;
195 smdata.run_all = (cpu == ALL_CPUS) ? 1 : 0;
178 init_completion(&smdata.done); 196 init_completion(&smdata.done);
179 197
180 mutex_lock(&stopmachine_mutex); 198 smp_wmb(); /* make sure other cpus see smdata updates */
181 199
182 /* If they don't care which CPU fn runs on, bind to any online one. */ 200 /* If they don't care which CPU fn runs on, bind to any online one. */
183 if (cpu == NR_CPUS) 201 if (cpu == NR_CPUS || cpu == ALL_CPUS)
184 cpu = raw_smp_processor_id(); 202 cpu = raw_smp_processor_id();
185 203
186 p = kthread_create(do_stop, &smdata, "kstopmachine"); 204 p = kthread_create(do_stop, &smdata, "kstopmachine");