aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2008-12-04 05:17:10 -0500
committerIngo Molnar <mingo@elte.hu>2008-12-04 05:31:25 -0500
commit37810659ea7d9572c5ac284ade272f806ef8f788 (patch)
tree7e251f9b8eb0552773702ecf45f8348f2b5b2e2f /kernel
parentca109491f612aab5c8152207631c0444f63da97f (diff)
hrtimer: removing all ur callback modes, fix hotplug
Impact: fix hrtimer locking (reported by lockdep) in the CPU hotplug case This addition fixes the hotplug locking issue on my machine Signed-off-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/hrtimer.c65
1 files changed, 37 insertions, 28 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index efd6f41e1c16..b09c7a27631d 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -1496,7 +1496,7 @@ static void __cpuinit init_hrtimers_cpu(int cpu)
1496#ifdef CONFIG_HOTPLUG_CPU 1496#ifdef CONFIG_HOTPLUG_CPU
1497 1497
1498static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, 1498static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
1499 struct hrtimer_clock_base *new_base, int dcpu) 1499 struct hrtimer_clock_base *new_base)
1500{ 1500{
1501 struct hrtimer *timer; 1501 struct hrtimer *timer;
1502 struct rb_node *node; 1502 struct rb_node *node;
@@ -1514,40 +1514,34 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
1514 __remove_hrtimer(timer, old_base, HRTIMER_STATE_MIGRATE, 0); 1514 __remove_hrtimer(timer, old_base, HRTIMER_STATE_MIGRATE, 0);
1515 timer->base = new_base; 1515 timer->base = new_base;
1516 /* 1516 /*
1517 * Enqueue the timer. Allow reprogramming of the event device 1517 * Enqueue the timers on the new cpu, but do not reprogram
1518 * the timer as that would enable a deadlock between
1519 * hrtimer_enqueue_reprogramm() running the timer and us still
1520 * holding a nested base lock.
1521 *
1522 * Instead we tickle the hrtimer interrupt after the migration
1523 * is done, which will run all expired timers and re-programm
1524 * the timer device.
1518 */ 1525 */
1519 enqueue_hrtimer(timer, new_base, 1); 1526 enqueue_hrtimer(timer, new_base, 0);
1520 1527
1521#ifdef CONFIG_HIGH_RES_TIMERS
1522 /*
1523 * Happens with high res enabled when the timer was
1524 * already expired and the callback mode is
1525 * HRTIMER_CB_IRQSAFE_UNLOCKED (hrtimer_sleeper). The
1526 * enqueue code does not move them to the soft irq
1527 * pending list for performance/latency reasons, but
1528 * in the migration state, we need to do that
1529 * otherwise we end up with a stale timer.
1530 */
1531 if (timer->state == HRTIMER_STATE_MIGRATE) {
1532 /* XXX: running on offline cpu */
1533 __run_hrtimer(timer);
1534 }
1535#endif
1536 /* Clear the migration state bit */ 1528 /* Clear the migration state bit */
1537 timer->state &= ~HRTIMER_STATE_MIGRATE; 1529 timer->state &= ~HRTIMER_STATE_MIGRATE;
1538 } 1530 }
1539} 1531}
1540 1532
1541static void migrate_hrtimers(int cpu) 1533static int migrate_hrtimers(int scpu)
1542{ 1534{
1543 struct hrtimer_cpu_base *old_base, *new_base; 1535 struct hrtimer_cpu_base *old_base, *new_base;
1544 int i; 1536 int dcpu, i;
1545 1537
1546 BUG_ON(cpu_online(cpu)); 1538 BUG_ON(cpu_online(scpu));
1547 old_base = &per_cpu(hrtimer_bases, cpu); 1539 old_base = &per_cpu(hrtimer_bases, scpu);
1548 new_base = &get_cpu_var(hrtimer_bases); 1540 new_base = &get_cpu_var(hrtimer_bases);
1549 1541
1550 tick_cancel_sched_timer(cpu); 1542 dcpu = smp_processor_id();
1543
1544 tick_cancel_sched_timer(scpu);
1551 /* 1545 /*
1552 * The caller is globally serialized and nobody else 1546 * The caller is globally serialized and nobody else
1553 * takes two locks at once, deadlock is not possible. 1547 * takes two locks at once, deadlock is not possible.
@@ -1557,32 +1551,47 @@ static void migrate_hrtimers(int cpu)
1557 1551
1558 for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { 1552 for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
1559 migrate_hrtimer_list(&old_base->clock_base[i], 1553 migrate_hrtimer_list(&old_base->clock_base[i],
1560 &new_base->clock_base[i], cpu); 1554 &new_base->clock_base[i]);
1561 } 1555 }
1562 1556
1563 spin_unlock(&old_base->lock); 1557 spin_unlock(&old_base->lock);
1564 spin_unlock_irq(&new_base->lock); 1558 spin_unlock_irq(&new_base->lock);
1565 put_cpu_var(hrtimer_bases); 1559 put_cpu_var(hrtimer_bases);
1560
1561 return dcpu;
1562}
1563
1564static void tickle_timers(void *arg)
1565{
1566 hrtimer_peek_ahead_timers();
1566} 1567}
1568
1567#endif /* CONFIG_HOTPLUG_CPU */ 1569#endif /* CONFIG_HOTPLUG_CPU */
1568 1570
1569static int __cpuinit hrtimer_cpu_notify(struct notifier_block *self, 1571static int __cpuinit hrtimer_cpu_notify(struct notifier_block *self,
1570 unsigned long action, void *hcpu) 1572 unsigned long action, void *hcpu)
1571{ 1573{
1572 unsigned int cpu = (long)hcpu; 1574 int dcpu = -1, scpu = (long)hcpu;
1573 1575
1574 switch (action) { 1576 switch (action) {
1575 1577
1576 case CPU_UP_PREPARE: 1578 case CPU_UP_PREPARE:
1577 case CPU_UP_PREPARE_FROZEN: 1579 case CPU_UP_PREPARE_FROZEN:
1578 init_hrtimers_cpu(cpu); 1580 init_hrtimers_cpu(scpu);
1579 break; 1581 break;
1580 1582
1581#ifdef CONFIG_HOTPLUG_CPU 1583#ifdef CONFIG_HOTPLUG_CPU
1582 case CPU_DEAD: 1584 case CPU_DEAD:
1583 case CPU_DEAD_FROZEN: 1585 case CPU_DEAD_FROZEN:
1584 clockevents_notify(CLOCK_EVT_NOTIFY_CPU_DEAD, &cpu); 1586 clockevents_notify(CLOCK_EVT_NOTIFY_CPU_DEAD, &scpu);
1585 migrate_hrtimers(cpu); 1587 dcpu = migrate_hrtimers(scpu);
1588 break;
1589
1590 case CPU_POST_DEAD:
1591 if (dcpu == -1)
1592 break;
1593
1594 smp_call_function_single(dcpu, tickle_timers, NULL, 0);
1586 break; 1595 break;
1587#endif 1596#endif
1588 1597