All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Tejun Heo" <tj@kernel.org>
Cc: sched-ext@lists.linux.dev
Subject: Re: [PATCH v3 sched_ext/for-7.3 35/36] tools/sched_ext: scx_qmap - Expand hierarchical sub-scheduling
Date: Tue, 07 Jul 2026 00:41:01 +0000	[thread overview]
Message-ID: <20260707004101.869821F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260707001229.1410929-36-tj@kernel.org>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] Newly acquired exclusive CPUs are not added to `idle_cids.mask` if they were already idle when ownership changed, leading to lost wakeups.
- [Medium] Tasks pinned exclusively to delegated CPUs will be permanently stranded in `SHARED_DSQ`.
- [Medium] `qmap_sub_attach` and `qmap_sub_detach` modify the `sub_sched_ctxs` array without synchronization, causing data races with timer-driven partition updates.
--

--- Patch [35]: [PATCH v3 sched_ext/for-7.3 35/36] tools/sched_ext: scx_qmap - Expand hierarchical sub-scheduling ---
commit 1fbc1bc9a944e2dd17d65dc96b81e16ff548c984
Author: Tejun Heo <tj@kernel.org>
Subject: tools/sched_ext: scx_qmap - Expand hierarchical sub-scheduling

This commit expands scx_qmap to demonstrate hierarchical sub-scheduling
features in sched_ext, allowing a parent scheduler to delegate CPU
capacities to child cgroup schedulers. The parent splits exclusive
capabilities among itself and children based on weight, with leftovers
forming a time-shared pool.

> diff --git a/tools/sched_ext/scx_qmap.bpf.c b/tools/sched_ext/scx_qmap.bpf.c
> index f6cfe63425d36..18afa975406de 100644
> --- a/tools/sched_ext/scx_qmap.bpf.c
> +++ b/tools/sched_ext/scx_qmap.bpf.c
[ ... ]
> @@ -567,12 +627,35 @@ void BPF_STRUCT_OPS(qmap_dispatch, s32 cid, struct task_struct *prev)
>  	struct cpu_ctx __arena *cpuc;
>  	task_ctx_t *taskc;
>  	u32 batch = dsp_batch ?: 1;
> +	s32 owner;
>  	s32 i;
>  
>  	if (dispatch_highpri(false))
>  		return;
>  
> -	if (!qa.nr_highpri_queued && scx_bpf_dsq_move_to_local(SHARED_DSQ, 0))
> +	/*
> +	 * Sub-sched routing: a child-owned cid goes to its owner. Never run
> +	 * this node's own tasks on a delegated cid. Read without the guard.
> +	 */
> +	owner = qa.part.cid_owner[cid];
> +	if (owner == CID_SHARED) {
> +		/* route to the live rr holder (0 = self, runs below) */
> +		s32 pos = qa.part.rr_pos;
> +		u64 holder_cgid = (pos >= 0 && pos < MAX_PARTS) ?
> +				  qa.part.rr_slots[pos] : 0;
> +
> +		if (holder_cgid) {
> +			scx_bpf_sub_dispatch(holder_cgid);
> +			return;
> +		}
> +	} else if (owner >= 0 && owner < MAX_SUB_SCHEDS &&
> +		   qa.sub_sched_ctxs[owner].cgroup_id) {
> +		if (scx_bpf_sub_dispatch(qa.sub_sched_ctxs[owner].cgroup_id))
> +			__sync_fetch_and_add(&qa.sub_sched_ctxs[owner].nr_dsps, 1);
> +		return;
> +	}

[Severity: Medium]
Could tasks pinned exclusively to delegated CPUs get permanently stranded on
SHARED_DSQ here?

If a task is pinned to a child's CPU mask, qmap_enqueue() nudges it to a
delegated CPU's local DSQ. Since the parent lacks the ENQ capability, the
kernel rejects it and re-enqueues it with SCX_ENQ_REENQ, placing it into
SHARED_DSQ.

However, when a delegated CPU executes qmap_dispatch(), it calls
scx_bpf_sub_dispatch() and returns immediately without ever pulling from
SHARED_DSQ. The parent's own CPUs cannot pull it because their cpus_allowed
mask does not match the task, which seems to leave the task stalled.

[ ... ]
> @@ -1065,6 +1149,486 @@ static int lowpri_timerfn(void *map, int *key, struct bpf_timer *timer)
[ ... ]
> +__noinline void apply_partition(void)
> +{
[ ... ]
> +	bpf_for(cid, 0, nr_cids) {
> +		s32 o = qa.part.cid_owner[cid];
> +
> +		if (cmask_test(cid, &qa.rr_cids.mask))
> +			continue;
> +		if (o >= 0 && o < MAX_SUB_SCHEDS)
> +			cmask_set(cid, &qa.sub_sched_ctxs[o].granted_cids.mask);
> +		else if (o == CID_SELF)
> +			cmask_set(cid, &qa.self_cids.mask);
> +	}

[Severity: Medium]
Does this miss adding newly acquired exclusive CPUs to idle_cids.mask if
they were already idle?

When a child scheduler is detached, its delegated CPUs are returned to
self_cids.mask by apply_partition(). If a returned CPU happens to be
physically idle at that moment, qmap_update_idle() is not re-triggered by
the kernel. Because qmap_update_idle() ignores idle transitions for CPUs not
currently in self_cids.mask, the CPU remains missing from idle_cids.mask.

Will this cause tasks queued in the BPF FIFOs to stall, since subsequent
enqueues will fail to pick the CPU via pick_direct_dispatch_cid() and won't
kick it?

[ ... ]
> @@ -1219,12 +1827,37 @@ void BPF_STRUCT_OPS(qmap_sub_detach, struct scx_sub_detach_args *args)
[ ... ]
>  	for (i = 0; i < MAX_SUB_SCHEDS; i++) {
> -		if (qa.sub_sched_cgroup_ids[i] == args->ops->sub_cgroup_id) {
> -			qa.sub_sched_cgroup_ids[i] = 0;
> -			bpf_printk("detaching sub-sched[%d] on %s",
> -				   i, args->cgroup_path);
> -			break;
> -		}
> +		if (qa.sub_sched_ctxs[i].cgroup_id != args->ops->sub_cgroup_id)
> +			continue;
> +
> +		qa.sub_sched_ctxs[i].cgroup_id = 0;
> +		qa.sub_sched_ctxs[i].weight = 100;
> +		cmask_init(&qa.sub_sched_ctxs[i].granted_cids.mask, 0, qa.nr_cids);
> +		qa.nr_sub_scheds--;
> +		bpf_printk("detaching sub-sched[%d] on %s", i, args->cgroup_path);
> +		redistribute();
> +		break;
>  	}
>  }

[Severity: Medium]
Is it safe to modify the sub_sched_ctxs array locklessly here?

The kernel calls qmap_sub_detach() when a child cgroup is removed, zeroing
out granted_cids.mask and updating cgroup_id. Concurrently, userspace can
trigger repartition() or a BPF timer can trigger rr_advance(), both of which
call apply_partition().

Since apply_partition() reads and sets bits in these same masks concurrently:

apply_partition() {
    ...
    if (o >= 0 && o < MAX_SUB_SCHEDS)
        cmask_set(cid, &qa.sub_sched_ctxs[o].granted_cids.mask);
    ...
}

Can this data race corrupt the internal state and lead to skipped capability
revocations or invalid scheduling structures?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260707001229.1410929-1-tj@kernel.org?part=35

  reply	other threads:[~2026-07-07  0:41 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-07  0:11 [PATCHSET v3 sched_ext/for-7.3] sched_ext: Capability-based CPU delegation for sub-schedulers Tejun Heo
2026-07-07  0:11 ` [PATCH v3 sched_ext/for-7.3 01/36] sched_ext: Add SCX_CALL_CID_OP_TASK() for cid-form op dispatch Tejun Heo
2026-07-07  0:11 ` [PATCH v3 sched_ext/for-7.3 02/36] sched_ext: Rename extra_enq_flags to remote_activate_enq_flags Tejun Heo
2026-07-07  0:11 ` [PATCH v3 sched_ext/for-7.3 03/36] sched_ext: Fix premature ops->priv publication in scx_alloc_and_add_sched() Tejun Heo
2026-07-07  0:11 ` [PATCH v3 sched_ext/for-7.3 04/36] tools/sched_ext: scx - Fix cmask_subset(), cmask_equal() and cmask_weight() Tejun Heo
2026-07-07  0:11 ` [PATCH v3 sched_ext/for-7.3 05/36] sched_ext: Use READ_ONCE/WRITE_ONCE in cmask word ops and drop _RACY variants Tejun Heo
2026-07-07  0:11 ` [PATCH v3 sched_ext/for-7.3 06/36] tools/sched_ext: scx_qmap - Use bare u64/u32/s32 integer types Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 07/36] sched_ext: Reject direct slice and dsq_vtime writes for cid-form schedulers Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 08/36] sched_ext: Make scx_bpf_kick_cid() return void Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 09/36] sched_ext: Make the kick machinery per-sched Tejun Heo
2026-07-07  0:33   ` sashiko-bot
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 10/36] sched_ext: Add ops.init_cids() to finalize the cid layout before init Tejun Heo
2026-07-07  0:36   ` sashiko-bot
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 11/36] sched_ext: Add CID sharding Tejun Heo
2026-07-07  0:30   ` sashiko-bot
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 12/36] sched_ext: Add shard boundaries to scx_bpf_cid_override() Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 13/36] sched_ext: Defer scx_sched kobj sysfs add into the enable workfns Tejun Heo
2026-07-07  0:31   ` sashiko-bot
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 14/36] sched_ext: Add per-shard scx_sched storage scaffolding Tejun Heo
2026-07-07  0:28   ` sashiko-bot
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 15/36] sched_ext: Add scx_cmask_ref for validated arena cmask access Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 16/36] sched_ext: Build the set_cmask scratch from trusted geometry Tejun Heo
2026-07-07  0:30   ` sashiko-bot
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 17/36] sched_ext: RCU-protect the sub-sched tree's children/sibling lists Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 18/36] sched_ext: Add scx_skip_subtree_pre() Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 19/36] sched_ext: Add per-shard cap delegation for sub-schedulers Tejun Heo
2026-07-07  0:39   ` sashiko-bot
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 20/36] sched_ext: Add coalescing sub_caps_updated() notifier " Tejun Heo
2026-07-07  0:33   ` sashiko-bot
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 21/36] sched_ext: Maintain per-cpu effective cap copies for single-read checks Tejun Heo
2026-07-07  0:38   ` sashiko-bot
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 22/36] sched_ext: Add sub_ecaps_updated() effective-cap change notifier Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 23/36] sched_ext: Generalize local-DSQ handling to rq-owned DSQs Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 24/36] sched_ext: Add reject DSQ for cap-rejected dispatches Tejun Heo
2026-07-07  0:38   ` sashiko-bot
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 25/36] sched_ext: Add the SCX_CAP_ENQ_IMMED cap Tejun Heo
2026-07-07  0:32   ` sashiko-bot
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 26/36] sched_ext: Assign a unique id to each scheduler instance Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 27/36] sched_ext: Route task slice writes through set_task_slice() Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 28/36] sched_ext: Tie cpu occupancy to SCX_CAP_BASE through the task slice Tejun Heo
2026-07-07  0:38   ` sashiko-bot
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 29/36] sched_ext: Add the SCX_CAP_ENQ cap Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 30/36] sched_ext: Gate kicks on SCX_CAP_BASE and preemption on SCX_CAP_PREEMPT Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 31/36] sched_ext: Authorize remote-move inserts against the placing scheduler Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 32/36] sched_ext: Route ops.update_idle() to sub-schedulers and re-notify owed scheds Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 33/36] sched_ext: Replay ecaps notifications suppressed by bypass Tejun Heo
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 34/36] sched_ext: Add scx_bpf_sub_kill() to evict a child sub-scheduler Tejun Heo
2026-07-07  0:42   ` sashiko-bot
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 35/36] tools/sched_ext: scx_qmap - Expand hierarchical sub-scheduling Tejun Heo
2026-07-07  0:41   ` sashiko-bot [this message]
2026-07-07  0:12 ` [PATCH v3 sched_ext/for-7.3 36/36] tools/sched_ext: scx_qmap - Add sub-sched cap fault injection Tejun Heo

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=20260707004101.869821F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=sched-ext@lists.linux.dev \
    --cc=tj@kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.