]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/hrtimer.c
V4L/DVB (9613): tvaudio: fix a memory leak
[linux-2.6-omap-h63xx.git] / kernel / hrtimer.c
index 2b465dfde4269b6d4609957999c9eecb0a148a36..95d3949f2ae51135b181906f632b8de7f5e3f8e7 100644 (file)
@@ -1209,6 +1209,7 @@ static void run_hrtimer_pending(struct hrtimer_cpu_base *cpu_base)
                enum hrtimer_restart (*fn)(struct hrtimer *);
                struct hrtimer *timer;
                int restart;
+               int emulate_hardirq_ctx = 0;
 
                timer = list_entry(cpu_base->cb_pending.next,
                                   struct hrtimer, cb_entry);
@@ -1217,10 +1218,24 @@ static void run_hrtimer_pending(struct hrtimer_cpu_base *cpu_base)
                timer_stats_account_hrtimer(timer);
 
                fn = timer->function;
+               /*
+                * A timer might have been added to the cb_pending list
+                * when it was migrated during a cpu-offline operation.
+                * Emulate hardirq context for such timers.
+                */
+               if (timer->cb_mode == HRTIMER_CB_IRQSAFE_PERCPU ||
+                   timer->cb_mode == HRTIMER_CB_IRQSAFE_UNLOCKED)
+                       emulate_hardirq_ctx = 1;
+
                __remove_hrtimer(timer, timer->base, HRTIMER_STATE_CALLBACK, 0);
                spin_unlock_irq(&cpu_base->lock);
 
-               restart = fn(timer);
+               if (unlikely(emulate_hardirq_ctx)) {
+                       local_irq_disable();
+                       restart = fn(timer);
+                       local_irq_enable();
+               } else
+                       restart = fn(timer);
 
                spin_lock_irq(&cpu_base->lock);