aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/hrtimer.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2008-09-29 08:09:39 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-09-29 11:09:14 -0400
commit41e1022eae71707f1ce6801a746f70b1e57b7567 (patch)
tree97f8a258adcaa0123f143c1f5c53f178d96d76e8 /kernel/hrtimer.c
parent7659e349672bb0d378ef8d7d62bae4c53d2bdd18 (diff)
hrtimer: fix migration of CB_IRQSAFE_NO_SOFTIRQ hrtimers
Impact: Stale timers after a CPU went offline. commit 37bb6cb4097e29ffee970065b74499cbf10603a3 hrtimer: unlock hrtimer_wakeup changed the hrtimer sleeper callback mode to CB_IRQSAFE_NO_SOFTIRQ due to locking problems. A result of this change is that when enqueue is called for an already expired hrtimer the callback function is not longer called directly from the enqueue code. The normal callers have been fixed in the code, but the migration code which moves hrtimers from a dead CPU to a live CPU was not made aware of this. This can be fixed by checking the timer state after the call to enqueue in the migration code. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/hrtimer.c')
-rw-r--r--kernel/hrtimer.c28
1 files changed, 25 insertions, 3 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 580bc66ae13..ac2f6d6d486 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -1591,11 +1591,12 @@ static void __cpuinit init_hrtimers_cpu(int cpu)
1591 1591
1592#ifdef CONFIG_HOTPLUG_CPU 1592#ifdef CONFIG_HOTPLUG_CPU
1593 1593
1594static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, 1594static int migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
1595 struct hrtimer_clock_base *new_base) 1595 struct hrtimer_clock_base *new_base)
1596{ 1596{
1597 struct hrtimer *timer; 1597 struct hrtimer *timer;
1598 struct rb_node *node; 1598 struct rb_node *node;
1599 int raise = 0;
1599 1600
1600 while ((node = rb_first(&old_base->active))) { 1601 while ((node = rb_first(&old_base->active))) {
1601 timer = rb_entry(node, struct hrtimer, node); 1602 timer = rb_entry(node, struct hrtimer, node);
@@ -1607,7 +1608,27 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
1607 * Enqueue the timer. Allow reprogramming of the event device 1608 * Enqueue the timer. Allow reprogramming of the event device
1608 */ 1609 */
1609 enqueue_hrtimer(timer, new_base, 1); 1610 enqueue_hrtimer(timer, new_base, 1);
1611
1612#ifdef CONFIG_HIGH_RES_TIMERS
1613 /*
1614 * Happens with high res enabled when the timer was
1615 * already expired and the callback mode is
1616 * HRTIMER_CB_IRQSAFE_NO_SOFTIRQ
1617 * (hrtimer_sleeper). The enqueue code does not move
1618 * them to the soft irq pending list for
1619 * performance/latency reasons, but in the migration
1620 * state, we need to do that otherwise we end up with
1621 * a stale timer.
1622 */
1623 if (timer->state == HRTIMER_STATE_INACTIVE) {
1624 timer->state = HRTIMER_STATE_PENDING;
1625 list_add_tail(&timer->cb_entry,
1626 &new_base->cpu_base->cb_pending);
1627 raise = 1;
1628 }
1629#endif
1610 } 1630 }
1631 return raise;
1611} 1632}
1612 1633
1613#ifdef CONFIG_HIGH_RES_TIMERS 1634#ifdef CONFIG_HIGH_RES_TIMERS
@@ -1652,8 +1673,9 @@ static void migrate_hrtimers(int cpu)
1652 spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); 1673 spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
1653 1674
1654 for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { 1675 for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
1655 migrate_hrtimer_list(&old_base->clock_base[i], 1676 if (migrate_hrtimer_list(&old_base->clock_base[i],
1656 &new_base->clock_base[i]); 1677 &new_base->clock_base[i]))
1678 raise = 1;
1657 } 1679 }
1658 1680
1659 if (migrate_hrtimer_pending(old_base, new_base)) 1681 if (migrate_hrtimer_pending(old_base, new_base))