diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/smp.c | 29 |
1 files changed, 19 insertions, 10 deletions
diff --git a/kernel/smp.c b/kernel/smp.c index 17c6e5860231..2fe66f7c617a 100644 --- a/kernel/smp.c +++ b/kernel/smp.c | |||
| @@ -194,6 +194,7 @@ void generic_smp_call_function_interrupt(void) | |||
| 194 | */ | 194 | */ |
| 195 | list_for_each_entry_rcu(data, &call_function.queue, csd.list) { | 195 | list_for_each_entry_rcu(data, &call_function.queue, csd.list) { |
| 196 | int refs; | 196 | int refs; |
| 197 | void (*func) (void *info); | ||
| 197 | 198 | ||
| 198 | /* | 199 | /* |
| 199 | * Since we walk the list without any locks, we might | 200 | * Since we walk the list without any locks, we might |
| @@ -213,24 +214,32 @@ void generic_smp_call_function_interrupt(void) | |||
| 213 | if (atomic_read(&data->refs) == 0) | 214 | if (atomic_read(&data->refs) == 0) |
| 214 | continue; | 215 | continue; |
| 215 | 216 | ||
| 216 | if (!cpumask_test_and_clear_cpu(cpu, data->cpumask)) | 217 | func = data->csd.func; /* for later warn */ |
| 217 | continue; | ||
| 218 | |||
| 219 | data->csd.func(data->csd.info); | 218 | data->csd.func(data->csd.info); |
| 220 | 219 | ||
| 220 | /* | ||
| 221 | * If the cpu mask is not still set then it enabled interrupts, | ||
| 222 | * we took another smp interrupt, and executed the function | ||
| 223 | * twice on this cpu. In theory that copy decremented refs. | ||
| 224 | */ | ||
| 225 | if (!cpumask_test_and_clear_cpu(cpu, data->cpumask)) { | ||
| 226 | WARN(1, "%pS enabled interrupts and double executed\n", | ||
| 227 | func); | ||
| 228 | continue; | ||
| 229 | } | ||
| 230 | |||
| 221 | refs = atomic_dec_return(&data->refs); | 231 | refs = atomic_dec_return(&data->refs); |
| 222 | WARN_ON(refs < 0); | 232 | WARN_ON(refs < 0); |
| 223 | if (!refs) { | ||
| 224 | WARN_ON(!cpumask_empty(data->cpumask)); | ||
| 225 | |||
| 226 | raw_spin_lock(&call_function.lock); | ||
| 227 | list_del_rcu(&data->csd.list); | ||
| 228 | raw_spin_unlock(&call_function.lock); | ||
| 229 | } | ||
| 230 | 233 | ||
| 231 | if (refs) | 234 | if (refs) |
| 232 | continue; | 235 | continue; |
| 233 | 236 | ||
| 237 | WARN_ON(!cpumask_empty(data->cpumask)); | ||
| 238 | |||
| 239 | raw_spin_lock(&call_function.lock); | ||
| 240 | list_del_rcu(&data->csd.list); | ||
| 241 | raw_spin_unlock(&call_function.lock); | ||
| 242 | |||
| 234 | csd_unlock(&data->csd); | 243 | csd_unlock(&data->csd); |
| 235 | } | 244 | } |
| 236 | 245 | ||
