Re: [PATCH 2/6] sched/numa: Leave the placement of a BPF-scheduled task to its scheduler

From: Peter Zijlstra

Date: Tue Oct 27 2026 - 06:48:00 EST


On Tue, Oct 27, 2026 at 05:13:31AM +0100, Andrea Righi wrote:
> A task under a BPF scheduler can take NUMA hinting faults via
> task_numa_fault() and then reach numa_migrate_preferred(), which may
> migrate the task to its preferred node through task_numa_migrate().
>
> The migration of such a task should always be driven by its BPF
> scheduler, which owns the placement of its tasks.
>
> Keep collecting the statistics, which is what makes
> p->numa_preferred_nid worth reading, but skip the migration for a task
> owned by a BPF scheduler. The scheduler can read the preferred node and
> decide for itself whether moving the task is worth the cost.
>
> For the same reason, never pick a task owned by a BPF scheduler as the
> swap partner of another task that NUMA balancing migrates, e.g., a fair
> task when the BPF scheduler runs in partial mode. Such a task is
> treated like a kthread on the destination CPU: the migrating task can
> still move there alone, but the BPF-scheduled task is left in place.
>
> Reported-by: Vladimir Vdovin <deliran@xxxxxxxxxx>
> Link: https://lore.kernel.org/r/20261002124559.10367-1-deliran@xxxxxxxxxx
> Signed-off-by: Andrea Righi <arighi@xxxxxxxxxx>
> ---
> kernel/sched/fair.c | 15 ++++++++++++++-
> 1 file changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index 36df9a4dde534..5064c7b707f4d 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -3267,8 +3267,13 @@ static bool task_numa_compare(struct task_numa_env *env,
>
> rcu_read_lock();
> cur = rcu_dereference_all(dst_rq->curr);
> + /*
> + * Never pick a task under a BPF scheduler as the swap partner: its
> + * placement is left to that scheduler, see numa_migrate_preferred().
> + * Moving the faulting task alone to the destination is still allowed.
> + */
> if (cur && ((cur->flags & (PF_EXITING | PF_KTHREAD)) ||
> - !cur->mm))
> + !cur->mm || task_on_scx(cur)))
> cur = NULL;

Rather than check task_on_scx(); your argument with Prateek seems to
highlight that the actual check you're looking for should be something
like: cur->class != &fair_sched_class or somesuch, right?

> /*
> @@ -3645,6 +3650,14 @@ static void numa_migrate_preferred(struct task_struct *p)
> if (task_node(p) == p->numa_preferred_nid)
> return;
>
> + /*
> + * A task under a BPF scheduler is placed by that scheduler. Keep the
> + * statistics coming, which is what makes p->numa_preferred_nid worth
> + * reading, but leave the placement alone.
> + */
> + if (task_on_scx(p))
> + return;
> +
> /* Otherwise, try migrate to a CPU on the preferred node */
> task_numa_migrate(p);
> }

I am somewhat confused on all this still, probably because I've not
looked at it for more than a couple of minutes at this point :-)

But rather than putting a callback in sched_setnuma() should you not put
a class call here?

That is; have this be:

p->class->task_numa_migrate(p);

and have fair set task_numa_migrate_fair(), which is the current
function, and then ext can implement the BPF thing.

Anyway, if you want to do this task_on_scx() thing like you did, its in
the wrong spot, that condition right above it is irrelevant if you're
not going to be calling task_numa_migrate().