Re: [PATCH v3] sched/fair: remove dead code on enqueue_task_fair()

From: Peter Zijlstra

Date: Tue Oct 13 2026 - 08:11:28 EST


On Mon, Oct 12, 2026 at 03:59:40PM +0100, Christian Loehle wrote:
> On 10/12/26 15:02, Peter Zijlstra wrote:

> > Anyway, this is different from the initial use-case, where a
> > sched_entity would get dequeue and re-enqueued while walking the cgroup
> > hierarchy, and thus had to appear like nothing happened in between.
> >
> > In this case we're fine to advance time.
> >
> > Anyway... the normal block/wakeup paths are >< close to also hitting
> > this in the case where balancing drops the rq->lock after dequeue. The
> > only reason ttwu can't tickle this is because it has that ->on_cpu
> > stuff. However, we cannot use that on the unthrottle path :/
> >
> > Bah.
> >
> > Does this work?
> >
> > diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> > index 5c98d8dfce5d..0edd8bfb6363 100644
> > --- a/kernel/sched/fair.c
> > +++ b/kernel/sched/fair.c
> > @@ -8250,7 +8250,14 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
> > weight = enqueue_hierarchy(p, flags);
> > reweight_eevdf(cfs_rq, se, weight, false);
> > place_entity(cfs_rq, se, flags | ENQUEUE_QUEUED);
> > - __enqueue_entity(cfs_rq, se);
> > +
> > + /*
> > + * This can actually happen with CFS_BANDWIDTH, in that case a task
> > + * can get throttled, dequeued and then unthrottled, woken *before* it
> > + * schedules out and does put_prev_task().
> > + */
> > + if (cfs_rq->curr != se)
> > + __enqueue_entity(cfs_rq, se);
> >
> > if (!rq_h_nr_queued && rq->cfs.h_nr_queued)
> > dl_server_start(&rq->fair_server);
>
> Tested-by: Christian Loehle <christian.loehle@xxxxxxx>
> for my reproducer, that being said, and indeed the failure is:
> throttle -> dequeue (not put_prev_task()'d yet) -> (from remote CPU) unthrottle -> enqueue()
>
> The dequeue()->enqueue() also lets place_entity()
> 'double-account' the entity's (on dequeue() saved) lag, right?
> After dequeue: curr == se, on_rq == 0 -> excl from average
> enqueue_hierarchy(): curr == se, on_rq == 1 -> incl again
> place_entity(): calculate placement assuming se is excl

I'm not entirely sure I follow. With the above fix there is still only
one place_entity(), which is after enqueue_hierarchy() and has
ENQUEUE_QUEUED on.

Here enqueue_hierarchy() adds the entity to h_nr_queued, and
ENQUEUE_QUEUED tells place_entity() exactly this, so it can adjust.