The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Rik van Riel <riel@surriel.com>
To: linux-kernel@vger.kernel.org
Cc: kernel-team@meta.com, mingo@redhat.com, peterz@infradead.org,
	juri.lelli@redhat.com, vincent.guittot@linaro.org,
	dietmar.eggemann@arm.com, vschneid@redhat.com,
	Rik van Riel <riel@surriel.com>
Subject: [PATCH 2/9] sched/core: defer WARN console output under rq->lock
Date: Wed, 10 Jun 2026 22:14:09 -0400	[thread overview]
Message-ID: <20260611021416.910555-3-riel@surriel.com> (raw)
In-Reply-To: <20260611021416.910555-1-riel@surriel.com>

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@surriel.com>
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


  parent reply	other threads:[~2026-06-11  2:14 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-11  2:14 [PATCH 0/9] sched: make WARN_ON under rq->lock deadlock-safe (SCHED_WARN_ON) Rik van Riel
2026-06-11  2:14 ` [PATCH 1/9] sched: add SCHED_WARN_ON()/SCHED_WARN_ON_ONCE()/SCHED_WARN()/SCHED_WARN_ONCE() Rik van Riel
2026-06-11  2:14 ` Rik van Riel [this message]
2026-06-11  2:14 ` [PATCH 3/9] sched/fair: defer WARN console output under rq->lock Rik van Riel
2026-06-11  2:14 ` [PATCH 4/9] sched/deadline: " Rik van Riel
2026-06-11  2:14 ` [PATCH 5/9] sched/rt: " Rik van Riel
2026-06-11  2:14 ` [PATCH 6/9] sched_ext: " Rik van Riel
2026-06-11  2:14 ` [PATCH 7/9] sched/core_sched: " Rik van Riel
2026-06-11  2:14 ` [PATCH 8/9] sched/deadline: " Rik van Riel
2026-06-11  2:14 ` [PATCH 9/9] sched/rt: " Rik van Riel
2026-06-11  7:43 ` [PATCH 0/9] sched: make WARN_ON under rq->lock deadlock-safe (SCHED_WARN_ON) Peter Zijlstra
2026-06-11 16:20   ` Rik van Riel
2026-06-11 19:19     ` Peter Zijlstra
2026-06-12  1:53       ` Rik van Riel
2026-06-12  6:52         ` Peter Zijlstra

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260611021416.910555-3-riel@surriel.com \
    --to=riel@surriel.com \
    --cc=dietmar.eggemann@arm.com \
    --cc=juri.lelli@redhat.com \
    --cc=kernel-team@meta.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=vincent.guittot@linaro.org \
    --cc=vschneid@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox