• Roman Gushchin's avatar
    sched/fair: Fix tg_set_cfs_bandwidth() deadlock on rq->lock · 09dc4ab0
    Roman Gushchin authored
    tg_set_cfs_bandwidth() sets cfs_b->timer_active to 0 to
    force the period timer restart. It's not safe, because
    can lead to deadlock, described in commit 927b54fc:
    "__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."
    
    Three CPUs must be involved:
    
      CPU0               CPU1                         CPU2
      take rq->lock      period timer fired
      ...                take cfs_b lock
      ...                ...                          tg_set_cfs_bandwidth()
      throttle_cfs_rq()  release cfs_b lock           take cfs_b lock
      ...                distribute_cfs_runtime()     timer_active = 0
      take cfs_b->lock   wait for rq->lock            ...
      __start_cfs_bandwidth()
      {wait for timer callback
       break if timer_active == 1}
    
    So, CPU0 and CPU1 are deadlocked.
    
    Instead of resetting cfs_b->timer_active, tg_set_cfs_bandwidth can
    wait for period timer callbacks (ignoring cfs_b->timer_active) and
    restart the timer explicitly.
    Signed-off-by: default avatarRoman Gushchin <klamm@yandex-team.ru>
    Reviewed-by: default avatarBen Segall <bsegall@google.com>
    Signed-off-by: default avatarPeter Zijlstra <peterz@infradead.org>
    Link: http://lkml.kernel.org/r/87wqdi9g8e.wl\%klamm@yandex-team.ru
    Cc: pjt@google.com
    Cc: chris.j.arges@canonical.com
    Cc: gregkh@linuxfoundation.org
    Cc: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
    09dc4ab0
sched.h 39.9 KB