diff --git a/kernel/sched/ext/sub.c b/kernel/sched/ext/sub.c index 5fe2f79064dc..17ed0d28f383 100644 --- a/kernel/sched/ext/sub.c +++ b/kernel/sched/ext/sub.c @@ -21,6 +21,33 @@ #ifdef CONFIG_EXT_SUB_SCHED +/** + * scx_skip_subtree_pre - Skip @pos's subtree in a pre-order walk + * @pos: current position + * @root: walk root + * + * In a walk started by scx_next_descendant_pre(), continue past @pos's subtree: + * return @pos's next sibling, or the closest ancestor's next sibling, or NULL + * if @pos's subtree is the last under @root. Same locking rules. + */ +struct scx_sched *scx_skip_subtree_pre(struct scx_sched *pos, struct scx_sched *root) +{ + struct scx_sched *next; + + lockdep_assert(lockdep_is_held(&scx_enable_mutex) || + lockdep_is_held(&scx_sched_lock) || + rcu_read_lock_any_held()); + + while (pos != root) { + next = list_next_or_null_rcu(&scx_parent(pos)->children, &pos->sibling, + struct scx_sched, sibling); + if (next) + return next; + pos = scx_parent(pos); + } + return NULL; +} + /** * scx_next_descendant_pre - find the next descendant for pre-order walk * @pos: the current position (%NULL to initiate traversal) @@ -48,15 +75,7 @@ struct scx_sched *scx_next_descendant_pre(struct scx_sched *pos, struct scx_sche return next; /* no child, visit my or the closest ancestor's next sibling */ - while (pos != root) { - next = list_next_or_null_rcu(&scx_parent(pos)->children, &pos->sibling, - struct scx_sched, sibling); - if (next) - return next; - pos = scx_parent(pos); - } - - return NULL; + return scx_skip_subtree_pre(pos, root); } static struct scx_sched *scx_find_sub_sched(u64 cgroup_id) diff --git a/kernel/sched/ext/sub.h b/kernel/sched/ext/sub.h index 45f3952b5d81..2688087a0654 100644 --- a/kernel/sched/ext/sub.h +++ b/kernel/sched/ext/sub.h @@ -15,6 +15,7 @@ #ifdef CONFIG_EXT_SUB_SCHED +struct scx_sched *scx_skip_subtree_pre(struct scx_sched *pos, struct scx_sched *root); struct scx_sched *scx_next_descendant_pre(struct scx_sched *pos, struct scx_sched *root); void scx_set_task_sched(struct task_struct *p, struct scx_sched *sch); struct cgroup *sch_cgroup(struct scx_sched *sch); @@ -35,6 +36,7 @@ static inline const char *sch_cgrp_path(struct scx_sched *sch) #else /* CONFIG_EXT_SUB_SCHED */ static inline struct scx_sched *scx_next_descendant_pre(struct scx_sched *pos, struct scx_sched *root) { return pos ? NULL : root; } +static inline struct scx_sched *scx_skip_subtree_pre(struct scx_sched *pos, struct scx_sched *root) { return NULL; } static inline void scx_set_task_sched(struct task_struct *p, struct scx_sched *sch) {} static inline struct cgroup *sch_cgroup(struct scx_sched *sch) { return NULL; } static inline const char *sch_cgrp_path(struct scx_sched *sch) { return "/"; }