Re: [RFC PATCH 14/16] sched/core: Introduce chain-wakeup to activate blocked donors

From: John Stultz

Date: Tue Sep 15 2026 - 01:56:03 EST


On Tue, Aug 25, 2026 at 11:34 PM K Prateek Nayak <kprateek.nayak@xxxxxxx> wrote:
> +static void
> +proxy_activate_blocked_task(struct rq *rq, struct task_struct *p, int en_flags)
> +{
> + int iowait_count = 0, load_contrib_count = 0;
> + struct task_struct *donor, *owner, *tmp;
> + int blocked_cpu, this_cpu = cpu_of(rq);
> + LIST_HEAD(migration_head);
> + LIST_HEAD(wakeup_head);
> + struct rq *blocked_rq;
> + bool needs_migration;
> +
> + WRITE_ONCE(p->on_rq, TASK_ON_RQ_MIGRATING);
> + ASSERT_EXCLUSIVE_WRITER(p->on_rq);
> +
> + /*
> + * Pairs against smp_mb() in proxy_enqueue_on_owner() which
> + * orders ownwer->on_rq state against the blocked_head addition.
> + */
> + smp_mb();
> +
> + /*
> + * Fast-path: Tasks blocking on us will see p->on_rq updated and
> + * will bail out natturally in proxy_enqueue_on_owner().
> + *
> + * proxy_enqueue_on_owner() holds the wait_lock to prevent owner
> + * from running and disappearing before the transient task can
> + * observe p->on_rq change and dequeue itself.
> + */
> + if (list_empty(&p->blocked_head)) {
> + __activate_task(rq, p, en_flags);
> + return;
> + }
> +
> + /*
> + * Slow-path: Since we need to wakeup tasks (and task queued on
> + * them, and task queued on them, and ... you get the gist) we
> + * need to grab some locks.
> + *
> + * Lucky for us, we have simplified this via p->blocked_cpu
> + * which is the task_cpu() for the entire chain. Wakeup is
> + * broken into two parts.
> + *
> + * Part1: Under the rq_lock + blocked lock, mark all tasks on
> + * the chain as TASK_ON_RQ_MIGRATING in breadth-first manner.
> + *
> + * Part2: Active all the tasks in bulk.
> + */
> +
> + /* Part 1: Prepare the blocked donor chain. */
> + blocked_cpu = p->blocked_cpu;
> + blocked_rq = cpu_rq(blocked_cpu);
> +
> + /*
> + * Blocked chain is linked to a different rq. Drop the rq_lock
> + * and migrate the chain over before wkaing it up here.
> + */
> + needs_migration = blocked_rq != rq;
> + if (needs_migration) {
> + raw_spin_rq_unlock(rq);
> + raw_spin_rq_lock(blocked_rq);
> + }

Hey Prateek!
My apologies for taking so long to get over to looking at this.
So, I'm still getting my head around this, but in running this series,
I'm hitting a lot of lockdep warnings here since we call
proxy_activate_blocked_task() with the rq lock pinned. This is why the
activate_blocked_waiters() in my patch is done outside the rq_lock.

Probably need to pass the rf as an argument to the function, then use
rq_unlock(rq, rf); there (and rq_lock(rq, rf) later)? That seems to
resolve it for me.

thanks
-john