mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: K Prateek Nayak <kprateek.nayak@amd.com>
To: Ingo Molnar <mingo@redhat.com>,
	Peter Zijlstra <peterz@infradead.org>,
	Juri Lelli <juri.lelli@redhat.com>,
	Vincent Guittot <vincent.guittot@linaro.org>,
	John Stultz <jstultz@google.com>, <linux-kernel@vger.kernel.org>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>,
	Valentin Schneider <vschneid@redhat.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	Ben Segall <bsegall@google.com>,
	Joel Fernandes <joelagnelf@nvidia.com>,
	Qais Yousef <qyousef@layalina.io>,
	Zimuzo Ezeozue <zezeozue@google.com>,
	Will Deacon <will@kernel.org>, Waiman Long <longman@redhat.com>,
	Boqun Feng <boqun.feng@gmail.com>,
	"Paul E. McKenney" <paulmck@kernel.org>,
	Metin Kaya <Metin.Kaya@arm.com>,
	Xuewen Yan <xuewen.yan94@gmail.com>,
	K Prateek Nayak <kprateek.nayak@amd.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	"Daniel Lezcano" <daniel.lezcano@linaro.org>,
	Suleiman Souhlal <suleiman@google.com>,
	kuyo chang <kuyo.chang@mediatek.com>, hupu <hupu.gm@gmail.com>,
	Vasily Gorbik <gor@linux.ibm.com>, <kernel-team@android.com>
Subject: [RFC PATCH 3/3] sched/core: Swap to lock owner for core-wide pick on core-cookie mismatch
Date: Fri, 17 Jul 2026 11:16:01 +0000	[thread overview]
Message-ID: <20260717111601.6017-4-kprateek.nayak@amd.com> (raw)
In-Reply-To: <20260717111601.6017-1-kprateek.nayak@amd.com>

Proxy donor can have a different core cookie compared to the lock owner.
Simply running a lock owner with a mismatched core-cookie in not an
option as this breaks the core scheduling guarantees.

To prevent a cookie mismatch, use the "rq->core_pick_leader" indicator
to know if the CPU with the blocked donor is the one with the highest
priority task. If the rq contains the highest priority task, it is
that rq's pick which dictates the core-cookie.

Once the find_proxy_task() chain stabilizes on the rq (find_proxy_task()
returns the valid lock owner queued on the same rq), set a second
"rq->core_pick_blocked_donor" and retry the pick.

The flattened flow looks as follows:

  donor = pick_next_task()
    rq_set_donor(rq, donor)

  if (donor->is_blocked)
     next = find_proxy_task()

  /*
   * next has a different cookie compared to doner and
   * rq->core_pick_leader is set.
   */
  sched_core_swap_task()
    rq->core_pick_blocked_donor = 1; /* rq->donor was the last pick */
    return RETRY_TASK;

  pick_next_task()
    donor = rq->donor;
    owner = NULL;

    if (rq->core_pick_blocked_donor)
      owner = find_proxy_task(donor);
      goto restart_multi;

    /*
     * Finish the core-pick and validate that this rq
     * is still the pick leaader.
     */
    if (rq->core_pick_blocked_donor &&
        rq->core_pick_leader &&
        rq->core_pick == donor)
      rq->core_pick = owner; /* Swapped donor with owner. */

    rq->core->coore_cookie = rq->core_pick->cookie; /* owner cookie */

    /* Continue with the rest */

    return rq->core_pick; /* Owner */

    if (sched_core_retain_donor(rq))
       rq->sched_core_proxy_pick = 0 /* Consume */

Since the owner is not blocked, it continues to run and rq->donor is
preserved while the "rq->core_pick_blocked_donor" gets consumed.

Signed-off-by: K Prateek Nayak <kprateek.nayak@amd.com>
---
 kernel/sched/core.c  | 81 +++++++++++++++++++++++++++++++++++++++-----
 kernel/sched/sched.h |  1 +
 2 files changed, 74 insertions(+), 8 deletions(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index ed11410f1416..ab3b3104cd86 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -6598,7 +6598,8 @@ __pick_next_task(struct rq *rq, struct rq_flags *rf)
 	BUG(); /* The idle class should always have a runnable task. */
 }
 
-static void proxy_deactivate(struct rq *rq, struct task_struct *donor);
+static struct task_struct *
+find_proxy_task(struct rq *rq, struct task_struct *donor, struct rq_flags *rf);
 
 #ifdef CONFIG_SCHED_CORE
 static inline bool is_task_rq_idle(struct task_struct *t)
@@ -6643,10 +6644,16 @@ extern void task_vruntime_update(struct rq *rq, struct task_struct *p, bool in_f
 
 static void queue_core_balance(struct rq *rq);
 
+static __always_inline bool sched_core_proxy_pick(struct rq *rq)
+{
+	return sched_proxy_exec() && unlikely(rq->core_pick_blocked_donor);
+}
+
 static struct task_struct *
 pick_next_task(struct rq *rq, struct rq_flags *rf)
 	__must_hold(__rq_lockp(rq))
 {
+	struct task_struct *owner = NULL, *donor = rq->donor;
 	struct task_struct *next, *p, *max;
 	const struct cpumask *smt_mask;
 	bool fi_before = false;
@@ -6728,6 +6735,24 @@ pick_next_task(struct rq *rq, struct rq_flags *rf)
 	 */
 	rq->core->core_task_seq++;
 
+	/* Last core_pick resolved to a blocked_donor! */
+	if (sched_core_proxy_pick(rq)) {
+		WARN_ON_ONCE(!donor->is_blocked);
+
+		donor->blocked_donor = NULL;
+		owner = find_proxy_task(rq, donor, rf);
+		if (owner && owner != rq->idle)
+			goto restart_multi;
+		/*
+		 * Something changed in the proxy chain!
+		 * Retry pick like normal. Increment core_task_seq
+		 * since the core-wide lock might have been dropped
+		 * during proxy-migration in find_proxy_task().
+		 */
+		rq->core_pick_blocked_donor = false;
+		rq->core->core_task_seq++;
+	}
+
 	/*
 	 * Optimize for common case where this CPU has no cookies
 	 * and there are no cookied tasks running on siblings.
@@ -6786,6 +6811,21 @@ pick_next_task(struct rq *rq, struct rq_flags *rf)
 	}
 
 	rq_max->core_pick_leader = true;
+
+	if (sched_core_proxy_pick(rq)) {
+		WARN_ON_ONCE(!owner);
+
+		/*
+		 * Core-wide pick resolved to the same state as last time.
+		 * Swap the donor with the lock owner and continue the
+		 * rest of the pick sequence.
+		 */
+		if (rq->core_pick_leader && rq->core_pick == donor) {
+			rq_max->core_pick = owner;
+			max = owner;
+		}
+	}
+
 	cookie = rq->core->core_cookie = max->core_cookie;
 
 	/*
@@ -6883,9 +6923,16 @@ pick_next_task(struct rq *rq, struct rq_flags *rf)
 	}
 
 out_set_next:
-	put_prev_set_next_task(rq, rq->donor, next);
-	if (rq->core->core_forceidle_count && next == rq->idle)
-		queue_core_balance(rq);
+	/*
+	 * If this is a redo for setting the owner's core-cookie,
+	 * put_prev_set_next_task() was already done during the
+	 * last pick and there is nothing to do now.
+	 */
+	if (!sched_core_proxy_pick(rq)) {
+		put_prev_set_next_task(rq, rq->donor, next);
+		if (rq->core->core_forceidle_count && next == rq->idle)
+			queue_core_balance(rq);
+	}
 
 	return next;
 }
@@ -7114,11 +7161,21 @@ sched_core_swap_pick(struct rq *rq, struct task_struct *next)
 		return rq->idle;
 	}
 
-	clear_task_blocked_on(rq->donor, NULL);
-	proxy_deactivate(rq, rq->donor);
+	rq->core_pick_blocked_donor = true;
 	return RETRY_TASK;
 }
 
+static bool sched_core_retain_donor(struct rq *rq)
+{
+	bool retain = rq->core_pick_blocked_donor;
+
+	if (!sched_core_enabled(rq))
+		return false;
+
+	rq->core_pick_blocked_donor = false;
+	return retain;
+}
+
 #else /* !CONFIG_SCHED_CORE: */
 
 static inline void sched_core_cpu_starting(unsigned int cpu) {}
@@ -7144,6 +7201,11 @@ sched_core_swap_pick(struct rq *rq, struct task_struct *next)
 	return next;
 }
 
+static bool sched_core_retain_donor(struct rq *rq)
+{
+	return false;
+}
+
 #endif /* !CONFIG_SCHED_CORE */
 
 /*
@@ -7694,8 +7756,11 @@ static void __sched notrace __schedule(int sched_mode)
 	if (sched_proxy_exec()) {
 		struct task_struct *prev_donor = rq->donor;
 
-		rq_set_donor(rq, next);
-		next->blocked_donor = NULL;
+		if (!sched_core_retain_donor(rq)) {
+			rq_set_donor(rq, next);
+			next->blocked_donor = NULL;
+		}
+
 		if (unlikely(next->is_blocked)) {
 			next = find_proxy_task(rq, next, &rf);
 			if (!next) {
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index b80a5eb384f0..541b2ae673d8 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1352,6 +1352,7 @@ struct rq {
 
 	/* private state for sched_proxy_exec()  */
 	bool			core_pick_leader;
+	bool			core_pick_blocked_donor;
 
 	/* shared state -- careful with sched_core_cpu_deactivate() */
 	unsigned int		core_task_seq;
-- 
2.43.0


  parent reply	other threads:[~2026-07-17 11:17 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-01 21:45 [PATCH v30 0/7] Sleeping Owner Handling for Proxy Execution (v30) John Stultz
2026-07-01 21:45 ` [PATCH v30 1/7] sched/core: Don't steal a proxy-exec donor John Stultz
2026-07-01 21:45 ` [PATCH v30 2/7] sched/core: Avoid migrating blocked_on tasks John Stultz
2026-07-01 21:45 ` [PATCH v30 3/7] sched/core: Don't proxy-exec unmatched cookie lock owners John Stultz
2026-07-02  5:13   ` K Prateek Nayak
2026-07-02  9:14     ` Peter Zijlstra
2026-07-08  5:00     ` John Stultz
2026-07-10  3:13       ` K Prateek Nayak
2026-07-10  3:32         ` John Stultz
2026-07-17 11:15           ` [RFC PATCH 0/3] sched/core: Allow proxy execution to work with core scheduling K Prateek Nayak
2026-07-17 11:15             ` [RFC PATCH 1/3] sched/core: Track the core-wide pick leader K Prateek Nayak
2026-07-17 11:16             ` [RFC PATCH 2/3] sched/core: Fix forceidle when lock owner has mismatchd cookie K Prateek Nayak
2026-07-17 11:16             ` K Prateek Nayak [this message]
2026-07-01 21:45 ` [PATCH v30 4/7] sched: Switch rq->next_class in proxy_reset_donor() John Stultz
2026-07-01 21:46 ` [PATCH v30 5/7] sched: Break out core of attach_tasks() helper into sched.h John Stultz
2026-07-01 21:46 ` [PATCH v30 6/7] sched: Migrate whole chain in proxy_migrate_task() John Stultz
2026-07-01 21:46 ` [PATCH v30 7/7] sched: Add deactivated (sleeping) owner handling to find_proxy_task() John Stultz
2026-07-03  3:06   ` K Prateek Nayak
2026-07-08  4:34     ` John Stultz
2026-07-10  4:03       ` K Prateek Nayak
2026-07-10  4:56         ` John Stultz

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=20260717111601.6017-4-kprateek.nayak@amd.com \
    --to=kprateek.nayak@amd.com \
    --cc=Metin.Kaya@arm.com \
    --cc=boqun.feng@gmail.com \
    --cc=bsegall@google.com \
    --cc=daniel.lezcano@linaro.org \
    --cc=dietmar.eggemann@arm.com \
    --cc=gor@linux.ibm.com \
    --cc=hupu.gm@gmail.com \
    --cc=joelagnelf@nvidia.com \
    --cc=jstultz@google.com \
    --cc=juri.lelli@redhat.com \
    --cc=kernel-team@android.com \
    --cc=kuyo.chang@mediatek.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=longman@redhat.com \
    --cc=mingo@redhat.com \
    --cc=paulmck@kernel.org \
    --cc=peterz@infradead.org \
    --cc=qyousef@layalina.io \
    --cc=rostedt@goodmis.org \
    --cc=suleiman@google.com \
    --cc=tglx@linutronix.de \
    --cc=vincent.guittot@linaro.org \
    --cc=vschneid@redhat.com \
    --cc=will@kernel.org \
    --cc=xuewen.yan94@gmail.com \
    --cc=zezeozue@google.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