blob: 0299ee857ee987df58bfc0ae0d341c3b7130002d [file] [log] [blame]
Subject: hrtimer: Don't call the timer handler from hrtimer_start
From: Peter Zijlstra <a.p.zijlstra@chello.nl>
Date: Fri Aug 12 17:39:54 CEST 2011
[<ffffffff812de4a9>] __delay+0xf/0x11
[<ffffffff812e36e9>] do_raw_spin_lock+0xd2/0x13c
[<ffffffff815028ee>] _raw_spin_lock+0x60/0x73 rt_b->rt_runtime_lock
[<ffffffff81068f68>] ? sched_rt_period_timer+0xad/0x281
[<ffffffff81068f68>] sched_rt_period_timer+0xad/0x281
[<ffffffff8109e5e1>] __run_hrtimer+0x1e4/0x347
[<ffffffff81068ebb>] ? enqueue_rt_entity+0x36/0x36
[<ffffffff8109f2b1>] __hrtimer_start_range_ns+0x2b5/0x40a base->cpu_base->lock (lock_hrtimer_base)
[<ffffffff81068b6f>] __enqueue_rt_entity+0x26f/0x2aa rt_b->rt_runtime_lock (start_rt_bandwidth)
[<ffffffff81068ead>] enqueue_rt_entity+0x28/0x36
[<ffffffff81069355>] enqueue_task_rt+0x3d/0xb0
[<ffffffff810679d6>] enqueue_task+0x5d/0x64
[<ffffffff810714fc>] task_setprio+0x210/0x29c rq->lock
[<ffffffff810b56cb>] __rt_mutex_adjust_prio+0x25/0x2a p->pi_lock
[<ffffffff810b5d2c>] task_blocks_on_rt_mutex+0x196/0x20f
Instead make __hrtimer_start_range_ns() return -ETIME when the timer
is in the past. Since body actually uses the hrtimer_start*() return
value its pretty safe to wreck it.
Also, it will only ever return -ETIME for timer->irqsafe || !wakeup
timers.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
---
kernel/hrtimer.c | 48 +++++++++++++++++++++++-------------------------
1 file changed, 23 insertions(+), 25 deletions(-)
Index: linux-stable/kernel/hrtimer.c
===================================================================
--- linux-stable.orig/kernel/hrtimer.c
+++ linux-stable/kernel/hrtimer.c
@@ -646,37 +646,24 @@ static inline int hrtimer_enqueue_reprog
struct hrtimer_clock_base *base,
int wakeup)
{
-#ifdef CONFIG_PREEMPT_RT_BASE
-again:
if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) {
+ if (!wakeup)
+ return -ETIME;
+
+#ifdef CONFIG_PREEMPT_RT_BASE
/*
* Move softirq based timers away from the rbtree in
* case it expired already. Otherwise we would have a
* stale base->first entry until the softirq runs.
*/
- if (!hrtimer_rt_defer(timer)) {
- ktime_t now = ktime_get();
-
- __run_hrtimer(timer, &now);
- /*
- * __run_hrtimer might have requeued timer and
- * it could be base->first again.
- */
- if (&timer->node == base->active.next)
- goto again;
- return 1;
- }
-#else
- if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) {
+ if (!hrtimer_rt_defer(timer))
+ return -ETIME;
#endif
- if (wakeup) {
- raw_spin_unlock(&base->cpu_base->lock);
- raise_softirq_irqoff(HRTIMER_SOFTIRQ);
- raw_spin_lock(&base->cpu_base->lock);
- } else
- __raise_softirq_irqoff(HRTIMER_SOFTIRQ);
+ raw_spin_unlock(&base->cpu_base->lock);
+ raise_softirq_irqoff(HRTIMER_SOFTIRQ);
+ raw_spin_lock(&base->cpu_base->lock);
- return 1;
+ return 0;
}
return 0;
@@ -1067,8 +1054,19 @@ int __hrtimer_start_range_ns(struct hrti
*
* XXX send_remote_softirq() ?
*/
- if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases))
- hrtimer_enqueue_reprogram(timer, new_base, wakeup);
+ if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)) {
+ ret = hrtimer_enqueue_reprogram(timer, new_base, wakeup);
+ if (ret) {
+ /*
+ * In case we failed to reprogram the timer (mostly
+ * because out current timer is already elapsed),
+ * remove it again and report a failure. This avoids
+ * stale base->first entries.
+ */
+ __remove_hrtimer(timer, new_base,
+ timer->state & HRTIMER_STATE_CALLBACK, 0);
+ }
+ }
unlock_hrtimer_base(timer, &flags);