return -(long)jiffies_to_msecs(now - at);
}
-/* if the highest set bit is N, return a mask with bits [N+1, 31] set */
-static u32 higher_bits(u32 flags)
-{
- return ~((1 << fls(flags)) - 1);
-}
-
-/* return the mask with only the highest bit set */
-static u32 highest_bit(u32 flags)
-{
- int bit = fls(flags);
- return ((u64)1 << bit) >> 1;
-}
-
static bool u32_before(u32 a, u32 b)
{
return (s32)(a - b) < 0;
return false;
}
-/*
- * scx_kf_mask enforcement. Some kfuncs can only be called from specific SCX
- * ops. When invoking SCX ops, SCX_CALL_OP[_RET]() should be used to indicate
- * the allowed kfuncs and those kfuncs should use scx_kf_allowed() to check
- * whether it's running from an allowed context.
- *
- * @mask is constant, always inline to cull the mask calculations.
- */
-static __always_inline void scx_kf_allow(u32 mask)
-{
- /* nesting is allowed only in increasing scx_kf_mask order */
- WARN_ONCE((mask | higher_bits(mask)) & current->scx.kf_mask,
- "invalid nesting current->scx.kf_mask=0x%x mask=0x%x\n",
- current->scx.kf_mask, mask);
- current->scx.kf_mask |= mask;
- barrier();
-}
-
-static void scx_kf_disallow(u32 mask)
-{
- barrier();
- current->scx.kf_mask &= ~mask;
-}
-
/*
* Track the rq currently locked.
*
__this_cpu_write(scx_locked_rq_state, rq);
}
-#define SCX_CALL_OP(sch, mask, op, rq, args...) \
+#define SCX_CALL_OP(sch, op, rq, args...) \
do { \
if (rq) \
update_locked_rq(rq); \
- if (mask) { \
- scx_kf_allow(mask); \
- (sch)->ops.op(args); \
- scx_kf_disallow(mask); \
- } else { \
- (sch)->ops.op(args); \
- } \
+ (sch)->ops.op(args); \
if (rq) \
update_locked_rq(NULL); \
} while (0)
-#define SCX_CALL_OP_RET(sch, mask, op, rq, args...) \
+#define SCX_CALL_OP_RET(sch, op, rq, args...) \
({ \
__typeof__((sch)->ops.op(args)) __ret; \
\
if (rq) \
update_locked_rq(rq); \
- if (mask) { \
- scx_kf_allow(mask); \
- __ret = (sch)->ops.op(args); \
- scx_kf_disallow(mask); \
- } else { \
- __ret = (sch)->ops.op(args); \
- } \
+ __ret = (sch)->ops.op(args); \
if (rq) \
update_locked_rq(NULL); \
__ret; \
*
* These macros only work for non-nesting ops since kf_tasks[] is not stacked.
*/
-#define SCX_CALL_OP_TASK(sch, mask, op, rq, task, args...) \
+#define SCX_CALL_OP_TASK(sch, op, rq, task, args...) \
do { \
- BUILD_BUG_ON((mask) & ~__SCX_KF_TERMINAL); \
current->scx.kf_tasks[0] = task; \
- SCX_CALL_OP((sch), mask, op, rq, task, ##args); \
+ SCX_CALL_OP((sch), op, rq, task, ##args); \
current->scx.kf_tasks[0] = NULL; \
} while (0)
-#define SCX_CALL_OP_TASK_RET(sch, mask, op, rq, task, args...) \
+#define SCX_CALL_OP_TASK_RET(sch, op, rq, task, args...) \
({ \
__typeof__((sch)->ops.op(task, ##args)) __ret; \
- BUILD_BUG_ON((mask) & ~__SCX_KF_TERMINAL); \
current->scx.kf_tasks[0] = task; \
- __ret = SCX_CALL_OP_RET((sch), mask, op, rq, task, ##args); \
+ __ret = SCX_CALL_OP_RET((sch), op, rq, task, ##args); \
current->scx.kf_tasks[0] = NULL; \
__ret; \
})
-#define SCX_CALL_OP_2TASKS_RET(sch, mask, op, rq, task0, task1, args...) \
+#define SCX_CALL_OP_2TASKS_RET(sch, op, rq, task0, task1, args...) \
({ \
__typeof__((sch)->ops.op(task0, task1, ##args)) __ret; \
- BUILD_BUG_ON((mask) & ~__SCX_KF_TERMINAL); \
current->scx.kf_tasks[0] = task0; \
current->scx.kf_tasks[1] = task1; \
- __ret = SCX_CALL_OP_RET((sch), mask, op, rq, task0, task1, ##args); \
+ __ret = SCX_CALL_OP_RET((sch), op, rq, task0, task1, ##args); \
current->scx.kf_tasks[0] = NULL; \
current->scx.kf_tasks[1] = NULL; \
__ret; \
})
-/* @mask is constant, always inline to cull unnecessary branches */
-static __always_inline bool scx_kf_allowed(struct scx_sched *sch, u32 mask)
-{
- if (unlikely(!(current->scx.kf_mask & mask))) {
- scx_error(sch, "kfunc with mask 0x%x called from an operation only allowing 0x%x",
- mask, current->scx.kf_mask);
- return false;
- }
-
- /*
- * Enforce nesting boundaries. e.g. A kfunc which can be called from
- * DISPATCH must not be called if we're running DEQUEUE which is nested
- * inside ops.dispatch(). We don't need to check boundaries for any
- * blocking kfuncs as the verifier ensures they're only called from
- * sleepable progs.
- */
- if (unlikely(highest_bit(mask) == SCX_KF_CPU_RELEASE &&
- (current->scx.kf_mask & higher_bits(SCX_KF_CPU_RELEASE)))) {
- scx_error(sch, "cpu_release kfunc called from a nested operation");
- return false;
- }
-
- if (unlikely(highest_bit(mask) == SCX_KF_DISPATCH &&
- (current->scx.kf_mask & higher_bits(SCX_KF_DISPATCH)))) {
- scx_error(sch, "dispatch kfunc called from a nested operation");
- return false;
- }
-
- return true;
-}
-
/* see SCX_CALL_OP_TASK() */
static __always_inline bool scx_kf_allowed_on_arg_tasks(struct scx_sched *sch,
struct task_struct *p)
return;
if (SCX_HAS_OP(sch, dequeue))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, dequeue, rq, p, deq_flags);
+ SCX_CALL_OP_TASK(sch, dequeue, rq, p, deq_flags);
p->scx.flags &= ~SCX_TASK_IN_CUSTODY;
}
WARN_ON_ONCE(*ddsp_taskp);
*ddsp_taskp = p;
- SCX_CALL_OP_TASK(sch, SCX_KF_ENQUEUE, enqueue, rq, p, enq_flags);
+ SCX_CALL_OP_TASK(sch, enqueue, rq, p, enq_flags);
*ddsp_taskp = NULL;
if (p->scx.ddsp_dsq_id != SCX_DSQ_INVALID)
add_nr_running(rq, 1);
if (SCX_HAS_OP(sch, runnable) && !task_on_rq_migrating(p))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, runnable, rq, p, enq_flags);
+ SCX_CALL_OP_TASK(sch, runnable, rq, p, enq_flags);
if (enq_flags & SCX_ENQ_WAKEUP)
touch_core_sched(rq, p);
*/
if (SCX_HAS_OP(sch, stopping) && task_current(rq, p)) {
update_curr_scx(rq);
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, stopping, rq, p, false);
+ SCX_CALL_OP_TASK(sch, stopping, rq, p, false);
}
if (SCX_HAS_OP(sch, quiescent) && !task_on_rq_migrating(p))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, quiescent, rq, p, deq_flags);
+ SCX_CALL_OP_TASK(sch, quiescent, rq, p, deq_flags);
if (deq_flags & SCX_DEQ_SLEEP)
p->scx.flags |= SCX_TASK_DEQD_FOR_SLEEP;
struct scx_sched *sch = scx_task_sched(p);
if (SCX_HAS_OP(sch, yield))
- SCX_CALL_OP_2TASKS_RET(sch, SCX_KF_REST, yield, rq, p, NULL);
+ SCX_CALL_OP_2TASKS_RET(sch, yield, rq, p, NULL);
else
p->scx.slice = 0;
}
struct scx_sched *sch = scx_task_sched(from);
if (SCX_HAS_OP(sch, yield) && sch == scx_task_sched(to))
- return SCX_CALL_OP_2TASKS_RET(sch, SCX_KF_REST, yield, rq,
- from, to);
+ return SCX_CALL_OP_2TASKS_RET(sch, yield, rq, from, to);
else
return false;
}
dspc->nr_tasks = 0;
if (nested) {
- /*
- * If nested, don't update kf_mask as the originating
- * invocation would already have set it up.
- */
- SCX_CALL_OP(sch, 0, dispatch, rq, cpu,
- prev_on_sch ? prev : NULL);
+ SCX_CALL_OP(sch, dispatch, rq, cpu, prev_on_sch ? prev : NULL);
} else {
- /*
- * If not nested, stash @prev so that nested invocations
- * can access it.
- */
+ /* stash @prev so that nested invocations can access it */
rq->scx.sub_dispatch_prev = prev;
- SCX_CALL_OP(sch, SCX_KF_DISPATCH, dispatch, rq, cpu,
- prev_on_sch ? prev : NULL);
+ SCX_CALL_OP(sch, dispatch, rq, cpu, prev_on_sch ? prev : NULL);
rq->scx.sub_dispatch_prev = NULL;
}
* emitted in switch_class().
*/
if (SCX_HAS_OP(sch, cpu_acquire))
- SCX_CALL_OP(sch, SCX_KF_REST, cpu_acquire, rq, cpu, NULL);
+ SCX_CALL_OP(sch, cpu_acquire, rq, cpu, NULL);
rq->scx.cpu_released = false;
}
/* see dequeue_task_scx() on why we skip when !QUEUED */
if (SCX_HAS_OP(sch, running) && (p->scx.flags & SCX_TASK_QUEUED))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, running, rq, p);
+ SCX_CALL_OP_TASK(sch, running, rq, p);
clr_task_runnable(p, true);
.task = next,
};
- SCX_CALL_OP(sch, SCX_KF_CPU_RELEASE, cpu_release, rq,
- cpu_of(rq), &args);
+ SCX_CALL_OP(sch, cpu_release, rq, cpu_of(rq), &args);
}
rq->scx.cpu_released = true;
}
/* see dequeue_task_scx() on why we skip when !QUEUED */
if (SCX_HAS_OP(sch, stopping) && (p->scx.flags & SCX_TASK_QUEUED))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, stopping, rq, p, true);
+ SCX_CALL_OP_TASK(sch, stopping, rq, p, true);
if (p->scx.flags & SCX_TASK_QUEUED) {
set_task_runnable(rq, p);
*/
if (sch_a == sch_b && SCX_HAS_OP(sch_a, core_sched_before) &&
!scx_bypassing(sch_a, task_cpu(a)))
- return SCX_CALL_OP_2TASKS_RET(sch_a, SCX_KF_REST, core_sched_before,
+ return SCX_CALL_OP_2TASKS_RET(sch_a, core_sched_before,
NULL,
(struct task_struct *)a,
(struct task_struct *)b);
*ddsp_taskp = p;
this_rq()->scx.in_select_cpu = true;
- cpu = SCX_CALL_OP_TASK_RET(sch,
- SCX_KF_ENQUEUE | SCX_KF_SELECT_CPU,
- select_cpu, NULL, p, prev_cpu,
- wake_flags);
+ cpu = SCX_CALL_OP_TASK_RET(sch, select_cpu, NULL, p, prev_cpu, wake_flags);
this_rq()->scx.in_select_cpu = false;
p->scx.selected_cpu = cpu;
*ddsp_taskp = NULL;
* designation pointless. Cast it away when calling the operation.
*/
if (SCX_HAS_OP(sch, set_cpumask))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, set_cpumask, task_rq(p),
- p, (struct cpumask *)p->cpus_ptr);
+ SCX_CALL_OP_TASK(sch, set_cpumask, task_rq(p), p, (struct cpumask *)p->cpus_ptr);
}
static void handle_hotplug(struct rq *rq, bool online)
scx_idle_update_selcpu_topology(&sch->ops);
if (online && SCX_HAS_OP(sch, cpu_online))
- SCX_CALL_OP(sch, SCX_KF_UNLOCKED, cpu_online, NULL, cpu);
+ SCX_CALL_OP(sch, cpu_online, NULL, cpu);
else if (!online && SCX_HAS_OP(sch, cpu_offline))
- SCX_CALL_OP(sch, SCX_KF_UNLOCKED, cpu_offline, NULL, cpu);
+ SCX_CALL_OP(sch, cpu_offline, NULL, cpu);
else
scx_exit(sch, SCX_EXIT_UNREG_KERN,
SCX_ECODE_ACT_RESTART | SCX_ECODE_RSN_HOTPLUG,
curr->scx.slice = 0;
touch_core_sched(rq, curr);
} else if (SCX_HAS_OP(sch, tick)) {
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, tick, rq, curr);
+ SCX_CALL_OP_TASK(sch, tick, rq, curr);
}
if (!curr->scx.slice)
.fork = fork,
};
- ret = SCX_CALL_OP_RET(sch, SCX_KF_UNLOCKED, init_task, NULL,
- p, &args);
+ ret = SCX_CALL_OP_RET(sch, init_task, NULL, p, &args);
if (unlikely(ret)) {
ret = ops_sanitize_err(sch, "init_task", ret);
return ret;
p->scx.weight = sched_weight_to_cgroup(weight);
if (SCX_HAS_OP(sch, enable))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, enable, rq, p);
+ SCX_CALL_OP_TASK(sch, enable, rq, p);
if (SCX_HAS_OP(sch, set_weight))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, set_weight, rq,
- p, p->scx.weight);
+ SCX_CALL_OP_TASK(sch, set_weight, rq, p, p->scx.weight);
}
static void scx_enable_task(struct scx_sched *sch, struct task_struct *p)
clear_direct_dispatch(p);
if (SCX_HAS_OP(sch, disable))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, disable, rq, p);
+ SCX_CALL_OP_TASK(sch, disable, rq, p);
scx_set_task_state(p, SCX_TASK_READY);
/*
}
if (SCX_HAS_OP(sch, exit_task))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, exit_task, task_rq(p),
- p, &args);
+ SCX_CALL_OP_TASK(sch, exit_task, task_rq(p), p, &args);
}
static void scx_disable_and_exit_task(struct scx_sched *sch,
p->scx.weight = sched_weight_to_cgroup(scale_load_down(lw->weight));
if (SCX_HAS_OP(sch, set_weight))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, set_weight, rq,
- p, p->scx.weight);
+ SCX_CALL_OP_TASK(sch, set_weight, rq, p, p->scx.weight);
}
static void prio_changed_scx(struct rq *rq, struct task_struct *p, u64 oldprio)
* different scheduler class. Keep the BPF scheduler up-to-date.
*/
if (SCX_HAS_OP(sch, set_cpumask))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, set_cpumask, rq,
- p, (struct cpumask *)p->cpus_ptr);
+ SCX_CALL_OP_TASK(sch, set_cpumask, rq, p, (struct cpumask *)p->cpus_ptr);
}
static void switched_from_scx(struct rq *rq, struct task_struct *p)
.bw_quota_us = tg->scx.bw_quota_us,
.bw_burst_us = tg->scx.bw_burst_us };
- ret = SCX_CALL_OP_RET(sch, SCX_KF_UNLOCKED, cgroup_init,
+ ret = SCX_CALL_OP_RET(sch, cgroup_init,
NULL, tg->css.cgroup, &args);
if (ret)
ret = ops_sanitize_err(sch, "cgroup_init", ret);
if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_exit) &&
(tg->scx.flags & SCX_TG_INITED))
- SCX_CALL_OP(sch, SCX_KF_UNLOCKED, cgroup_exit, NULL,
- tg->css.cgroup);
+ SCX_CALL_OP(sch, cgroup_exit, NULL, tg->css.cgroup);
tg->scx.flags &= ~(SCX_TG_ONLINE | SCX_TG_INITED);
}
continue;
if (SCX_HAS_OP(sch, cgroup_prep_move)) {
- ret = SCX_CALL_OP_RET(sch, SCX_KF_UNLOCKED,
- cgroup_prep_move, NULL,
+ ret = SCX_CALL_OP_RET(sch, cgroup_prep_move, NULL,
p, from, css->cgroup);
if (ret)
goto err;
cgroup_taskset_for_each(p, css, tset) {
if (SCX_HAS_OP(sch, cgroup_cancel_move) &&
p->scx.cgrp_moving_from)
- SCX_CALL_OP(sch, SCX_KF_UNLOCKED, cgroup_cancel_move, NULL,
+ SCX_CALL_OP(sch, cgroup_cancel_move, NULL,
p, p->scx.cgrp_moving_from, css->cgroup);
p->scx.cgrp_moving_from = NULL;
}
*/
if (SCX_HAS_OP(sch, cgroup_move) &&
!WARN_ON_ONCE(!p->scx.cgrp_moving_from))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, cgroup_move, task_rq(p),
+ SCX_CALL_OP_TASK(sch, cgroup_move, task_rq(p),
p, p->scx.cgrp_moving_from,
tg_cgrp(task_group(p)));
p->scx.cgrp_moving_from = NULL;
cgroup_taskset_for_each(p, css, tset) {
if (SCX_HAS_OP(sch, cgroup_cancel_move) &&
p->scx.cgrp_moving_from)
- SCX_CALL_OP(sch, SCX_KF_UNLOCKED, cgroup_cancel_move, NULL,
+ SCX_CALL_OP(sch, cgroup_cancel_move, NULL,
p, p->scx.cgrp_moving_from, css->cgroup);
p->scx.cgrp_moving_from = NULL;
}
if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_weight) &&
tg->scx.weight != weight)
- SCX_CALL_OP(sch, SCX_KF_UNLOCKED, cgroup_set_weight, NULL,
- tg_cgrp(tg), weight);
+ SCX_CALL_OP(sch, cgroup_set_weight, NULL, tg_cgrp(tg), weight);
tg->scx.weight = weight;
percpu_down_read(&scx_cgroup_ops_rwsem);
if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_idle))
- SCX_CALL_OP(sch, SCX_KF_UNLOCKED, cgroup_set_idle, NULL,
- tg_cgrp(tg), idle);
+ SCX_CALL_OP(sch, cgroup_set_idle, NULL, tg_cgrp(tg), idle);
/* Update the task group's idle state */
tg->scx.idle = idle;
(tg->scx.bw_period_us != period_us ||
tg->scx.bw_quota_us != quota_us ||
tg->scx.bw_burst_us != burst_us))
- SCX_CALL_OP(sch, SCX_KF_UNLOCKED, cgroup_set_bandwidth, NULL,
+ SCX_CALL_OP(sch, cgroup_set_bandwidth, NULL,
tg_cgrp(tg), period_us, quota_us, burst_us);
tg->scx.bw_period_us = period_us;
if (!sch->ops.cgroup_exit)
continue;
- SCX_CALL_OP(sch, SCX_KF_UNLOCKED, cgroup_exit, NULL,
- css->cgroup);
+ SCX_CALL_OP(sch, cgroup_exit, NULL, css->cgroup);
}
}
continue;
}
- ret = SCX_CALL_OP_RET(sch, SCX_KF_UNLOCKED, cgroup_init, NULL,
+ ret = SCX_CALL_OP_RET(sch, cgroup_init, NULL,
css->cgroup, &args);
if (ret) {
scx_error(sch, "ops.cgroup_init() failed (%d)", ret);
.ops = &sch->ops,
.cgroup_path = sch->cgrp_path,
};
- SCX_CALL_OP(parent, SCX_KF_UNLOCKED, sub_detach, NULL,
+ SCX_CALL_OP(parent, sub_detach, NULL,
&sub_detach_args);
}
if (sch->ops.exit)
- SCX_CALL_OP(sch, SCX_KF_UNLOCKED, exit, NULL, sch->exit_info);
+ SCX_CALL_OP(sch, exit, NULL, sch->exit_info);
kobject_del(&sch->kobj);
}
#else /* CONFIG_EXT_SUB_SCHED */
}
if (sch->ops.exit)
- SCX_CALL_OP(sch, SCX_KF_UNLOCKED, exit, NULL, ei);
+ SCX_CALL_OP(sch, exit, NULL, ei);
scx_unlink_sched(sch);
if (SCX_HAS_OP(sch, dump_task)) {
ops_dump_init(s, " ");
- SCX_CALL_OP(sch, SCX_KF_REST, dump_task, NULL, dctx, p);
+ SCX_CALL_OP(sch, dump_task, NULL, dctx, p);
ops_dump_exit();
}
if (SCX_HAS_OP(sch, dump)) {
ops_dump_init(&s, "");
- SCX_CALL_OP(sch, SCX_KF_UNLOCKED, dump, NULL, &dctx);
+ SCX_CALL_OP(sch, dump, NULL, &dctx);
ops_dump_exit();
}
used = seq_buf_used(&ns);
if (SCX_HAS_OP(sch, dump_cpu)) {
ops_dump_init(&ns, " ");
- SCX_CALL_OP(sch, SCX_KF_REST, dump_cpu, NULL,
+ SCX_CALL_OP(sch, dump_cpu, NULL,
&dctx, cpu, idle);
ops_dump_exit();
}
scx_idle_enable(ops);
if (sch->ops.init) {
- ret = SCX_CALL_OP_RET(sch, SCX_KF_UNLOCKED, init, NULL);
+ ret = SCX_CALL_OP_RET(sch, init, NULL);
if (ret) {
ret = ops_sanitize_err(sch, "init", ret);
cpus_read_unlock();
}
if (sch->ops.init) {
- ret = SCX_CALL_OP_RET(sch, SCX_KF_UNLOCKED, init, NULL);
+ ret = SCX_CALL_OP_RET(sch, init, NULL);
if (ret) {
ret = ops_sanitize_err(sch, "init", ret);
scx_error(sch, "ops.init() failed (%d)", ret);
.cgroup_path = sch->cgrp_path,
};
- ret = SCX_CALL_OP_RET(parent, SCX_KF_UNLOCKED, sub_attach, NULL,
+ ret = SCX_CALL_OP_RET(parent, sub_attach, NULL,
&sub_attach_args);
if (ret) {
ret = ops_sanitize_err(sch, "sub_attach", ret);
static bool scx_dsq_insert_preamble(struct scx_sched *sch, struct task_struct *p,
u64 dsq_id, u64 *enq_flags)
{
- if (!scx_kf_allowed(sch, SCX_KF_ENQUEUE | SCX_KF_DISPATCH))
- return false;
-
lockdep_assert_irqs_disabled();
if (unlikely(!p)) {
bool in_balance;
unsigned long flags;
- if ((scx_locked_rq() || this_rq()->scx.in_select_cpu) &&
- !scx_kf_allowed(sch, SCX_KF_DISPATCH))
- return false;
-
if (!scx_vet_enq_flags(sch, dsq_id, &enq_flags))
return false;
if (unlikely(!sch))
return 0;
- if (!scx_kf_allowed(sch, SCX_KF_DISPATCH))
- return 0;
-
return sch->dsp_max_batch - __this_cpu_read(sch->pcpu->dsp_ctx.cursor);
}
if (unlikely(!sch))
return;
- if (!scx_kf_allowed(sch, SCX_KF_DISPATCH))
- return;
-
dspc = &this_cpu_ptr(sch->pcpu)->dsp_ctx;
if (dspc->cursor > 0)
if (unlikely(!sch))
return false;
- if (!scx_kf_allowed(sch, SCX_KF_DISPATCH))
- return false;
-
if (!scx_vet_enq_flags(sch, SCX_DSQ_LOCAL, &enq_flags))
return false;
if (unlikely(!parent))
return false;
- if (!scx_kf_allowed(parent, SCX_KF_DISPATCH))
- return false;
-
child = scx_find_sub_sched(cgroup_id);
if (unlikely(!child))
if (unlikely(!sch))
return 0;
- if (!scx_kf_allowed(sch, SCX_KF_CPU_RELEASE))
- return 0;
-
rq = cpu_rq(smp_processor_id());
lockdep_assert_rq_held(rq);