diff options
-rw-r--r-- | kernel/hrtimer.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 2b465dfde426..95d3949f2ae5 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
@@ -1209,6 +1209,7 @@ static void run_hrtimer_pending(struct hrtimer_cpu_base *cpu_base) | |||
1209 | enum hrtimer_restart (*fn)(struct hrtimer *); | 1209 | enum hrtimer_restart (*fn)(struct hrtimer *); |
1210 | struct hrtimer *timer; | 1210 | struct hrtimer *timer; |
1211 | int restart; | 1211 | int restart; |
1212 | int emulate_hardirq_ctx = 0; | ||
1212 | 1213 | ||
1213 | timer = list_entry(cpu_base->cb_pending.next, | 1214 | timer = list_entry(cpu_base->cb_pending.next, |
1214 | struct hrtimer, cb_entry); | 1215 | struct hrtimer, cb_entry); |
@@ -1217,10 +1218,24 @@ static void run_hrtimer_pending(struct hrtimer_cpu_base *cpu_base) | |||
1217 | timer_stats_account_hrtimer(timer); | 1218 | timer_stats_account_hrtimer(timer); |
1218 | 1219 | ||
1219 | fn = timer->function; | 1220 | fn = timer->function; |
1221 | /* | ||
1222 | * A timer might have been added to the cb_pending list | ||
1223 | * when it was migrated during a cpu-offline operation. | ||
1224 | * Emulate hardirq context for such timers. | ||
1225 | */ | ||
1226 | if (timer->cb_mode == HRTIMER_CB_IRQSAFE_PERCPU || | ||
1227 | timer->cb_mode == HRTIMER_CB_IRQSAFE_UNLOCKED) | ||
1228 | emulate_hardirq_ctx = 1; | ||
1229 | |||
1220 | __remove_hrtimer(timer, timer->base, HRTIMER_STATE_CALLBACK, 0); | 1230 | __remove_hrtimer(timer, timer->base, HRTIMER_STATE_CALLBACK, 0); |
1221 | spin_unlock_irq(&cpu_base->lock); | 1231 | spin_unlock_irq(&cpu_base->lock); |
1222 | 1232 | ||
1223 | restart = fn(timer); | 1233 | if (unlikely(emulate_hardirq_ctx)) { |
1234 | local_irq_disable(); | ||
1235 | restart = fn(timer); | ||
1236 | local_irq_enable(); | ||
1237 | } else | ||
1238 | restart = fn(timer); | ||
1224 | 1239 | ||
1225 | spin_lock_irq(&cpu_base->lock); | 1240 | spin_lock_irq(&cpu_base->lock); |
1226 | 1241 | ||