diff options
author | Peter Zijlstra <peterz@infradead.org> | 2008-12-04 05:17:10 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-12-04 05:31:25 -0500 |
commit | 37810659ea7d9572c5ac284ade272f806ef8f788 (patch) | |
tree | 7e251f9b8eb0552773702ecf45f8348f2b5b2e2f /kernel | |
parent | ca109491f612aab5c8152207631c0444f63da97f (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.c | 65 |
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 | ||
1498 | static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, | 1498 | static 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 | ||
1541 | static void migrate_hrtimers(int cpu) | 1533 | static 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 | |||
1564 | static 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 | ||
1569 | static int __cpuinit hrtimer_cpu_notify(struct notifier_block *self, | 1571 | static 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 | ||