[PATCH 2/9] sched/core: defer WARN console output under rq->lock
From: Rik van Riel
Date: Wed Jun 10 2026 - 22:23:56 EST
Convert the WARN*() calls that run under rq->lock or ->pi_lock to the
SCHED_WARN*() variants, so their console output is deferred to irq_work
instead of being emitted synchronously (which can deadlock via
console_unlock() -> up(&console_sem) -> try_to_wake_up() while the lock
is held).
This should prevent a deadlock if these warnings fire with a legacy
or boot console configured.
Signed-off-by: Rik van Riel <riel@xxxxxxxxxxx>
Assisted-by: Claude:claude-opus-4-8
---
kernel/sched/core.c | 68 ++++++++++++++++++++++-----------------------
1 file changed, 34 insertions(+), 34 deletions(-)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 2f4530eb543f..d83ee1fcdd5e 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -868,7 +868,7 @@ void update_rq_clock(struct rq *rq)
return;
if (sched_feat(WARN_DOUBLE_CLOCK))
- WARN_ON_ONCE(rq->clock_update_flags & RQCF_UPDATED);
+ SCHED_WARN_ON_ONCE(rq->clock_update_flags & RQCF_UPDATED);
rq->clock_update_flags |= RQCF_UPDATED;
clock = sched_clock_cpu(cpu_of(rq));
@@ -1826,7 +1826,7 @@ static inline void uclamp_rq_dec_id(struct rq *rq, struct task_struct *p,
bucket = &uc_rq->bucket[uc_se->bucket_id];
- WARN_ON_ONCE(!bucket->tasks);
+ SCHED_WARN_ON_ONCE(!bucket->tasks);
if (likely(bucket->tasks))
bucket->tasks--;
@@ -1846,7 +1846,7 @@ static inline void uclamp_rq_dec_id(struct rq *rq, struct task_struct *p,
* Defensive programming: this should never happen. If it happens,
* e.g. due to future modification, warn and fix up the expected value.
*/
- WARN_ON_ONCE(bucket->value > rq_clamp);
+ SCHED_WARN_ON_ONCE(bucket->value > rq_clamp);
if (bucket->value >= rq_clamp) {
bkt_clamp = uclamp_rq_max_value(rq, clamp_id, uc_se->value);
uclamp_rq_set(rq, clamp_id, bkt_clamp);
@@ -2229,7 +2229,7 @@ void activate_task(struct rq *rq, struct task_struct *p, int flags)
void deactivate_task(struct rq *rq, struct task_struct *p, int flags)
{
- WARN_ON_ONCE(flags & DEQUEUE_SLEEP);
+ SCHED_WARN_ON_ONCE(flags & DEQUEUE_SLEEP);
WRITE_ONCE(p->on_rq, TASK_ON_RQ_MIGRATING);
ASSERT_EXCLUSIVE_WRITER(p->on_rq);
@@ -2556,7 +2556,7 @@ static struct rq *move_queued_task(struct rq *rq, struct rq_flags *rf,
rq = cpu_rq(new_cpu);
rq_lock(rq, rf);
- WARN_ON_ONCE(task_cpu(p) != new_cpu);
+ SCHED_WARN_ON_ONCE(task_cpu(p) != new_cpu);
activate_task(rq, p, 0);
wakeup_preempt(rq, p, 0);
@@ -2642,7 +2642,7 @@ static int migration_cpu_stop(void *data)
* If we were passed a pending, then ->stop_pending was set, thus
* p->migration_pending must have remained stable.
*/
- WARN_ON_ONCE(pending && pending != p->migration_pending);
+ SCHED_WARN_ON_ONCE(pending && pending != p->migration_pending);
/*
* If task_rq(p) != rq, it cannot be migrated here, because we're
@@ -2701,7 +2701,7 @@ static int migration_cpu_stop(void *data)
* determine is_migration_disabled() and so have to chase after
* it.
*/
- WARN_ON_ONCE(!pending->stop_pending);
+ SCHED_WARN_ON_ONCE(!pending->stop_pending);
preempt_disable();
rq_unlock(rq, &rf);
raw_spin_unlock_irqrestore(&p->pi_lock, rf.flags);
@@ -3044,7 +3044,7 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
*
* Either way, we really should have a @pending here.
*/
- if (WARN_ON_ONCE(!pending)) {
+ if (SCHED_WARN_ON_ONCE(!pending)) {
task_rq_unlock(rq, p, rf);
return -EINVAL;
}
@@ -3101,7 +3101,7 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
wait_var_event(&my_pending.refs, !refcount_read(&my_pending.refs));
/* ARGH */
- WARN_ON_ONCE(my_pending.stop_pending);
+ SCHED_WARN_ON_ONCE(my_pending.stop_pending);
return 0;
}
@@ -3156,7 +3156,7 @@ static int __set_cpus_allowed_ptr_locked(struct task_struct *p,
goto out;
}
- if (WARN_ON_ONCE(p == current &&
+ if (SCHED_WARN_ON_ONCE(p == current &&
is_migration_disabled(p) &&
!cpumask_test_cpu(task_cpu(p), ctx->new_mask))) {
ret = -EBUSY;
@@ -3346,14 +3346,14 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
* We should never call set_task_cpu() on a blocked task,
* ttwu() will sort out the placement.
*/
- WARN_ON_ONCE(state != TASK_RUNNING && state != TASK_WAKING && !p->on_rq);
+ SCHED_WARN_ON_ONCE(state != TASK_RUNNING && state != TASK_WAKING && !p->on_rq);
/*
* Migrating fair class task must have p->on_rq = TASK_ON_RQ_MIGRATING,
* because schedstat_wait_{start,end} rebase migrating task's wait_start
* time relying on p->on_rq.
*/
- WARN_ON_ONCE(state == TASK_RUNNING &&
+ SCHED_WARN_ON_ONCE(state == TASK_RUNNING &&
p->sched_class == &fair_sched_class &&
(p->on_rq && !task_on_rq_migrating(p)));
@@ -3368,15 +3368,15 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
* Furthermore, all task_rq users should acquire both locks, see
* task_rq_lock().
*/
- WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) ||
+ SCHED_WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) ||
lockdep_is_held(__rq_lockp(task_rq(p)))));
#endif
/*
* Clearly, migrating tasks to offline CPUs is a fairly daft thing.
*/
- WARN_ON_ONCE(!cpu_online(new_cpu));
+ SCHED_WARN_ON_ONCE(!cpu_online(new_cpu));
- WARN_ON_ONCE(is_migration_disabled(p));
+ SCHED_WARN_ON_ONCE(is_migration_disabled(p));
trace_sched_migrate_task(p, new_cpu);
@@ -3902,10 +3902,10 @@ void sched_ttwu_pending(void *arg)
update_rq_clock(rq);
llist_for_each_entry_safe(p, t, llist, wake_entry.llist) {
- if (WARN_ON_ONCE(p->on_cpu))
+ if (SCHED_WARN_ON_ONCE(p->on_cpu))
smp_cond_load_acquire(&p->on_cpu, !VAL);
- if (WARN_ON_ONCE(task_cpu(p) != cpu_of(rq)))
+ if (SCHED_WARN_ON_ONCE(task_cpu(p) != cpu_of(rq)))
set_task_cpu(p, cpu_of(rq));
ttwu_do_activate(rq, p, p->sched_remote_wakeup ? WF_MIGRATED : 0, &rf);
@@ -4102,7 +4102,7 @@ bool ttwu_state_match(struct task_struct *p, unsigned int state, int *success)
int match;
if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)) {
- WARN_ON_ONCE((state & TASK_RTLOCK_WAIT) &&
+ SCHED_WARN_ON_ONCE((state & TASK_RTLOCK_WAIT) &&
state != TASK_RTLOCK_WAIT);
}
@@ -5333,7 +5333,7 @@ static struct rq *finish_task_switch(struct task_struct *prev)
*
* Also, see FORK_PREEMPT_COUNT.
*/
- if (WARN_ONCE(preempt_count() != 2*PREEMPT_DISABLE_OFFSET,
+ if (SCHED_WARN_ONCE(preempt_count() != 2*PREEMPT_DISABLE_OFFSET,
"corrupted preempt_count: %s/%d/0x%x\n",
current->comm, current->pid, preempt_count()))
preempt_count_set(FORK_PREEMPT_COUNT);
@@ -5861,7 +5861,7 @@ static void sched_tick_remote(struct work_struct *work)
* we are always sure that there is no proxy (only a
* single task is running).
*/
- WARN_ON_ONCE(rq->curr != rq->donor);
+ SCHED_WARN_ON_ONCE(rq->curr != rq->donor);
update_rq_clock(rq);
if (!is_idle_task(curr)) {
@@ -5870,7 +5870,7 @@ static void sched_tick_remote(struct work_struct *work)
* reasonable amount of time.
*/
u64 delta = rq_clock_task(rq) - curr->se.exec_start;
- WARN_ON_ONCE(delta > (u64)NSEC_PER_SEC * 30);
+ SCHED_WARN_ON_ONCE(delta > (u64)NSEC_PER_SEC * 30);
}
curr->sched_class->task_tick(rq, curr, 0);
@@ -6302,7 +6302,7 @@ pick_next_task(struct rq *rq, struct rq_flags *rf)
* For robustness, update the min_vruntime_fi for
* unconstrained picks as well.
*/
- WARN_ON_ONCE(fi_before);
+ SCHED_WARN_ON_ONCE(fi_before);
task_vruntime_update(rq, next, false);
goto out_set_next;
}
@@ -6380,7 +6380,7 @@ pick_next_task(struct rq *rq, struct rq_flags *rf)
rq->core_sched_seq = rq->core->core_pick_seq;
/* Something should have been selected for current CPU */
- WARN_ON_ONCE(!next);
+ SCHED_WARN_ON_ONCE(!next);
/*
* Reschedule siblings
@@ -6423,7 +6423,7 @@ pick_next_task(struct rq *rq, struct rq_flags *rf)
}
/* Did we break L1TF mitigation requirements? */
- WARN_ON_ONCE(!cookie_match(next, rq_i->core_pick));
+ SCHED_WARN_ON_ONCE(!cookie_match(next, rq_i->core_pick));
if (rq_i->curr == rq_i->core_pick) {
rq_i->core_pick = NULL;
@@ -6561,7 +6561,7 @@ static void sched_core_cpu_starting(unsigned int cpu)
guard(core_lock)(&cpu);
- WARN_ON_ONCE(rq->core != rq);
+ SCHED_WARN_ON_ONCE(rq->core != rq);
/* if we're the first, we'll be our own leader */
if (cpumask_weight(smt_mask) == 1)
@@ -6578,7 +6578,7 @@ static void sched_core_cpu_starting(unsigned int cpu)
}
}
- if (WARN_ON_ONCE(!core_rq)) /* whoopsie */
+ if (SCHED_WARN_ON_ONCE(!core_rq)) /* whoopsie */
return;
/* install and validate core_rq */
@@ -6588,7 +6588,7 @@ static void sched_core_cpu_starting(unsigned int cpu)
if (t == cpu)
rq->core = core_rq;
- WARN_ON_ONCE(rq->core != core_rq);
+ SCHED_WARN_ON_ONCE(rq->core != core_rq);
}
}
@@ -6602,7 +6602,7 @@ static void sched_core_cpu_deactivate(unsigned int cpu)
/* if we're the last man standing, nothing to do */
if (cpumask_weight(smt_mask) == 1) {
- WARN_ON_ONCE(rq->core != rq);
+ SCHED_WARN_ON_ONCE(rq->core != rq);
return;
}
@@ -6618,7 +6618,7 @@ static void sched_core_cpu_deactivate(unsigned int cpu)
break;
}
- if (WARN_ON_ONCE(!core_rq)) /* impossible */
+ if (SCHED_WARN_ON_ONCE(!core_rq)) /* impossible */
return;
/* copy the shared state to the new leader */
@@ -7004,7 +7004,7 @@ find_proxy_task(struct rq *rq, struct task_struct *donor, struct rq_flags *rf)
static struct task_struct *
find_proxy_task(struct rq *rq, struct task_struct *donor, struct rq_flags *rf)
{
- WARN_ONCE(1, "This should never be called in the !SCHED_PROXY_EXEC case\n");
+ SCHED_WARN_ONCE(1, "This should never be called in the !SCHED_PROXY_EXEC case\n");
return donor;
}
#endif /* SCHED_PROXY_EXEC */
@@ -7666,8 +7666,8 @@ void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task)
* real need to boost.
*/
if (unlikely(p == rq->idle)) {
- WARN_ON(p != rq->curr);
- WARN_ON(p->pi_blocked_on);
+ SCHED_WARN_ON(p != rq->curr);
+ SCHED_WARN_ON(p->pi_blocked_on);
goto out_unlock;
}
@@ -8499,7 +8499,7 @@ static void balance_push_set(int cpu, bool on)
rq_lock_irqsave(rq, &rf);
if (on) {
- WARN_ON_ONCE(rq->balance_callback);
+ SCHED_WARN_ON_ONCE(rq->balance_callback);
rq->balance_callback = &balance_push_callback;
} else if (rq->balance_callback == &balance_push_callback) {
rq->balance_callback = NULL;
@@ -8832,7 +8832,7 @@ int sched_cpu_dying(unsigned int cpu)
rq_lock_irqsave(rq, &rf);
update_rq_clock(rq);
if (rq->nr_running != 1 || rq_has_pinned_tasks(rq)) {
- WARN(true, "Dying CPU not properly vacated!");
+ SCHED_WARN(true, "Dying CPU not properly vacated!");
dump_rq_tasks(rq, KERN_WARNING);
}
dl_server_stop(&rq->fair_server);
--
2.53.0-Meta