Skip to content

Commit 5de2755

Browse files
Peter ZijlstraKAGA-KOKO
authored andcommitted
hrtimer: Allow concurrent hrtimer_start() for self restarting timers
Because we drop cpu_base->lock around calling hrtimer::function, it is possible for hrtimer_start() to come in between and enqueue the timer. If hrtimer::function then returns HRTIMER_RESTART we'll hit the BUG_ON because HRTIMER_STATE_ENQUEUED will be set. Since the above is a perfectly valid scenario, remove the BUG_ON and make the enqueue_hrtimer() call conditional on the timer not being enqueued already. NOTE: in that concurrent scenario its entirely common for both sites to want to modify the hrtimer, since hrtimers don't provide serialization themselves be sure to provide some such that the hrtimer::function and the hrtimer_start() caller don't both try and fudge the expiration state at the same time. To that effect, add a WARN when someone tries to forward an already enqueued timer, the most common way to change the expiry of self restarting timers. Ideally we'd put the WARN in everything modifying the expiry but most of that is inlines and we don't need the bloat. Fixes: 2d44ae4 ("hrtimer: clean up cpu->base locking tricks") Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Cc: Ben Segall <[email protected]> Cc: Roman Gushchin <[email protected]> Cc: Paul Turner <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thomas Gleixner <[email protected]>
1 parent 2ad5d32 commit 5de2755

File tree

1 file changed

+9
-3
lines changed

1 file changed

+9
-3
lines changed

kernel/time/hrtimer.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,9 @@ u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
799799
if (delta.tv64 < 0)
800800
return 0;
801801

802+
if (WARN_ON(timer->state & HRTIMER_STATE_ENQUEUED))
803+
return 0;
804+
802805
if (interval.tv64 < hrtimer_resolution)
803806
interval.tv64 = hrtimer_resolution;
804807

@@ -1139,11 +1142,14 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
11391142
* Note: We clear the CALLBACK bit after enqueue_hrtimer and
11401143
* we do not reprogramm the event hardware. Happens either in
11411144
* hrtimer_start_range_ns() or in hrtimer_interrupt()
1145+
*
1146+
* Note: Because we dropped the cpu_base->lock above,
1147+
* hrtimer_start_range_ns() can have popped in and enqueued the timer
1148+
* for us already.
11421149
*/
1143-
if (restart != HRTIMER_NORESTART) {
1144-
BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
1150+
if (restart != HRTIMER_NORESTART &&
1151+
!(timer->state & HRTIMER_STATE_ENQUEUED))
11451152
enqueue_hrtimer(timer, base);
1146-
}
11471153

11481154
WARN_ON_ONCE(!(timer->state & HRTIMER_STATE_CALLBACK));
11491155

0 commit comments

Comments
 (0)