From d44093323131a42a85184315bb9b6da4813cc39b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 14 Aug 2026 23:47:39 -1000 Subject: [PATCH] sched_ext: Drop unlocked scx_rq_clock_invalidate() from scx_root_disable() scx_root_disable() invalidates each rq's clock before taking the rq lock. scx_rq_clock_invalidate() is a plain read-modify-write of rq->scx.flags and every other writer of the word runs under the rq lock, so the unlocked update can race a concurrent flags update and lose one side's bits. The invalidation doesn't matter in the first place. The cached clock is read only by scx_bpf_now() from a loaded scheduler's BPF programs, nothing can re-validate the clock while sched_ext is disabled as scx_rq_clock_update() is gated on scx_enabled() too, and the usual rq lock cycles under the next scheduler refresh or invalidate it before it's practically observable. Drop the invalidation instead of fixing the locking. v2: Description and comment updated - the invalidation is unnecessary rather than subsumed by the rq lock cycle below. Fixes: 3a9910b5904d ("sched_ext: Implement scx_bpf_now()") Signed-off-by: Tejun Heo Cc: Changwoo Min --- kernel/sched/ext/ext.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c index 2adf2bde0cb1..0e136398e715 100644 --- a/kernel/sched/ext/ext.c +++ b/kernel/sched/ext/ext.c @@ -6476,12 +6476,9 @@ static void scx_root_disable(struct scx_sched *sch) percpu_up_write(&scx_fork_rwsem); /* - * Invalidate all the rq clocks to prevent getting outdated - * rq clocks from a previous scx scheduler. - * - * Also re-balance the dl_server bandwidth reservations: detach - * ext_server (no more sched_ext tasks) and reinstate fair_server if it - * was previously detached because we were running in full mode. + * Re-balance the dl_server bandwidth reservations: detach ext_server + * (no more sched_ext tasks) and reinstate fair_server if it was + * previously detached because we were running in full mode. * * Unlike the enable path, this runs on a recovery path that cannot * fail, so we use dl_server_swap_bw() to atomically free ext_server's @@ -6494,8 +6491,6 @@ static void scx_root_disable(struct scx_sched *sch) for_each_possible_cpu(cpu) { struct rq *rq = cpu_rq(cpu); - scx_rq_clock_invalidate(rq); - scoped_guard(rq_lock_irqsave, rq) { update_rq_clock(rq); if (was_switched_all) {