Sched_ext development
 help / color / mirror / Atom feed
* [PATCHSET v3 sched_ext/for-7.3] sched: Make proxy execution compatible with sched_ext
@ 2026-07-06  6:50 Andrea Righi
  2026-07-06  6:50 ` [PATCH 1/9] sched/core: Drop mutex locks before proxy rescheduling Andrea Righi
                   ` (8 more replies)
  0 siblings, 9 replies; 16+ messages in thread
From: Andrea Righi @ 2026-07-06  6:50 UTC (permalink / raw)
  To: Tejun Heo, David Vernet, Changwoo Min, John Stultz
  Cc: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
	Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
	Valentin Schneider, K Prateek Nayak, Christian Loehle, David Dai,
	Koba Ko, Aiqun Yu, Shuah Khan, sched-ext, linux-kernel

This series enables using proxy execution with sched_ext and is based on early
work by John Stultz [1].

Background
==========

Proxy execution (proxy-exec) lets a waiting task ("donor") donate its scheduling
context to a mutex owner, so the owner can run while the donor stays eligible on
the runqueue.

Currently, proxy execution and sched_ext are mutually exclusive at build time:
we can't enable CONFIG_SCHED_PROXY_EXEC=y and CONFIG_SCHED_CLASS_EXT=y in the
same kernel.

This restriction can be problematic for Linux distributions and for anyone who
wants to ship one kernel and choose features at runtime.

Why are they mutually exclusive?
================================

sched_ext schedulers drive dispatch through their own interfaces. A proxy-exec
handoff can run a task that the BPF scheduler never dispatched through that
path. sched_ext callbacks then observe a "current" task that does not match what
the BPF side considers running, so kfuncs and helper state can see an
inconsistent view of the executing task.

sched_ext also tracks runnable work through Dispatch Queues (DSQs) and BPF
chosen dispatch rules, while the core scheduler still maintains classic per-CPU
runqueues and pick paths. A proxy handoff can therefore switch the CPU to a task
that the BPF scheduler never inserted or ordered through its DSQ interface.

DSQ state, vtime, and "who is running" bookkeeping inside the BPF program can
then disagree with what the core actually executes, so helpers and kfuncs that
assume their dispatched task is current may observe stale or inconsistent state.

Design: supporting proxy execution with sched_ext
=================================================

Provide proxy execution in sched_ext as optional per-scheduler capability: a BPF
scheduler can set the ops flag SCX_OPS_ENQ_BLOCKED to keep mutex-blocked donors
runnable and receive them through ops.enqueue() with SCX_ENQ_BLOCKED set.

This flag requires an ops.enqueue() callback and gives BPF control over whether,
where, and in what order to dispatch each donor. The core then walks the
mutex-owner chain and, when needed, migrates the donor's scheduling context to
the owner's rq before executing the owner.

Without the SCX_OPS_ENQ_BLOCKED flag, mutex waiters block normally and do not
participate in proxy execution while owned by that scheduler.

The donor-to-owner handoff is modeled like a "function call" from the
scheduler's perspective. The donor remains the running scheduling entity
selected by BPF: its scheduling context, runtime and slice are consumed while
the core temporarily invokes the mutex owner's code to make the critical section
progress. It is not a scheduler-visible switch to the owner.

Accordingly, the donor remains the scheduling context presented to sched_ext,
while the mutex owner is treated solely as the execution context selected
internally by the core scheduler. Scheduling state is accounted against
rq->donor where appropriate, while rq->curr identifies the execution context.
The internal owner substitution does not generate synthetic sched_ext callbacks
for a task that BPF did not dispatch.

Scheduler ownership changes need special handling because a donor may already be
blocked when a root scheduler is enabled or when a task moves between root and
sub-schedulers. If the incoming scheduler does not set SCX_OPS_ENQ_BLOCKED, the
retained donor is removed from the runqueue and stays on the normal mutex wait
path. Otherwise it remains eligible for BPF admission.

The mutex owner's CPU can be queried from BPF using scx_bpf_task_proxy_cpu(p) or
scx_bpf_task_proxy_cid(p), with p being the mutex-blocked task. It's up to the
BPF scheduler to decide if and how to use this information. For example, a BPF
scheduler may inspect the task currently running at that location and request
preemption to expedite the proxy-execution handoff. Schedulers that decide to
not use this information can keep the donor on its current CPU/cid and let the
core perform the handoff.

scx_qmap has been modified with a -B option to enable queueing mutex-blocked
tasks for proxy execution.

A new kselftest (enq_blocked) is also introduced to validate proxy execution
with sched_ext. The test creates a three-task priority inversion on one CPU: a
low-priority owner (nice +19) holds a kernel mutex, a high-priority donor (nice
-20) blocks on it and a nice 0 contender competes for the CPU. The first donor
blocks before the BPF scheduler is attached, allowing the test to verify that
switching to a scheduler without SCX_OPS_ENQ_BLOCKED removes the retained donor
from the runqueue, while switching to one with the flag preserves it. Access to
the mutex is provided by a loadable kernel module built via TEST_GEN_MODS_DIR,
with the test responsible for its lifecycle.

Example kselftest run:

  $ sudo tools/testing/selftests/sched_ext/runner -t enq_blocked
  ===== START =====
  TEST: enq_blocked
  DESCRIPTION: Verify BPF-driven proxy donor admission
  OUTPUT:

  [SCX_OPS_ENQ_BLOCKED=disabled]
    proxy_exec=enabled
    owner_nice=19
    donor_nice=-20
    contender_nice=0
    mutex_hold_avg_ns=254084719 (254.084 ms, samples=10)
    mutex_wait_avg_ns=254095120 (254.095 ms, samples=10)
    nr_blocked_enqueues=0

  [SCX_OPS_ENQ_BLOCKED=enabled]
    proxy_exec=enabled
    owner_nice=19
    donor_nice=-20
    contender_nice=0
    mutex_hold_avg_ns=228884734 (228.884 ms, samples=10)
    mutex_wait_avg_ns=207903720 (207.903 ms, samples=10)
    nr_blocked_enqueues=51

  [delta: enabled - disabled]
    mutex_hold_delta_ns=-25199985 (-9.92%)
    mutex_wait_delta_ns=-46191400 (-18.18%)
  ok 1 enq_blocked #
  =====  END  =====


  =============================

  RESULTS:

  PASSED:  1
  SKIPPED: 0
  FAILED:  0

References
==========

[1] https://lore.kernel.org/all/20251206001451.1418225-1-jstultz@google.com

Git tree: git://git.kernel.org/pub/scm/linux/kernel/git/arighi/linux.git scx-proxy-exec

Changes in v3:
 - Dropped the core restrictions on proxy-migrating migration-disabled and
   single-CPU donors: proxy execution moves the scheduling context, not the
   task's execution context (Peter Zijlstra, K Prateek Nayak)
 - Dropped the sched_ext-specific put_prev_task()/set_next_task() exception and
   fixed ops.running()/ops.stopping() pairing inside sched_ext instead; track a
   real running transition even when either callback is absent (Peter Zijlstra)
 - Dropped the kf_tasks[] nesting and nested ops.runnable() patches from v2;
   extensive proxy-exec testing did not reproduce task-op re-entry, so retain
   the existing non-nesting invariant
 - Replaced scx_bpf_task_is_blocked() with SCX_ENQ_BLOCKED in ops.enqueue()
   flags
 - Expanded the curr/donor description to cover mixed scheduling classes and
   fixed local preemption to expire rq->donor's slice (Aiqun Maria Yu)
 - Allow inactive blocked donors to be placed on a remote local DSQ while
   preventing normal migration of an active rq donor (Aiqun Maria Yu)
 - Deactivate retained donors when ownership changes to a root or sub-scheduler
   without SCX_OPS_ENQ_BLOCKED, and extend the selftest to cover attaching a
   scheduler after the donor blocks (K Prateek Nayak)
 - Hardened remote DSQ consumption by rejecting active tasks and re-checking
   migration eligibility after locking the source rq; fall back to the global
   DSQ without treating an eligibility change during the lock handoff as a BPF
   scheduler error
 - scx_qmap has a command line option (-B) to enable blocked-donor queueing
 - Link to v2: https://lore.kernel.org/all/20260702171909.1994478-1-arighi@nvidia.com/

Changes in v2:
 - Rebased onto sched_ext/for-7.3 and adapted the series to the split
   sched_ext implementation and cid-form scheduler interfaces.
 - Replaced the global sched_proxy_exec_scx boot-time opt-in with the
   per-scheduler SCX_OPS_ENQ_BLOCKED capability, allowing BPF to control donor
   admission and ordering through ops.enqueue().
 - Added scx_bpf_task_is_blocked(), scx_bpf_task_proxy_cpu(), and
   scx_bpf_task_proxy_cid(); enforce CPU/cid API separation for cid-form
   schedulers.
 - Added proxy exec support to scx_qmap, including optional owner-cid steering,
   affinity validation, and fallback to the donor's current cid.
 - Added a kselftest with a kernel mutex test and a three-task priority
   inversion workload, test is executed with blocked task admission disabled and
   enabled, validates the behavior, and reports hold/wait-time deltas.
 - Link to v1: https://lore.kernel.org/all/20260506174639.535232-1-arighi@nvidia.com/

Andrea Righi (7):
      sched/core: Drop mutex locks before proxy rescheduling
      sched_ext: Fix TOCTOU race in consume_remote_task()
      sched_ext: Fix ops.running/stopping() pairing for proxy-exec donors
      sched_ext: Delegate proxy donor admission to BPF schedulers
      sched_ext: Add selftest for blocked donor admission
      sched_ext: scx_qmap: Add proxy execution support
      sched: Allow enabling proxy exec with sched_ext

John Stultz (2):
      sched_ext: Split curr|donor references properly
      sched_ext: Handle blocked donor migration with proxy execution

 include/linux/sched/ext.h                          |   2 +
 init/Kconfig                                       |   2 -
 kernel/sched/core.c                                |  68 +-
 kernel/sched/ext/ext.c                             | 245 ++++++-
 kernel/sched/ext/ext.h                             |   2 +
 kernel/sched/ext/internal.h                        |  25 +-
 kernel/sched/ext/sub.c                             |  12 +-
 kernel/sched/sched.h                               |   8 +
 tools/sched_ext/include/scx/common.bpf.h           |   2 +
 tools/sched_ext/include/scx/compat.bpf.h           |  18 +
 tools/sched_ext/include/scx/compat.h               |   1 +
 tools/sched_ext/include/scx/enum_defs.autogen.h    |   1 +
 tools/sched_ext/include/scx/enums.autogen.bpf.h    |   3 +
 tools/sched_ext/include/scx/enums.autogen.h        |   1 +
 tools/sched_ext/scx_qmap.bpf.c                     |  13 +
 tools/sched_ext/scx_qmap.c                         |   9 +-
 tools/testing/selftests/sched_ext/.gitignore       |   4 +
 tools/testing/selftests/sched_ext/Makefile         |   2 +
 tools/testing/selftests/sched_ext/config           |   2 +
 .../testing/selftests/sched_ext/enq_blocked.bpf.c  | 128 ++++
 tools/testing/selftests/sched_ext/enq_blocked.c    | 732 +++++++++++++++++++++
 tools/testing/selftests/sched_ext/enq_blocked.h    |  27 +
 .../selftests/sched_ext/test_modules/Makefile      |  13 +
 .../sched_ext/test_modules/scx_enq_blocked_test.c  | 193 ++++++
 24 files changed, 1464 insertions(+), 49 deletions(-)
 create mode 100644 tools/testing/selftests/sched_ext/enq_blocked.bpf.c
 create mode 100644 tools/testing/selftests/sched_ext/enq_blocked.c
 create mode 100644 tools/testing/selftests/sched_ext/enq_blocked.h
 create mode 100644 tools/testing/selftests/sched_ext/test_modules/Makefile
 create mode 100644 tools/testing/selftests/sched_ext/test_modules/scx_enq_blocked_test.c

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2026-07-06  8:46 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-06  6:50 [PATCHSET v3 sched_ext/for-7.3] sched: Make proxy execution compatible with sched_ext Andrea Righi
2026-07-06  6:50 ` [PATCH 1/9] sched/core: Drop mutex locks before proxy rescheduling Andrea Righi
2026-07-06  8:45   ` K Prateek Nayak
2026-07-06  6:50 ` [PATCH 2/9] sched_ext: Split curr|donor references properly Andrea Righi
2026-07-06  7:35   ` sashiko-bot
2026-07-06  6:50 ` [PATCH 3/9] sched_ext: Fix TOCTOU race in consume_remote_task() Andrea Righi
2026-07-06  7:24   ` sashiko-bot
2026-07-06  6:50 ` [PATCH 4/9] sched_ext: Handle blocked donor migration with proxy execution Andrea Righi
2026-07-06  7:21   ` sashiko-bot
2026-07-06  6:51 ` [PATCH 5/9] sched_ext: Fix ops.running/stopping() pairing for proxy-exec donors Andrea Righi
2026-07-06  6:51 ` [PATCH 6/9] sched_ext: Delegate proxy donor admission to BPF schedulers Andrea Righi
2026-07-06  7:36   ` sashiko-bot
2026-07-06  7:49   ` K Prateek Nayak
2026-07-06  6:51 ` [PATCH 7/9] sched_ext: Add selftest for blocked donor admission Andrea Righi
2026-07-06  6:51 ` [PATCH 8/9] sched_ext: scx_qmap: Add proxy execution support Andrea Righi
2026-07-06  6:51 ` [PATCH 9/9] sched: Allow enabling proxy exec with sched_ext Andrea Righi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox