diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-10-20 06:22:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-10-20 06:22:25 -0400 |
commit | 589f1222e043ab1f5cbce558cfaed0c0fa76e7bb (patch) | |
tree | 0e054ea811a6bd5ff40854a352abe1b6eba0c1ab /kernel | |
parent | 531e93d11470aa2e14e6a3febef50d9bc7bab7a1 (diff) | |
parent | b1fc5833357524d5d342737913dbe32ff3557bc5 (diff) |
Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull stop-machine fix from Thomas Gleixner:
"A single fix, amending stop machine with WRITE/READ_ONCE() to address
the fallout of KCSAN"
* 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
stop_machine: Avoid potential race behaviour
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/stop_machine.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index c7031a22aa7b..998d50ee2d9b 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * Copyright (C) 2010 SUSE Linux Products GmbH | 7 | * Copyright (C) 2010 SUSE Linux Products GmbH |
8 | * Copyright (C) 2010 Tejun Heo <tj@kernel.org> | 8 | * Copyright (C) 2010 Tejun Heo <tj@kernel.org> |
9 | */ | 9 | */ |
10 | #include <linux/compiler.h> | ||
10 | #include <linux/completion.h> | 11 | #include <linux/completion.h> |
11 | #include <linux/cpu.h> | 12 | #include <linux/cpu.h> |
12 | #include <linux/init.h> | 13 | #include <linux/init.h> |
@@ -167,7 +168,7 @@ static void set_state(struct multi_stop_data *msdata, | |||
167 | /* Reset ack counter. */ | 168 | /* Reset ack counter. */ |
168 | atomic_set(&msdata->thread_ack, msdata->num_threads); | 169 | atomic_set(&msdata->thread_ack, msdata->num_threads); |
169 | smp_wmb(); | 170 | smp_wmb(); |
170 | msdata->state = newstate; | 171 | WRITE_ONCE(msdata->state, newstate); |
171 | } | 172 | } |
172 | 173 | ||
173 | /* Last one to ack a state moves to the next state. */ | 174 | /* Last one to ack a state moves to the next state. */ |
@@ -186,7 +187,7 @@ void __weak stop_machine_yield(const struct cpumask *cpumask) | |||
186 | static int multi_cpu_stop(void *data) | 187 | static int multi_cpu_stop(void *data) |
187 | { | 188 | { |
188 | struct multi_stop_data *msdata = data; | 189 | struct multi_stop_data *msdata = data; |
189 | enum multi_stop_state curstate = MULTI_STOP_NONE; | 190 | enum multi_stop_state newstate, curstate = MULTI_STOP_NONE; |
190 | int cpu = smp_processor_id(), err = 0; | 191 | int cpu = smp_processor_id(), err = 0; |
191 | const struct cpumask *cpumask; | 192 | const struct cpumask *cpumask; |
192 | unsigned long flags; | 193 | unsigned long flags; |
@@ -210,8 +211,9 @@ static int multi_cpu_stop(void *data) | |||
210 | do { | 211 | do { |
211 | /* Chill out and ensure we re-read multi_stop_state. */ | 212 | /* Chill out and ensure we re-read multi_stop_state. */ |
212 | stop_machine_yield(cpumask); | 213 | stop_machine_yield(cpumask); |
213 | if (msdata->state != curstate) { | 214 | newstate = READ_ONCE(msdata->state); |
214 | curstate = msdata->state; | 215 | if (newstate != curstate) { |
216 | curstate = newstate; | ||
215 | switch (curstate) { | 217 | switch (curstate) { |
216 | case MULTI_STOP_DISABLE_IRQ: | 218 | case MULTI_STOP_DISABLE_IRQ: |
217 | local_irq_disable(); | 219 | local_irq_disable(); |