Skip to content

Commit 102a283

Browse files
kudureranganathPeter Zijlstra
authored andcommitted
sched/fair: Move the throttled tasks to a local list in tg_unthrottle_up()
An update_curr() during the enqueue of throttled task will start throttling the hierarchy from subsequent commit. This can lead to tg_throttle_down() seeing non-empty throttled_limbo_list for the cfs_rq attaching the task from throttled_limbo_list one by one. For example: R | A / \ *B C | rq->curr *B is throttled with tasks on hte limbo list. When the tasks are unthrottled via tg_unthrottle_up() and entity of group B is placed onto A, update_curr() is called to catch up the vruntime and it may throttle group A causing the subsequent tg_throttle_down() to see the pending task's on B's limbo list. tg_unthrottle_up() /* --cfs_rq->throttle_count == 0 */ list_for_each_entry_safe(p, cfs_rq->throttled_limbo_list) enqueue_task_fair() enqueue_entity(se /* B->se */) update_curr(cfs_rq /* A->gcfs_rq */) account_cfs_rq_runtime(cfs_rq) throttle_cfs_rq(cfs_rq /* A->gcfs_rq */ ) tg_throttle_down() /* Reaches B->cfs_rq with throttle_count == 0 */ !!! !list_empty(&cfs_rq->throttled_limbo_list)) !!! Move the tasks from throttled_limbo_list onto a local list before starting the unthrottle to prevent the splat described above. If the hierarchy is throttled again in middle of an unthrottle, put the pending tasks back onto the limbo list to prevent running them unnecessarily. Signed-off-by: K Prateek Nayak <kprateek.nayak@amd.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Benjamin Segall <bsegall@google.com> Tested-by: Aaron Lu <ziqianlu@bytedance.com> Link: https://patch.msgid.link/20260602052531.11450-2-kprateek.nayak@amd.com
1 parent 28ad542 commit 102a283

1 file changed

Lines changed: 21 additions & 2 deletions

File tree

kernel/sched/fair.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6739,6 +6739,7 @@ static int tg_unthrottle_up(struct task_group *tg, void *data)
67396739
struct rq *rq = data;
67406740
struct cfs_rq *cfs_rq = tg_cfs_rq(tg, cpu_of(rq));
67416741
struct task_struct *p, *tmp;
6742+
LIST_HEAD(throttled_tasks);
67426743

67436744
/*
67446745
* If cfs_rq->curr is set, the cfs_rq might not have caught up
@@ -6769,13 +6770,31 @@ static int tg_unthrottle_up(struct task_group *tg, void *data)
67696770
cfs_rq->throttled_clock_self_time += delta;
67706771
}
67716772

6773+
/*
6774+
* Move the tasks to a local list since an update_curr() during
6775+
* enqueue_task_fair() can throttle a higher cfs_rq, and it can
6776+
* see the "throttled_limbo_list" being non-empty in
6777+
* tg_throttle_down() if throttle_count turned 0 above.
6778+
*/
6779+
list_splice_init(&cfs_rq->throttled_limbo_list, &throttled_tasks);
6780+
67726781
/* Re-enqueue the tasks that have been throttled at this level. */
6773-
list_for_each_entry_safe(p, tmp, &cfs_rq->throttled_limbo_list, throttle_node) {
6782+
list_for_each_entry_safe(p, tmp, &throttled_tasks, throttle_node) {
6783+
/*
6784+
* Back to being throttled! Break out and put the remaining
6785+
* tasks back onto the limbo_list to prevent running them
6786+
* unnecessarily.
6787+
*/
6788+
if (cfs_rq->throttle_count)
6789+
break;
6790+
67746791
list_del_init(&p->throttle_node);
67756792
p->throttled = false;
6776-
enqueue_task_fair(rq_of(cfs_rq), p, ENQUEUE_WAKEUP);
6793+
enqueue_task_fair(rq, p, ENQUEUE_WAKEUP);
67776794
}
67786795

6796+
list_splice(&throttled_tasks, &cfs_rq->throttled_limbo_list);
6797+
67796798
/* Add cfs_rq with load or one or more already running entities to the list */
67806799
if (!cfs_rq_is_decayed(cfs_rq))
67816800
list_add_leaf_cfs_rq(cfs_rq);

0 commit comments

Comments
 (0)