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 3/9] sched/fair: defer WARN console output under rq->lock
Date: Wed, 10 Jun 2026 22:14:10 -0400	[thread overview]
Message-ID: <20260611021416.910555-4-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/fair.c | 66 ++++++++++++++++++++++-----------------------
 1 file changed, 33 insertions(+), 33 deletions(-)

diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 49b48c5f5746..0cddbbe2e6a5 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -404,7 +404,7 @@ static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
 
 static inline void assert_list_leaf_cfs_rq(struct rq *rq)
 {
-	WARN_ON_ONCE(rq->tmp_alone_branch != &rq->leaf_cfs_rq_list);
+	SCHED_WARN_ON_ONCE(rq->tmp_alone_branch != &rq->leaf_cfs_rq_list);
 }
 
 /* Iterate through all leaf cfs_rq's on a runqueue */
@@ -689,7 +689,7 @@ __sum_w_vruntime_add(struct cfs_rq *cfs_rq, struct sched_entity *se)
 	s64 w_vruntime, key = entity_key(cfs_rq, se);
 
 	w_vruntime = key * weight;
-	WARN_ON_ONCE((w_vruntime >> 63) != (w_vruntime >> 62));
+	SCHED_WARN_ON_ONCE((w_vruntime >> 63) != (w_vruntime >> 62));
 
 	cfs_rq->sum_w_vruntime += w_vruntime;
 	cfs_rq->sum_weight += weight;
@@ -861,7 +861,7 @@ bool update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
 	u64 avruntime = avg_vruntime(cfs_rq);
 	s64 vlag = entity_lag(cfs_rq, se, avruntime);
 
-	WARN_ON_ONCE(!se->on_rq);
+	SCHED_WARN_ON_ONCE(!se->on_rq);
 
 	if (se->sched_delayed) {
 		/* previous vlag < 0 otherwise se would not be delayed */
@@ -1153,7 +1153,7 @@ static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq, bool protect)
 	if (sched_feat(PICK_BUDDY) && protect &&
 	    cfs_rq->next && entity_eligible(cfs_rq, cfs_rq->next)) {
 		/* ->next will never be delayed */
-		WARN_ON_ONCE(cfs_rq->next->sched_delayed);
+		SCHED_WARN_ON_ONCE(cfs_rq->next->sched_delayed);
 		return cfs_rq->next;
 	}
 
@@ -4918,7 +4918,7 @@ static inline bool load_avg_is_decayed(struct sched_avg *sa)
 	 * Make sure that rounding and/or propagation of PELT values never
 	 * break this.
 	 */
-	WARN_ON_ONCE(sa->load_avg ||
+	SCHED_WARN_ON_ONCE(sa->load_avg ||
 		      sa->util_avg ||
 		      sa->runnable_avg);
 
@@ -6065,7 +6065,7 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
 
 		weight = avg_vruntime_weight(cfs_rq, se->load.weight);
 		lag *= load + weight;
-		if (WARN_ON_ONCE(!load))
+		if (SCHED_WARN_ON_ONCE(!load))
 			load = 1;
 		lag = div64_long(lag, load);
 
@@ -6258,7 +6258,7 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
 	clear_buddies(cfs_rq, se);
 
 	if (flags & DEQUEUE_DELAYED) {
-		WARN_ON_ONCE(!se->sched_delayed);
+		SCHED_WARN_ON_ONCE(!se->sched_delayed);
 	} else {
 		bool delay = sleep;
 		/*
@@ -6268,7 +6268,7 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
 		if (flags & (DEQUEUE_SPECIAL | DEQUEUE_THROTTLE))
 			delay = false;
 
-		WARN_ON_ONCE(delay && se->sched_delayed);
+		SCHED_WARN_ON_ONCE(delay && se->sched_delayed);
 
 		if (sched_feat(DELAY_DEQUEUE) && delay &&
 		    !entity_eligible(cfs_rq, se)) {
@@ -6360,7 +6360,7 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, bool first)
 	}
 
 	update_stats_curr_start(cfs_rq, se);
-	WARN_ON_ONCE(cfs_rq->curr);
+	SCHED_WARN_ON_ONCE(cfs_rq->curr);
 	cfs_rq->curr = se;
 
 	/*
@@ -6422,7 +6422,7 @@ static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
 		/* in !on_rq case, update occurred at dequeue */
 		update_load_avg(cfs_rq, prev, 0);
 	}
-	WARN_ON_ONCE(cfs_rq->curr != prev);
+	SCHED_WARN_ON_ONCE(cfs_rq->curr != prev);
 	cfs_rq->curr = NULL;
 }
 
@@ -6768,7 +6768,7 @@ static int tg_unthrottle_up(struct task_group *tg, void *data)
 
 		cfs_rq->throttled_clock_self = 0;
 
-		if (WARN_ON_ONCE((s64)delta < 0))
+		if (SCHED_WARN_ON_ONCE((s64)delta < 0))
 			delta = 0;
 
 		cfs_rq->throttled_clock_self_time += delta;
@@ -6855,8 +6855,8 @@ static int tg_throttle_down(struct task_group *tg, void *data)
 		cfs_rq->pelt_clock_throttled = 1;
 	}
 
-	WARN_ON_ONCE(cfs_rq->throttled_clock_self);
-	WARN_ON_ONCE(!list_empty(&cfs_rq->throttled_limbo_list));
+	SCHED_WARN_ON_ONCE(cfs_rq->throttled_clock_self);
+	SCHED_WARN_ON_ONCE(!list_empty(&cfs_rq->throttled_limbo_list));
 	return 0;
 }
 
@@ -6910,7 +6910,7 @@ static bool throttle_cfs_rq(struct cfs_rq *cfs_rq)
 	 * throttled-list.  rq->lock protects completion.
 	 */
 	cfs_rq->throttled = 1;
-	WARN_ON_ONCE(cfs_rq->throttled_clock);
+	SCHED_WARN_ON_ONCE(cfs_rq->throttled_clock);
 
 	/*
 	 * If current hierarchy was throttled, add throttle work to the
@@ -7029,7 +7029,7 @@ static inline void __unthrottle_cfs_rq_async(struct cfs_rq *cfs_rq)
 	}
 
 	/* Already enqueued */
-	if (WARN_ON_ONCE(!list_empty(&cfs_rq->throttled_csd_list)))
+	if (SCHED_WARN_ON_ONCE(!list_empty(&cfs_rq->throttled_csd_list)))
 		return;
 
 	first = list_empty(&rq->cfsb_csd_list);
@@ -7042,7 +7042,7 @@ static void unthrottle_cfs_rq_async(struct cfs_rq *cfs_rq)
 {
 	lockdep_assert_rq_held(rq_of(cfs_rq));
 
-	if (WARN_ON_ONCE(!cfs_rq_throttled(cfs_rq) ||
+	if (SCHED_WARN_ON_ONCE(!cfs_rq_throttled(cfs_rq) ||
 	    cfs_rq->runtime_remaining <= 0))
 		return;
 
@@ -7083,7 +7083,7 @@ static bool distribute_cfs_runtime(struct cfs_bandwidth *cfs_b)
 		}
 
 		/* By the above checks, this should never be true */
-		WARN_ON_ONCE(cfs_rq->runtime_remaining > 0);
+		SCHED_WARN_ON_ONCE(cfs_rq->runtime_remaining > 0);
 
 		scoped_guard(raw_spinlock, &cfs_b->lock) {
 			runtime = -cfs_rq->runtime_remaining + 1;
@@ -7671,7 +7671,7 @@ static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
 	u64 vdelta;
 	u64 delta;
 
-	WARN_ON_ONCE(task_rq(p) != rq);
+	SCHED_WARN_ON_ONCE(task_rq(p) != rq);
 
 	if (rq->cfs.h_nr_queued <= 1)
 		return;
@@ -7794,8 +7794,8 @@ requeue_delayed_entity(struct sched_entity *se)
 	 * Because a delayed entity is one that is still on
 	 * the runqueue competing until elegibility.
 	 */
-	WARN_ON_ONCE(!se->sched_delayed);
-	WARN_ON_ONCE(!se->on_rq);
+	SCHED_WARN_ON_ONCE(!se->sched_delayed);
+	SCHED_WARN_ON_ONCE(!se->on_rq);
 
 	if (update_entity_lag(cfs_rq, se)) {
 		cfs_rq->nr_queued--;
@@ -8032,8 +8032,8 @@ static int dequeue_entities(struct rq *rq, struct sched_entity *se, int flags)
 		rq->next_balance = jiffies;
 
 	if (p && task_delayed) {
-		WARN_ON_ONCE(!task_sleep);
-		WARN_ON_ONCE(p->on_rq != 1);
+		SCHED_WARN_ON_ONCE(!task_sleep);
+		SCHED_WARN_ON_ONCE(p->on_rq != 1);
 
 		/*
 		 * Fix-up what block_task() skipped.
@@ -9709,7 +9709,7 @@ static void set_cpus_allowed_fair(struct task_struct *p, struct affinity_context
 static void set_next_buddy(struct sched_entity *se)
 {
 	for_each_sched_entity(se) {
-		if (WARN_ON_ONCE(!se->on_rq))
+		if (SCHED_WARN_ON_ONCE(!se->on_rq))
 			return;
 		if (se_is_idle(se))
 			return;
@@ -9756,7 +9756,7 @@ preempt_sync(struct rq *rq, int wake_flags,
 	 * WF_SYNC without WF_TTWU is not expected so warn if it happens even
 	 * though it is likely harmless.
 	 */
-	WARN_ON_ONCE(!(wake_flags & WF_TTWU));
+	SCHED_WARN_ON_ONCE(!(wake_flags & WF_TTWU));
 
 	threshold = sysctl_sched_migration_cost;
 	delta = rq_clock_task(rq) - se->exec_start;
@@ -9828,7 +9828,7 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f
 		return;
 
 	find_matching_se(&se, &pse);
-	WARN_ON_ONCE(!pse);
+	SCHED_WARN_ON_ONCE(!pse);
 
 	cse_is_idle = se_is_idle(se);
 	pse_is_idle = se_is_idle(pse);
@@ -10861,8 +10861,8 @@ static void detach_task(struct task_struct *p, struct lb_env *env)
 		schedstat_inc(p->stats.nr_forced_migrations);
 	}
 
-	WARN_ON(task_current(env->src_rq, p));
-	WARN_ON(task_current_donor(env->src_rq, p));
+	SCHED_WARN_ON(task_current(env->src_rq, p));
+	SCHED_WARN_ON(task_current_donor(env->src_rq, p));
 
 	deactivate_task(env->src_rq, p, DEQUEUE_NOCLOCK);
 	set_task_cpu(p, env->dst_cpu);
@@ -13334,7 +13334,7 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
 		goto out_balanced;
 	}
 
-	WARN_ON_ONCE(busiest == env.dst_rq);
+	SCHED_WARN_ON_ONCE(busiest == env.dst_rq);
 
 	update_lb_imbalance_stat(&env, sd, idle);
 
@@ -13651,7 +13651,7 @@ static int active_load_balance_cpu_stop(void *data)
 	 * we need to fix it. Originally reported by
 	 * Bjorn Helgaas on a 128-CPU setup.
 	 */
-	WARN_ON_ONCE(busiest_rq == target_rq);
+	SCHED_WARN_ON_ONCE(busiest_rq == target_rq);
 
 	/* Search for an sd spanning us and the target CPU. */
 	rcu_read_lock();
@@ -14802,7 +14802,7 @@ bool cfs_prio_less(const struct task_struct *a, const struct task_struct *b,
 	struct cfs_rq *cfs_rqb;
 	s64 delta;
 
-	WARN_ON_ONCE(task_rq(b)->core != rq->core);
+	SCHED_WARN_ON_ONCE(task_rq(b)->core != rq->core);
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
 	/*
@@ -15020,7 +15020,7 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p)
 
 static void switched_to_fair(struct rq *rq, struct task_struct *p)
 {
-	WARN_ON_ONCE(p->se.sched_delayed);
+	SCHED_WARN_ON_ONCE(p->se.sched_delayed);
 
 	attach_task_cfs_rq(p);
 
@@ -15077,7 +15077,7 @@ static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool first)
 	if (!first)
 		return;
 
-	WARN_ON_ONCE(se->sched_delayed);
+	SCHED_WARN_ON_ONCE(se->sched_delayed);
 
 	if (hrtick_enabled_fair(rq))
 		hrtick_start_fair(rq, p);
@@ -15311,7 +15311,7 @@ int sched_group_set_idle(struct task_group *tg, long idle)
 		rq_lock_irqsave(rq, &rf);
 
 		grp_cfs_rq->idle = idle;
-		if (WARN_ON_ONCE(was_idle == cfs_rq_is_idle(grp_cfs_rq)))
+		if (SCHED_WARN_ON_ONCE(was_idle == cfs_rq_is_idle(grp_cfs_rq)))
 			goto next_cpu;
 
 		idle_task_delta = grp_cfs_rq->h_nr_queued -
-- 
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 ` [PATCH 2/9] sched/core: defer WARN console output under rq->lock Rik van Riel
2026-06-11  2:14 ` Rik van Riel [this message]
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-4-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