[PATCH v3] sched/core: Use the scheduling context for remote ticks
From: Shubhang Kaushik (Ampere)
Date: Wed Oct 21 2026 - 19:36:53 EST
sched_tick_remote() assumes that a CPU in full dynticks mode has only
one running task. It therefore assumes that proxy execution cannot be
active and that rq->curr == rq->donor.
However, sched_can_stop_tick() can stop the tick with multiple tasks on
the runqueue. With exactly one SCHED_RR task, the tick is not needed for
round-robin timeslice rotation. When there are no SCHED_RR tasks,
SCHED_FIFO tasks do not require the tick because they have no forced
tick preemption. Lower scheduling-class tasks can still be queued in
both cases.
Consequently, a SCHED_FIFO task blocked on a SCHED_NORMAL mutex owner
can remain rq->donor while find_proxy_task() selects the owner to
execute as rq->curr. sched_tick_remote() can therefore run with
rq->curr != rq->donor.
The full-nohz state check in sched_tick_remote() is intentionally racy
and can allow an extra or missed remote tick. This issue does not rely
on that race: the tick can be legitimately stopped in the cases above.
Use rq->donor for the remote class tick and its full-nohz tick-interval
sanity check, matching sched_tick() and hrtick().
Fixes: 7de9d4f94638 ("sched: Start blocked_on chain processing in find_proxy_task()")
Acked-by: John Stultz <jstultz@xxxxxxxxxx>
Signed-off-by: Shubhang Kaushik (Ampere) <sh@xxxxxxxxxx>
---
Testing was performed on an Ampere Altra system with
CONFIG_SCHED_PROXY_EXEC=y and CONFIG_NO_HZ_FULL=y, booted with:
sched_proxy_exec=1 nohz_full=78
On the unpatched baseline, 70dd4ee72eb2 (7.3.0-rc7), mutex locktorture
with four writers pinned to CPU 78 and RT boosting triggered:
WARNING: kernel/sched/core.c:5895 at sched_tick_remote...
Workqueue: events_unbound sched_tick_remote
This warning is WARN_ON_ONCE(rq->curr != rq->donor), demonstrating that
a full-nohz remote tick can run while the executing task and scheduling
context differ.
The v3 patched kernel completed the same 10 minute workload
without scheduler warnings or locktorture failures.
Changes in v3:
- Rewrite the changelog to explain why full-nohz can stop the tick
with multiple tasks on the runqueue and therefore permit proxy
execution.
- Clarify that the racy full-nohz-state check is not required to
trigger the issue.
- Add Acked-by from John Stultz.
Link to v2: https://lore.kernel.org/r/20261021-remote-tick-proxy-v2-1-07890601a71e@xxxxxxxxxx
---
kernel/sched/core.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 0ab15f03cb947eb958ff9f97d890716346377889..729ebaca35e1a9a12cda59e96c650ee6b1576951 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5934,26 +5934,20 @@ static void sched_tick_remote(struct work_struct *work)
*/
if (tick_nohz_tick_stopped_cpu(cpu)) {
guard(rq_lock_irq)(rq);
- struct task_struct *curr = rq->curr;
+ struct task_struct *donor = rq->donor;
if (cpu_online(cpu)) {
- /*
- * Since this is a remote tick for full dynticks mode,
- * we are always sure that there is no proxy (only a
- * single task is running).
- */
- WARN_ON_ONCE(rq->curr != rq->donor);
update_rq_clock(rq);
- if (!is_idle_task(curr)) {
+ if (!is_idle_task(donor)) {
/*
* Make sure the next tick runs within a
* reasonable amount of time.
*/
- u64 delta = rq_clock_task(rq) - curr->se.exec_start;
+ u64 delta = rq_clock_task(rq) - donor->se.exec_start;
WARN_ON_ONCE(delta > (u64)NSEC_PER_SEC * 30);
}
- curr->sched_class->task_tick(rq, curr, 0);
+ donor->sched_class->task_tick(rq, donor, 0);
calc_load_nohz_remote(rq);
}
---
base-commit: a804c5742bff224d4cb4d25dd383554d598be32b
change-id: 20261016-remote-tick-proxy-237fc1da63c8
Best regards,
--
Shubhang Kaushik (Ampere) <sh@xxxxxxxxxx>