Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

sched_ext: Fix local_dsq_post_enq() to use task's scheduler in sub-sched

local_dsq_post_enq() calls call_task_dequeue() with scx_root instead of
the scheduler instance actually managing the task. When
CONFIG_EXT_SUB_SCHED is enabled, tasks may be managed by a sub-scheduler
whose ops.dequeue() callback differs from root's. Using scx_root causes
the wrong scheduler's ops.dequeue() to be consulted: sub-sched tasks
dispatched to a local DSQ via scx_bpf_dsq_move_to_local() will have
SCX_TASK_IN_CUSTODY cleared but the sub-scheduler's ops.dequeue() is
never invoked, violating the custody exit semantics.

Fix by adding a 'struct scx_sched *sch' parameter to local_dsq_post_enq()
and move_local_task_to_local_dsq(), and propagating the correct scheduler
from their callers dispatch_enqueue(), move_task_between_dsqs(), and
consume_dispatch_q().

This is consistent with dispatch_enqueue()'s non-local path which already
passes 'sch' directly to call_task_dequeue() for global/bypass DSQs.

Fixes: ebf1ccff79c4 ("sched_ext: Fix ops.dequeue() semantics")
Signed-off-by: zhidao su <suzhidao@xiaomi.com>
Signed-off-by: Tejun Heo <tj@kernel.org>

authored by

zhidao su and committed by
Tejun Heo
4e3d7c89 05909810

+9 -8
+9 -8
kernel/sched/ext.c
··· 1389 1389 p->scx.flags &= ~SCX_TASK_IN_CUSTODY; 1390 1390 } 1391 1391 1392 - static void local_dsq_post_enq(struct scx_dispatch_q *dsq, struct task_struct *p, 1393 - u64 enq_flags) 1392 + static void local_dsq_post_enq(struct scx_sched *sch, struct scx_dispatch_q *dsq, 1393 + struct task_struct *p, u64 enq_flags) 1394 1394 { 1395 1395 struct rq *rq = container_of(dsq, struct rq, scx.local_dsq); 1396 1396 bool preempt = false; 1397 1397 1398 - call_task_dequeue(scx_root, rq, p, 0); 1398 + call_task_dequeue(sch, rq, p, 0); 1399 1399 1400 1400 /* 1401 1401 * If @rq is in balance, the CPU is already vacant and looking for the ··· 1519 1519 * concurrently in a non-atomic way. 1520 1520 */ 1521 1521 if (is_local) { 1522 - local_dsq_post_enq(dsq, p, enq_flags); 1522 + local_dsq_post_enq(sch, dsq, p, enq_flags); 1523 1523 } else { 1524 1524 /* 1525 1525 * Task on global/bypass DSQ: leave custody, task on ··· 2130 2130 schedule_reenq_local(rq, 0); 2131 2131 } 2132 2132 2133 - static void move_local_task_to_local_dsq(struct task_struct *p, u64 enq_flags, 2133 + static void move_local_task_to_local_dsq(struct scx_sched *sch, 2134 + struct task_struct *p, u64 enq_flags, 2134 2135 struct scx_dispatch_q *src_dsq, 2135 2136 struct rq *dst_rq) 2136 2137 { ··· 2151 2150 dsq_inc_nr(dst_dsq, p, enq_flags); 2152 2151 p->scx.dsq = dst_dsq; 2153 2152 2154 - local_dsq_post_enq(dst_dsq, p, enq_flags); 2153 + local_dsq_post_enq(sch, dst_dsq, p, enq_flags); 2155 2154 } 2156 2155 2157 2156 /** ··· 2372 2371 /* @p is going from a non-local DSQ to a local DSQ */ 2373 2372 if (src_rq == dst_rq) { 2374 2373 task_unlink_from_dsq(p, src_dsq); 2375 - move_local_task_to_local_dsq(p, enq_flags, 2374 + move_local_task_to_local_dsq(sch, p, enq_flags, 2376 2375 src_dsq, dst_rq); 2377 2376 raw_spin_unlock(&src_dsq->lock); 2378 2377 } else { ··· 2425 2424 2426 2425 if (rq == task_rq) { 2427 2426 task_unlink_from_dsq(p, dsq); 2428 - move_local_task_to_local_dsq(p, enq_flags, dsq, rq); 2427 + move_local_task_to_local_dsq(sch, p, enq_flags, dsq, rq); 2429 2428 raw_spin_unlock(&dsq->lock); 2430 2429 return true; 2431 2430 }