hrtimer: migrate pending list on cpu offline
authorThomas Gleixner <tglx@linutronix.de>
Mon, 29 Sep 2008 12:06:45 +0000 (14:06 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Mon, 29 Sep 2008 15:09:13 +0000 (17:09 +0200)
Impact: hrtimers which are on the pending list are not migrated at cpu
offline and can be stale forever

Add the pending list migration when CONFIG_HIGH_RES_TIMERS is enabled

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
kernel/hrtimer.c

index b8e4dce80a748dc06c94ed6cb43225903c7f99c1..580bc66ae13631e30ff01bce4c8f0bd1db21bcdf 100644 (file)
@@ -1610,10 +1610,36 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
        }
 }
 
+#ifdef CONFIG_HIGH_RES_TIMERS
+static int migrate_hrtimer_pending(struct hrtimer_cpu_base *old_base,
+                                  struct hrtimer_cpu_base *new_base)
+{
+       struct hrtimer *timer;
+       int raise = 0;
+
+       while (!list_empty(&old_base->cb_pending)) {
+               timer = list_entry(old_base->cb_pending.next,
+                                  struct hrtimer, cb_entry);
+
+               __remove_hrtimer(timer, timer->base, HRTIMER_STATE_PENDING, 0);
+               timer->base = &new_base->clock_base[timer->base->index];
+               list_add_tail(&timer->cb_entry, &new_base->cb_pending);
+               raise = 1;
+       }
+       return raise;
+}
+#else
+static int migrate_hrtimer_pending(struct hrtimer_cpu_base *old_base,
+                                  struct hrtimer_cpu_base *new_base)
+{
+       return 0;
+}
+#endif
+
 static void migrate_hrtimers(int cpu)
 {
        struct hrtimer_cpu_base *old_base, *new_base;
-       int i;
+       int i, raise = 0;
 
        BUG_ON(cpu_online(cpu));
        old_base = &per_cpu(hrtimer_bases, cpu);
@@ -1630,10 +1656,16 @@ static void migrate_hrtimers(int cpu)
                                     &new_base->clock_base[i]);
        }
 
+       if (migrate_hrtimer_pending(old_base, new_base))
+               raise = 1;
+
        spin_unlock(&old_base->lock);
        spin_unlock(&new_base->lock);
        local_irq_enable();
        put_cpu_var(hrtimer_bases);
+
+       if (raise)
+               hrtimer_raise_softirq();
 }
 #endif /* CONFIG_HOTPLUG_CPU */