aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-02-11 15:42:10 -0500
committerIngo Molnar <mingo@kernel.org>2015-04-17 03:57:52 -0400
commit8053871d0f7f67c7efb7f226ef031f78877d6625 (patch)
treee73fabcd5872b6b5d3d7591fd7a45ee825bfb641 /kernel
parentd7bc3197b41e0a1af6677e83f8736e93a1575ce0 (diff)
smp: Fix smp_call_function_single_async() locking
The current smp_function_call code suffers a number of problems, most notably smp_call_function_single_async() is broken. The problem is that flush_smp_call_function_queue() does csd_unlock() _after_ calling csd->func(). This means that a caller cannot properly synchronize the csd usage as it has to. Change the code to release the csd before calling ->func() for the async case, and put a WARN_ON_ONCE(csd->flags & CSD_FLAG_LOCK) in smp_call_function_single_async() to warn us of improper serialization, because any waiting there can results in deadlocks when called with IRQs disabled. Rename the (currently) unused WAIT flag to SYNCHRONOUS and (re)use it such that we know what to do in flush_smp_call_function_queue(). Rework csd_{,un}lock() to use smp_load_acquire() / smp_store_release() to avoid some full barriers while more clearly providing lock semantics. Finally move the csd maintenance out of generic_exec_single() into its callers for clearer code. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> [ Added changelog. ] Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jens Axboe <axboe@kernel.dk> Cc: Rafael David Tinoco <inaddy@ubuntu.com> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/CA+55aFz492bzLFhdbKN-Hygjcreup7CjMEYk3nTSfRWjppz-OA@mail.gmail.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/smp.c78
1 files changed, 47 insertions, 31 deletions
diff --git a/kernel/smp.c b/kernel/smp.c
index f38a1e692259..2aaac2c47683 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -19,7 +19,7 @@
19 19
20enum { 20enum {
21 CSD_FLAG_LOCK = 0x01, 21 CSD_FLAG_LOCK = 0x01,
22 CSD_FLAG_WAIT = 0x02, 22 CSD_FLAG_SYNCHRONOUS = 0x02,
23}; 23};
24 24
25struct call_function_data { 25struct call_function_data {
@@ -107,7 +107,7 @@ void __init call_function_init(void)
107 */ 107 */
108static void csd_lock_wait(struct call_single_data *csd) 108static void csd_lock_wait(struct call_single_data *csd)
109{ 109{
110 while (csd->flags & CSD_FLAG_LOCK) 110 while (smp_load_acquire(&csd->flags) & CSD_FLAG_LOCK)
111 cpu_relax(); 111 cpu_relax();
112} 112}
113 113
@@ -121,19 +121,17 @@ static void csd_lock(struct call_single_data *csd)
121 * to ->flags with any subsequent assignments to other 121 * to ->flags with any subsequent assignments to other
122 * fields of the specified call_single_data structure: 122 * fields of the specified call_single_data structure:
123 */ 123 */
124 smp_mb(); 124 smp_wmb();
125} 125}
126 126
127static void csd_unlock(struct call_single_data *csd) 127static void csd_unlock(struct call_single_data *csd)
128{ 128{
129 WARN_ON((csd->flags & CSD_FLAG_WAIT) && !(csd->flags & CSD_FLAG_LOCK)); 129 WARN_ON(!(csd->flags & CSD_FLAG_LOCK));
130 130
131 /* 131 /*
132 * ensure we're all done before releasing data: 132 * ensure we're all done before releasing data:
133 */ 133 */
134 smp_mb(); 134 smp_store_release(&csd->flags, 0);
135
136 csd->flags &= ~CSD_FLAG_LOCK;
137} 135}
138 136
139static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_data, csd_data); 137static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_data, csd_data);
@@ -144,13 +142,16 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_data, csd_data);
144 * ->func, ->info, and ->flags set. 142 * ->func, ->info, and ->flags set.
145 */ 143 */
146static int generic_exec_single(int cpu, struct call_single_data *csd, 144static int generic_exec_single(int cpu, struct call_single_data *csd,
147 smp_call_func_t func, void *info, int wait) 145 smp_call_func_t func, void *info)
148{ 146{
149 struct call_single_data csd_stack = { .flags = 0 };
150 unsigned long flags;
151
152
153 if (cpu == smp_processor_id()) { 147 if (cpu == smp_processor_id()) {
148 unsigned long flags;
149
150 /*
151 * We can unlock early even for the synchronous on-stack case,
152 * since we're doing this from the same CPU..
153 */
154 csd_unlock(csd);
154 local_irq_save(flags); 155 local_irq_save(flags);
155 func(info); 156 func(info);
156 local_irq_restore(flags); 157 local_irq_restore(flags);
@@ -161,21 +162,9 @@ static int generic_exec_single(int cpu, struct call_single_data *csd,
161 if ((unsigned)cpu >= nr_cpu_ids || !cpu_online(cpu)) 162 if ((unsigned)cpu >= nr_cpu_ids || !cpu_online(cpu))
162 return -ENXIO; 163 return -ENXIO;
163 164
164
165 if (!csd) {
166 csd = &csd_stack;
167 if (!wait)
168 csd = this_cpu_ptr(&csd_data);
169 }
170
171 csd_lock(csd);
172
173 csd->func = func; 165 csd->func = func;
174 csd->info = info; 166 csd->info = info;
175 167
176 if (wait)
177 csd->flags |= CSD_FLAG_WAIT;
178
179 /* 168 /*
180 * The list addition should be visible before sending the IPI 169 * The list addition should be visible before sending the IPI
181 * handler locks the list to pull the entry off it because of 170 * handler locks the list to pull the entry off it because of
@@ -190,9 +179,6 @@ static int generic_exec_single(int cpu, struct call_single_data *csd,
190 if (llist_add(&csd->llist, &per_cpu(call_single_queue, cpu))) 179 if (llist_add(&csd->llist, &per_cpu(call_single_queue, cpu)))
191 arch_send_call_function_single_ipi(cpu); 180 arch_send_call_function_single_ipi(cpu);
192 181
193 if (wait)
194 csd_lock_wait(csd);
195
196 return 0; 182 return 0;
197} 183}
198 184
@@ -250,8 +236,17 @@ static void flush_smp_call_function_queue(bool warn_cpu_offline)
250 } 236 }
251 237
252 llist_for_each_entry_safe(csd, csd_next, entry, llist) { 238 llist_for_each_entry_safe(csd, csd_next, entry, llist) {
253 csd->func(csd->info); 239 smp_call_func_t func = csd->func;
254 csd_unlock(csd); 240 void *info = csd->info;
241
242 /* Do we wait until *after* callback? */
243 if (csd->flags & CSD_FLAG_SYNCHRONOUS) {
244 func(info);
245 csd_unlock(csd);
246 } else {
247 csd_unlock(csd);
248 func(info);
249 }
255 } 250 }
256 251
257 /* 252 /*
@@ -274,6 +269,8 @@ static void flush_smp_call_function_queue(bool warn_cpu_offline)
274int smp_call_function_single(int cpu, smp_call_func_t func, void *info, 269int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
275 int wait) 270 int wait)
276{ 271{
272 struct call_single_data *csd;
273 struct call_single_data csd_stack = { .flags = CSD_FLAG_LOCK | CSD_FLAG_SYNCHRONOUS };
277 int this_cpu; 274 int this_cpu;
278 int err; 275 int err;
279 276
@@ -292,7 +289,16 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
292 WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled() 289 WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
293 && !oops_in_progress); 290 && !oops_in_progress);
294 291
295 err = generic_exec_single(cpu, NULL, func, info, wait); 292 csd = &csd_stack;
293 if (!wait) {
294 csd = this_cpu_ptr(&csd_data);
295 csd_lock(csd);
296 }
297
298 err = generic_exec_single(cpu, csd, func, info);
299
300 if (wait)
301 csd_lock_wait(csd);
296 302
297 put_cpu(); 303 put_cpu();
298 304
@@ -321,7 +327,15 @@ int smp_call_function_single_async(int cpu, struct call_single_data *csd)
321 int err = 0; 327 int err = 0;
322 328
323 preempt_disable(); 329 preempt_disable();
324 err = generic_exec_single(cpu, csd, csd->func, csd->info, 0); 330
331 /* We could deadlock if we have to wait here with interrupts disabled! */
332 if (WARN_ON_ONCE(csd->flags & CSD_FLAG_LOCK))
333 csd_lock_wait(csd);
334
335 csd->flags = CSD_FLAG_LOCK;
336 smp_wmb();
337
338 err = generic_exec_single(cpu, csd, csd->func, csd->info);
325 preempt_enable(); 339 preempt_enable();
326 340
327 return err; 341 return err;
@@ -433,6 +447,8 @@ void smp_call_function_many(const struct cpumask *mask,
433 struct call_single_data *csd = per_cpu_ptr(cfd->csd, cpu); 447 struct call_single_data *csd = per_cpu_ptr(cfd->csd, cpu);
434 448
435 csd_lock(csd); 449 csd_lock(csd);
450 if (wait)
451 csd->flags |= CSD_FLAG_SYNCHRONOUS;
436 csd->func = func; 452 csd->func = func;
437 csd->info = info; 453 csd->info = info;
438 llist_add(&csd->llist, &per_cpu(call_single_queue, cpu)); 454 llist_add(&csd->llist, &per_cpu(call_single_queue, cpu));