Skip to content

Commit 3d92aa0

Browse files
htejungregkh
authored andcommitted
sched_ext: Fix migration disabled handling in targeted dispatches
[ Upstream commit 3296682 ] A dispatch operation that can target a specific local DSQ - scx_bpf_dsq_move_to_local() or scx_bpf_dsq_move() - checks whether the task can be migrated to the target CPU using task_can_run_on_remote_rq(). If the task can't be migrated to the targeted CPU, it is bounced through a global DSQ. task_can_run_on_remote_rq() assumes that the task is on a CPU that's different from the targeted CPU but the callers doesn't uphold the assumption and may call the function when the task is already on the target CPU. When such task has migration disabled, task_can_run_on_remote_rq() ends up returning %false incorrectly unnecessarily bouncing the task to a global DSQ. Fix it by updating the callers to only call task_can_run_on_remote_rq() when the task is on a different CPU than the target CPU. As this is a bit subtle, for clarity and documentation: - Make task_can_run_on_remote_rq() trigger SCHED_WARN_ON() if the task is on the same CPU as the target CPU. - is_migration_disabled() test in task_can_run_on_remote_rq() cannot trigger if the task is on a different CPU than the target CPU as the preceding task_allowed_on_cpu() test should fail beforehand. Convert the test into SCHED_WARN_ON(). Signed-off-by: Tejun Heo <tj@kernel.org> Fixes: 4c30f5c ("sched_ext: Implement scx_bpf_dispatch[_vtime]_from_dsq()") Fixes: 0366017 ("sched_ext: Use task_can_run_on_remote_rq() test in dispatch_to_local_dsq()") Cc: stable@vger.kernel.org # v6.12+ Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent d045c8f commit 3d92aa0

File tree

1 file changed

+13
-4
lines changed

1 file changed

+13
-4
lines changed

kernel/sched/ext.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2300,12 +2300,16 @@ static void move_remote_task_to_local_dsq(struct task_struct *p, u64 enq_flags,
23002300
*
23012301
* - The BPF scheduler is bypassed while the rq is offline and we can always say
23022302
* no to the BPF scheduler initiated migrations while offline.
2303+
*
2304+
* The caller must ensure that @p and @rq are on different CPUs.
23032305
*/
23042306
static bool task_can_run_on_remote_rq(struct task_struct *p, struct rq *rq,
23052307
bool trigger_error)
23062308
{
23072309
int cpu = cpu_of(rq);
23082310

2311+
SCHED_WARN_ON(task_cpu(p) == cpu);
2312+
23092313
/*
23102314
* We don't require the BPF scheduler to avoid dispatching to offline
23112315
* CPUs mostly for convenience but also because CPUs can go offline
@@ -2319,8 +2323,11 @@ static bool task_can_run_on_remote_rq(struct task_struct *p, struct rq *rq,
23192323
return false;
23202324
}
23212325

2322-
if (unlikely(is_migration_disabled(p)))
2323-
return false;
2326+
/*
2327+
* If @p has migration disabled, @p->cpus_ptr only contains its current
2328+
* CPU and the above task_allowed_on_cpu() test should have failed.
2329+
*/
2330+
SCHED_WARN_ON(is_migration_disabled(p));
23242331

23252332
if (!scx_rq_online(rq))
23262333
return false;
@@ -2424,7 +2431,8 @@ static struct rq *move_task_between_dsqs(struct task_struct *p, u64 enq_flags,
24242431

24252432
if (dst_dsq->id == SCX_DSQ_LOCAL) {
24262433
dst_rq = container_of(dst_dsq, struct rq, scx.local_dsq);
2427-
if (!task_can_run_on_remote_rq(p, dst_rq, true)) {
2434+
if (src_rq != dst_rq &&
2435+
unlikely(!task_can_run_on_remote_rq(p, dst_rq, true))) {
24282436
dst_dsq = find_global_dsq(p);
24292437
dst_rq = src_rq;
24302438
}
@@ -2541,7 +2549,8 @@ static void dispatch_to_local_dsq(struct rq *rq, struct scx_dispatch_q *dst_dsq,
25412549
}
25422550

25432551
#ifdef CONFIG_SMP
2544-
if (unlikely(!task_can_run_on_remote_rq(p, dst_rq, true))) {
2552+
if (src_rq != dst_rq &&
2553+
unlikely(!task_can_run_on_remote_rq(p, dst_rq, true))) {
25452554
dispatch_enqueue(find_global_dsq(p), p,
25462555
enq_flags | SCX_ENQ_CLEAR_OPSS);
25472556
return;

0 commit comments

Comments
 (0)