mirror of
https://github.com/torvalds/linux.git
synced 2026-09-11 20:13:02 +02:00
sched_ext: Allow ops.cgroup_set_bandwidth() to be sleepable
ops.cgroup_set_bandwidth() is delivered from scx_group_set_bandwidth(), which runs from the cpu.max cgroup interface write path (tg_set_bandwidth()) in process context. scx_group_set_bandwidth() holds percpu_down_read(&scx_cgroup_ops_rwsem), whose read side may sleep. The call site is therefore sleepable, like ops.cgroup_init(). bpf_scx_check_member() rejects a sleepable program on any member not on its allow-list, so a BPF scheduler cannot allocate -- which is sleepable -- when a cgroup gains a cpu.max limit at runtime; it must instead pre-reserve memory for a callback that cannot allocate. Add cgroup_set_bandwidth() to the allow-list so the callback can allocate on demand, and document that it may block. A scheduler must decide at load time whether to mark the callback sleepable, but the allow-list entry is a verifier property with no symbol to probe. Add a compatibility marker whose presence in the kernel's BTF lets userspace detect this support: DEFINE_SCX_COMPAT_MARKER() emits an empty, callerless function, here scx_compat_marker_cgroup_set_bandwidth_may_sleep(). It is __used __retain so neither the compiler nor the linker (under CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) drops it. The markers share the scx_compat_marker_ prefix and are collected near the end of ext.c so more can be added as further capabilities appear. Signed-off-by: Changwoo Min <changwoo@igalia.com> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
parent
fab183d632
commit
5f01293930
|
|
@ -8079,6 +8079,7 @@ static int bpf_scx_check_member(const struct btf_type *t,
|
|||
case offsetof(struct sched_ext_ops, cgroup_init):
|
||||
case offsetof(struct sched_ext_ops, cgroup_exit):
|
||||
case offsetof(struct sched_ext_ops, cgroup_prep_move):
|
||||
case offsetof(struct sched_ext_ops, cgroup_set_bandwidth):
|
||||
#endif
|
||||
case offsetof(struct sched_ext_ops, cpu_online):
|
||||
case offsetof(struct sched_ext_ops, cpu_offline):
|
||||
|
|
@ -11041,3 +11042,16 @@ static int __init scx_init(void)
|
|||
return 0;
|
||||
}
|
||||
__initcall(scx_init);
|
||||
|
||||
/*
|
||||
* Compatibility markers for userspace. Existence of a marker function
|
||||
* represents that the kernel supports that sched-ext feature.
|
||||
*/
|
||||
|
||||
/*
|
||||
* scx_compat_marker_cgroup_set_bandwidth_may_sleep: advertises that
|
||||
* ops.cgroup_set_bandwidth() may be implemented as a sleepable callback.
|
||||
*/
|
||||
#ifdef CONFIG_EXT_GROUP_SCHED
|
||||
DEFINE_SCX_COMPAT_MARKER(cgroup_set_bandwidth_may_sleep);
|
||||
#endif /* CONFIG_EXT_GROUP_SCHED */
|
||||
|
|
|
|||
|
|
@ -753,7 +753,7 @@ struct sched_ext_ops {
|
|||
* @burst_us: bandwidth control burst
|
||||
*
|
||||
* Update @cgrp's bandwidth control parameters. This is from the cpu.max
|
||||
* cgroup interface.
|
||||
* cgroup interface. This operation may block.
|
||||
*
|
||||
* @quota_us / @period_us determines the CPU bandwidth @cgrp is entitled
|
||||
* to. For example, if @period_us is 1_000_000 and @quota_us is
|
||||
|
|
@ -2001,6 +2001,27 @@ struct scx_bstr_buf {
|
|||
char line[SCX_EXIT_MSG_LEN];
|
||||
};
|
||||
|
||||
/* Internal helper for DEFINE_SCX_COMPAT_MARKER(). */
|
||||
#define DECLARE_SCX_COMPAT_MARKER(func) \
|
||||
extern void scx_compat_marker_##func(void)
|
||||
|
||||
/**
|
||||
* DEFINE_SCX_COMPAT_MARKER() - define a userspace capability marker
|
||||
* @func: marker suffix; the defined symbol is scx_compat_marker_@func
|
||||
*
|
||||
* Emit an empty, callerless function that is retained in the kernel's BTF.
|
||||
* Its presence is part of the kernel<->userspace contract: userspace probes
|
||||
* scx_compat_marker_@func (e.g. via BTF) to detect that this kernel supports
|
||||
* the corresponding feature.
|
||||
*
|
||||
* The leading declaration suppresses the missing-prototype warning; the
|
||||
* trailing declaration consumes the semicolon at the use site.
|
||||
*/
|
||||
#define DEFINE_SCX_COMPAT_MARKER(func) \
|
||||
DECLARE_SCX_COMPAT_MARKER(func); \
|
||||
__used __retain void scx_compat_marker_##func(void) {} \
|
||||
DECLARE_SCX_COMPAT_MARKER(func)
|
||||
|
||||
extern struct scx_sched __rcu *scx_root;
|
||||
DECLARE_PER_CPU(struct rq *, scx_locked_rq_state);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user