]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
829f2974d13a20e15d47da0be38382dabccae5c4
[thirdparty/kernel/stable-queue.git] /
1 From f3f08c3acfb8860e07a22814a344e83c99ad7398 Mon Sep 17 00:00:00 2001
2 From: Tejun Heo <tj@kernel.org>
3 Date: Mon, 10 Feb 2025 09:27:09 -1000
4 Subject: sched_ext: Fix incorrect assumption about migration disabled tasks in task_can_run_on_remote_rq()
5
6 From: Tejun Heo <tj@kernel.org>
7
8 commit f3f08c3acfb8860e07a22814a344e83c99ad7398 upstream.
9
10 While fixing migration disabled task handling, 32966821574c ("sched_ext: Fix
11 migration disabled handling in targeted dispatches") assumed that a
12 migration disabled task's ->cpus_ptr would only have the pinned CPU. While
13 this is eventually true for migration disabled tasks that are switched out,
14 ->cpus_ptr update is performed by migrate_disable_switch() which is called
15 right before context_switch() in __scheduler(). However, the task is
16 enqueued earlier during pick_next_task() via put_prev_task_scx(), so there
17 is a race window where another CPU can see the task on a DSQ.
18
19 If the CPU tries to dispatch the migration disabled task while in that
20 window, task_allowed_on_cpu() will succeed and task_can_run_on_remote_rq()
21 will subsequently trigger SCHED_WARN(is_migration_disabled()).
22
23 WARNING: CPU: 8 PID: 1837 at kernel/sched/ext.c:2466 task_can_run_on_remote_rq+0x12e/0x140
24 Sched_ext: layered (enabled+all), task: runnable_at=-10ms
25 RIP: 0010:task_can_run_on_remote_rq+0x12e/0x140
26 ...
27 <TASK>
28 consume_dispatch_q+0xab/0x220
29 scx_bpf_dsq_move_to_local+0x58/0xd0
30 bpf_prog_84dd17b0654b6cf0_layered_dispatch+0x290/0x1cfa
31 bpf__sched_ext_ops_dispatch+0x4b/0xab
32 balance_one+0x1fe/0x3b0
33 balance_scx+0x61/0x1d0
34 prev_balance+0x46/0xc0
35 __pick_next_task+0x73/0x1c0
36 __schedule+0x206/0x1730
37 schedule+0x3a/0x160
38 __do_sys_sched_yield+0xe/0x20
39 do_syscall_64+0xbb/0x1e0
40 entry_SYSCALL_64_after_hwframe+0x77/0x7f
41
42 Fix it by converting the SCHED_WARN() back to a regular failure path. Also,
43 perform the migration disabled test before task_allowed_on_cpu() test so
44 that BPF schedulers which fail to handle migration disabled tasks can be
45 noticed easily.
46
47 While at it, adjust scx_ops_error() message for !task_allowed_on_cpu() case
48 for brevity and consistency.
49
50 Signed-off-by: Tejun Heo <tj@kernel.org>
51 Fixes: 32966821574c ("sched_ext: Fix migration disabled handling in targeted dispatches")
52 Acked-by: Andrea Righi <arighi@nvidia.com>
53 Reported-by: Jake Hillion <jakehillion@meta.com>
54 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
55 ---
56 kernel/sched/ext.c | 29 +++++++++++++++++++++--------
57 1 file changed, 21 insertions(+), 8 deletions(-)
58
59 --- a/kernel/sched/ext.c
60 +++ b/kernel/sched/ext.c
61 @@ -2311,6 +2311,25 @@ static bool task_can_run_on_remote_rq(st
62 SCHED_WARN_ON(task_cpu(p) == cpu);
63
64 /*
65 + * If @p has migration disabled, @p->cpus_ptr is updated to contain only
66 + * the pinned CPU in migrate_disable_switch() while @p is being switched
67 + * out. However, put_prev_task_scx() is called before @p->cpus_ptr is
68 + * updated and thus another CPU may see @p on a DSQ inbetween leading to
69 + * @p passing the below task_allowed_on_cpu() check while migration is
70 + * disabled.
71 + *
72 + * Test the migration disabled state first as the race window is narrow
73 + * and the BPF scheduler failing to check migration disabled state can
74 + * easily be masked if task_allowed_on_cpu() is done first.
75 + */
76 + if (unlikely(is_migration_disabled(p))) {
77 + if (trigger_error)
78 + scx_ops_error("SCX_DSQ_LOCAL[_ON] cannot move migration disabled %s[%d] from CPU %d to %d",
79 + p->comm, p->pid, task_cpu(p), cpu);
80 + return false;
81 + }
82 +
83 + /*
84 * We don't require the BPF scheduler to avoid dispatching to offline
85 * CPUs mostly for convenience but also because CPUs can go offline
86 * between scx_bpf_dispatch() calls and here. Trigger error iff the
87 @@ -2318,17 +2337,11 @@ static bool task_can_run_on_remote_rq(st
88 */
89 if (!task_allowed_on_cpu(p, cpu)) {
90 if (trigger_error)
91 - scx_ops_error("SCX_DSQ_LOCAL[_ON] verdict target cpu %d not allowed for %s[%d]",
92 - cpu_of(rq), p->comm, p->pid);
93 + scx_ops_error("SCX_DSQ_LOCAL[_ON] target CPU %d not allowed for %s[%d]",
94 + cpu, p->comm, p->pid);
95 return false;
96 }
97
98 - /*
99 - * If @p has migration disabled, @p->cpus_ptr only contains its current
100 - * CPU and the above task_allowed_on_cpu() test should have failed.
101 - */
102 - SCHED_WARN_ON(is_migration_disabled(p));
103 -
104 if (!scx_rq_online(rq))
105 return false;
106