Skip to content

Commit 927b54f

Browse files
Ben SegallIngo Molnar
authored andcommitted
sched: Fix hrtimer_cancel()/rq->lock deadlock
__start_cfs_bandwidth calls hrtimer_cancel while holding rq->lock, waiting for the hrtimer to finish. However, if sched_cfs_period_timer runs for another loop iteration, the hrtimer can attempt to take rq->lock, resulting in deadlock. Fix this by ensuring that cfs_b->timer_active is cleared only if the _latest_ call to do_sched_cfs_period_timer is returning as idle. Then __start_cfs_bandwidth can just call hrtimer_try_to_cancel and wait for that to succeed or timer_active == 1. Signed-off-by: Ben Segall <[email protected]> Signed-off-by: Peter Zijlstra <[email protected]> Cc: [email protected] Link: http://lkml.kernel.org/r/20131016181622.22647.16643.stgit@sword-of-the-dawn.mtv.corp.google.com Signed-off-by: Ingo Molnar <[email protected]>
1 parent db06e78 commit 927b54f

File tree

1 file changed

+11
-4
lines changed

1 file changed

+11
-4
lines changed

kernel/sched/fair.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3225,6 +3225,13 @@ static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun)
32253225
if (idle)
32263226
goto out_unlock;
32273227

3228+
/*
3229+
* if we have relooped after returning idle once, we need to update our
3230+
* status as actually running, so that other cpus doing
3231+
* __start_cfs_bandwidth will stop trying to cancel us.
3232+
*/
3233+
cfs_b->timer_active = 1;
3234+
32283235
__refill_cfs_bandwidth_runtime(cfs_b);
32293236

32303237
if (!throttled) {
@@ -3493,11 +3500,11 @@ void __start_cfs_bandwidth(struct cfs_bandwidth *cfs_b)
34933500
* (timer_active==0 becomes visible before the hrtimer call-back
34943501
* terminates). In either case we ensure that it's re-programmed
34953502
*/
3496-
while (unlikely(hrtimer_active(&cfs_b->period_timer))) {
3503+
while (unlikely(hrtimer_active(&cfs_b->period_timer)) &&
3504+
hrtimer_try_to_cancel(&cfs_b->period_timer) < 0) {
3505+
/* bounce the lock to allow do_sched_cfs_period_timer to run */
34973506
raw_spin_unlock(&cfs_b->lock);
3498-
/* ensure cfs_b->lock is available while we wait */
3499-
hrtimer_cancel(&cfs_b->period_timer);
3500-
3507+
cpu_relax();
35013508
raw_spin_lock(&cfs_b->lock);
35023509
/* if someone else restarted the timer then we're done */
35033510
if (cfs_b->timer_active)

0 commit comments

Comments
 (0)