The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Andrea Righi <arighi@nvidia.com>
To: Tejun Heo <tj@kernel.org>
Cc: linux-kernel@vger.kernel.org,
	Peter Zijlstra <peterz@infradead.org>,
	Ingo Molnar <mingo@redhat.com>,
	Juri Lelli <juri.lelli@redhat.com>,
	Vincent Guittot <vincent.guittot@linaro.org>,
	David Vernet <void@manifault.com>,
	Changwoo Min <changwoo@igalia.com>,
	Emil Tsalapatis <emil@etsalapatis.com>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	sched-ext@lists.linux.dev
Subject: Re: [PATCH sched_ext/for-7.2 2/2] sched_ext: Move shared helpers from ext.c into internal.h and cid.h
Date: Mon, 22 Jun 2026 20:45:32 +0200	[thread overview]
Message-ID: <ajmCzLPU6Jo_2iB9@gpd4> (raw)
In-Reply-To: <20260622173904.1169407-2-tj@kernel.org>

Hi Tejun,

On Mon, Jun 22, 2026 at 07:39:04AM -1000, Tejun Heo wrote:
> idle.c and cid.c are included into build_policy.c together with ext.c and
> use helpers that ext.c defines. Because the helpers live in ext.c, the two
> files can not parse as standalone units and clangd reports errors in them.
> 
> Move the helpers to the headers they belong to. The op-dispatch macros and
> helpers plus scx_parent() to internal.h, and scx_cpu_arg()/scx_cpu_ret() to
> cid.h. No functional change. idle.c and cid.c now parse clean standalone.
> 
> Suggested-by: Peter Zijlstra <peterz@infradead.org>
> Signed-off-by: Tejun Heo <tj@kernel.org>
> ---

Looks good to me.

Reviewed-by: Andrea Righi <arighi@nvidia.com>

Thanks,
-Andrea

>  kernel/sched/ext/cid.h      |  21 ++++++
>  kernel/sched/ext/ext.c      | 141 ------------------------------------
>  kernel/sched/ext/internal.h | 121 +++++++++++++++++++++++++++++++
>  3 files changed, 142 insertions(+), 141 deletions(-)
> 
> diff --git a/kernel/sched/ext/cid.h b/kernel/sched/ext/cid.h
> index 41d0802c6af3..9c4f4b907f12 100644
> --- a/kernel/sched/ext/cid.h
> +++ b/kernel/sched/ext/cid.h
> @@ -270,4 +270,25 @@ static inline u32 scx_cmask_nr_used_words(const struct scx_cmask *m)
>  		     __w && ((cid) = __bs + __wi * 64 + __ffs64(__w), true);	\
>  		     __w &= __w - 1)
>  
> +/*
> + * scx_cpu_arg() wraps a cpu arg being handed to an SCX op. For cid-form
> + * schedulers it resolves to the matching cid; for cpu-form it passes @cpu
> + * through. scx_cpu_ret() is the inverse for a cpu/cid returned from an op
> + * (currently only ops.select_cpu); it validates the BPF-supplied cid and
> + * triggers scx_error() on @sch if invalid.
> + */
> +static inline s32 scx_cpu_arg(s32 cpu)
> +{
> +	if (scx_is_cid_type())
> +		return __scx_cpu_to_cid(cpu);
> +	return cpu;
> +}
> +
> +static inline s32 scx_cpu_ret(struct scx_sched *sch, s32 cpu_or_cid)
> +{
> +	if (cpu_or_cid < 0 || !scx_is_cid_type())
> +		return cpu_or_cid;
> +	return scx_cid_to_cpu(sch, cpu_or_cid);
> +}
> +
>  #endif /* _KERNEL_SCHED_EXT_CID_H */
> diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
> index ebf6dc84cb4d..dd41b84ae680 100644
> --- a/kernel/sched/ext/ext.c
> +++ b/kernel/sched/ext/ext.c
> @@ -258,8 +258,6 @@ __printf(5, 6) bool __scx_exit(struct scx_sched *sch,
>  	return ret;
>  }
>  
> -#define SCX_HAS_OP(sch, op)	test_bit(SCX_OP_IDX(op), (sch)->has_op)
> -
>  static long jiffies_delta_msecs(unsigned long at, unsigned long now)
>  {
>  	if (time_after(at, now))
> @@ -274,20 +272,6 @@ static bool u32_before(u32 a, u32 b)
>  }
>  
>  #ifdef CONFIG_EXT_SUB_SCHED
> -/**
> - * scx_parent - Find the parent sched
> - * @sch: sched to find the parent of
> - *
> - * Returns the parent scheduler or %NULL if @sch is root.
> - */
> -static struct scx_sched *scx_parent(struct scx_sched *sch)
> -{
> -	if (sch->level)
> -		return sch->ancestors[sch->level - 1];
> -	else
> -		return NULL;
> -}
> -
>  /**
>   * scx_next_descendant_pre - find the next descendant for pre-order walk
>   * @pos: the current position (%NULL to initiate traversal)
> @@ -335,7 +319,6 @@ static void scx_set_task_sched(struct task_struct *p, struct scx_sched *sch)
>  	rcu_assign_pointer(p->scx.sched, sch);
>  }
>  #else	/* CONFIG_EXT_SUB_SCHED */
> -static inline struct scx_sched *scx_parent(struct scx_sched *sch) { return NULL; }
>  static inline struct scx_sched *scx_next_descendant_pre(struct scx_sched *pos, struct scx_sched *root) { return pos ? NULL : root; }
>  static inline void scx_set_task_sched(struct task_struct *p, struct scx_sched *sch) {}
>  #endif	/* CONFIG_EXT_SUB_SCHED */
> @@ -495,123 +478,12 @@ static bool rq_is_open(struct rq *rq, u64 enq_flags)
>   */
>  DEFINE_PER_CPU(struct rq *, scx_locked_rq_state);
>  
> -static inline void update_locked_rq(struct rq *rq)
> -{
> -	/*
> -	 * Check whether @rq is actually locked. This can help expose bugs
> -	 * or incorrect assumptions about the context in which a kfunc or
> -	 * callback is executed.
> -	 */
> -	if (rq)
> -		lockdep_assert_rq_held(rq);
> -	__this_cpu_write(scx_locked_rq_state, rq);
> -}
> -
> -/*
> - * SCX ops can recurse via scx_bpf_sub_dispatch() - the inner call must not
> - * clobber the outer's scx_locked_rq_state. Save it on entry, restore on exit.
> - */
> -#define SCX_CALL_OP(sch, op, locked_rq, args...)				\
> -do {										\
> -	struct rq *__prev_locked_rq;						\
> -										\
> -	if (locked_rq) {							\
> -		__prev_locked_rq = scx_locked_rq();				\
> -		update_locked_rq(locked_rq);					\
> -	}									\
> -	(sch)->ops.op(args);							\
> -	if (locked_rq)								\
> -		update_locked_rq(__prev_locked_rq);				\
> -} while (0)
> -
>  /*
>   * Flipped on enable per sch->is_cid_type. Declared in internal.h so
>   * subsystem inlines can read it.
>   */
>  DEFINE_STATIC_KEY_FALSE(__scx_is_cid_type);
>  
> -/*
> - * scx_cpu_arg() wraps a cpu arg being handed to an SCX op. For cid-form
> - * schedulers it resolves to the matching cid; for cpu-form it passes @cpu
> - * through. scx_cpu_ret() is the inverse for a cpu/cid returned from an op
> - * (currently only ops.select_cpu); it validates the BPF-supplied cid and
> - * triggers scx_error() on @sch if invalid.
> - */
> -static s32 scx_cpu_arg(s32 cpu)
> -{
> -	if (scx_is_cid_type())
> -		return __scx_cpu_to_cid(cpu);
> -	return cpu;
> -}
> -
> -static s32 scx_cpu_ret(struct scx_sched *sch, s32 cpu_or_cid)
> -{
> -	if (cpu_or_cid < 0 || !scx_is_cid_type())
> -		return cpu_or_cid;
> -	return scx_cid_to_cpu(sch, cpu_or_cid);
> -}
> -
> -#define SCX_CALL_OP_RET(sch, op, locked_rq, args...)				\
> -({										\
> -	struct rq *__prev_locked_rq;						\
> -	__typeof__((sch)->ops.op(args)) __ret;					\
> -										\
> -	if (locked_rq) {							\
> -		__prev_locked_rq = scx_locked_rq();				\
> -		update_locked_rq(locked_rq);					\
> -	}									\
> -	__ret = (sch)->ops.op(args);						\
> -	if (locked_rq)								\
> -		update_locked_rq(__prev_locked_rq);				\
> -	__ret;									\
> -})
> -
> -/*
> - * SCX_CALL_OP_TASK*() invokes an SCX op that takes one or two task arguments
> - * and records them in current->scx.kf_tasks[] for the duration of the call. A
> - * kfunc invoked from inside such an op can then use
> - * scx_kf_arg_task_ok() to verify that its task argument is one of
> - * those subject tasks.
> - *
> - * Every SCX_CALL_OP_TASK*() call site invokes its op with @p's rq lock held -
> - * either via the @locked_rq argument here, or (for ops.select_cpu()) via @p's
> - * pi_lock held by try_to_wake_up() with rq tracking via scx_rq.in_select_cpu.
> - * So if kf_tasks[] is set, @p's scheduler-protected fields are stable.
> - *
> - * kf_tasks[] can not stack, so task-based SCX ops must not nest. The
> - * WARN_ON_ONCE() in each macro catches a re-entry of any of the three variants
> - * while a previous one is still in progress.
> - */
> -#define SCX_CALL_OP_TASK(sch, op, locked_rq, task, args...)			\
> -do {										\
> -	WARN_ON_ONCE(current->scx.kf_tasks[0]);					\
> -	current->scx.kf_tasks[0] = task;					\
> -	SCX_CALL_OP((sch), op, locked_rq, task, ##args);			\
> -	current->scx.kf_tasks[0] = NULL;					\
> -} while (0)
> -
> -#define SCX_CALL_OP_TASK_RET(sch, op, locked_rq, task, args...)			\
> -({										\
> -	__typeof__((sch)->ops.op(task, ##args)) __ret;				\
> -	WARN_ON_ONCE(current->scx.kf_tasks[0]);					\
> -	current->scx.kf_tasks[0] = task;					\
> -	__ret = SCX_CALL_OP_RET((sch), op, locked_rq, task, ##args);		\
> -	current->scx.kf_tasks[0] = NULL;					\
> -	__ret;									\
> -})
> -
> -#define SCX_CALL_OP_2TASKS_RET(sch, op, locked_rq, task0, task1, args...)	\
> -({										\
> -	__typeof__((sch)->ops.op(task0, task1, ##args)) __ret;			\
> -	WARN_ON_ONCE(current->scx.kf_tasks[0]);					\
> -	current->scx.kf_tasks[0] = task0;					\
> -	current->scx.kf_tasks[1] = task1;					\
> -	__ret = SCX_CALL_OP_RET((sch), op, locked_rq, task0, task1, ##args);	\
> -	current->scx.kf_tasks[0] = NULL;					\
> -	current->scx.kf_tasks[1] = NULL;					\
> -	__ret;									\
> -})
> -
>  /**
>   * scx_call_op_set_cpumask - invoke ops.set_cpumask / ops_cid.set_cmask for @task
>   * @sch: scx_sched being invoked
> @@ -650,19 +522,6 @@ static inline void scx_call_op_set_cpumask(struct scx_sched *sch, struct rq *rq,
>  	current->scx.kf_tasks[0] = NULL;
>  }
>  
> -/* see SCX_CALL_OP_TASK() */
> -static __always_inline bool scx_kf_arg_task_ok(struct scx_sched *sch,
> -							struct task_struct *p)
> -{
> -	if (unlikely((p != current->scx.kf_tasks[0] &&
> -		      p != current->scx.kf_tasks[1]))) {
> -		scx_error(sch, "called on a task not being operated on");
> -		return false;
> -	}
> -
> -	return true;
> -}
> -
>  enum scx_dsq_iter_flags {
>  	/* iterate in the reverse dispatch order */
>  	SCX_DSQ_ITER_REV		= 1U << 16,
> diff --git a/kernel/sched/ext/internal.h b/kernel/sched/ext/internal.h
> index 1f5312b3b387..145272cb4d8a 100644
> --- a/kernel/sched/ext/internal.h
> +++ b/kernel/sched/ext/internal.h
> @@ -1553,6 +1553,111 @@ static inline struct rq *scx_locked_rq(void)
>  	return __this_cpu_read(scx_locked_rq_state);
>  }
>  
> +static inline void update_locked_rq(struct rq *rq)
> +{
> +	/*
> +	 * Check whether @rq is actually locked. This can help expose bugs
> +	 * or incorrect assumptions about the context in which a kfunc or
> +	 * callback is executed.
> +	 */
> +	if (rq)
> +		lockdep_assert_rq_held(rq);
> +	__this_cpu_write(scx_locked_rq_state, rq);
> +}
> +
> +#define SCX_HAS_OP(sch, op)	test_bit(SCX_OP_IDX(op), (sch)->has_op)
> +
> +/*
> + * SCX ops can recurse via scx_bpf_sub_dispatch() - the inner call must not
> + * clobber the outer's scx_locked_rq_state. Save it on entry, restore on exit.
> + */
> +#define SCX_CALL_OP(sch, op, locked_rq, args...)				\
> +do {										\
> +	struct rq *__prev_locked_rq;						\
> +										\
> +	if (locked_rq) {							\
> +		__prev_locked_rq = scx_locked_rq();				\
> +		update_locked_rq(locked_rq);					\
> +	}									\
> +	(sch)->ops.op(args);							\
> +	if (locked_rq)								\
> +		update_locked_rq(__prev_locked_rq);				\
> +} while (0)
> +
> +#define SCX_CALL_OP_RET(sch, op, locked_rq, args...)				\
> +({										\
> +	struct rq *__prev_locked_rq;						\
> +	__typeof__((sch)->ops.op(args)) __ret;					\
> +										\
> +	if (locked_rq) {							\
> +		__prev_locked_rq = scx_locked_rq();				\
> +		update_locked_rq(locked_rq);					\
> +	}									\
> +	__ret = (sch)->ops.op(args);						\
> +	if (locked_rq)								\
> +		update_locked_rq(__prev_locked_rq);				\
> +	__ret;									\
> +})
> +
> +/*
> + * SCX_CALL_OP_TASK*() invokes an SCX op that takes one or two task arguments
> + * and records them in current->scx.kf_tasks[] for the duration of the call. A
> + * kfunc invoked from inside such an op can then use
> + * scx_kf_arg_task_ok() to verify that its task argument is one of
> + * those subject tasks.
> + *
> + * Every SCX_CALL_OP_TASK*() call site invokes its op with @p's rq lock held -
> + * either via the @locked_rq argument here, or (for ops.select_cpu()) via @p's
> + * pi_lock held by try_to_wake_up() with rq tracking via scx_rq.in_select_cpu.
> + * So if kf_tasks[] is set, @p's scheduler-protected fields are stable.
> + *
> + * kf_tasks[] can not stack, so task-based SCX ops must not nest. The
> + * WARN_ON_ONCE() in each macro catches a re-entry of any of the three variants
> + * while a previous one is still in progress.
> + */
> +#define SCX_CALL_OP_TASK(sch, op, locked_rq, task, args...)			\
> +do {										\
> +	WARN_ON_ONCE(current->scx.kf_tasks[0]);					\
> +	current->scx.kf_tasks[0] = task;					\
> +	SCX_CALL_OP((sch), op, locked_rq, task, ##args);			\
> +	current->scx.kf_tasks[0] = NULL;					\
> +} while (0)
> +
> +#define SCX_CALL_OP_TASK_RET(sch, op, locked_rq, task, args...)			\
> +({										\
> +	__typeof__((sch)->ops.op(task, ##args)) __ret;				\
> +	WARN_ON_ONCE(current->scx.kf_tasks[0]);					\
> +	current->scx.kf_tasks[0] = task;					\
> +	__ret = SCX_CALL_OP_RET((sch), op, locked_rq, task, ##args);		\
> +	current->scx.kf_tasks[0] = NULL;					\
> +	__ret;									\
> +})
> +
> +#define SCX_CALL_OP_2TASKS_RET(sch, op, locked_rq, task0, task1, args...)	\
> +({										\
> +	__typeof__((sch)->ops.op(task0, task1, ##args)) __ret;			\
> +	WARN_ON_ONCE(current->scx.kf_tasks[0]);					\
> +	current->scx.kf_tasks[0] = task0;					\
> +	current->scx.kf_tasks[1] = task1;					\
> +	__ret = SCX_CALL_OP_RET((sch), op, locked_rq, task0, task1, ##args);	\
> +	current->scx.kf_tasks[0] = NULL;					\
> +	current->scx.kf_tasks[1] = NULL;					\
> +	__ret;									\
> +})
> +
> +/* see SCX_CALL_OP_TASK() */
> +static __always_inline bool scx_kf_arg_task_ok(struct scx_sched *sch,
> +					       struct task_struct *p)
> +{
> +	if (unlikely((p != current->scx.kf_tasks[0] &&
> +		      p != current->scx.kf_tasks[1]))) {
> +		scx_error(sch, "called on a task not being operated on");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
>  static inline bool scx_bypassing(struct scx_sched *sch, s32 cpu)
>  {
>  	return unlikely(per_cpu_ptr(sch->pcpu, cpu)->flags &
> @@ -1633,6 +1738,20 @@ static inline struct scx_sched *scx_prog_sched(const struct bpf_prog_aux *aux)
>  
>  	return NULL;
>  }
> +
> +/**
> + * scx_parent - Find the parent sched
> + * @sch: sched to find the parent of
> + *
> + * Returns the parent scheduler or %NULL if @sch is root.
> + */
> +static inline struct scx_sched *scx_parent(struct scx_sched *sch)
> +{
> +	if (sch->level)
> +		return sch->ancestors[sch->level - 1];
> +	else
> +		return NULL;
> +}
>  #else	/* CONFIG_EXT_SUB_SCHED */
>  static inline struct scx_sched *scx_task_sched(const struct task_struct *p)
>  {
> @@ -1656,6 +1775,8 @@ static inline struct scx_sched *scx_prog_sched(const struct bpf_prog_aux *aux)
>  {
>  	return rcu_dereference_all(scx_root);
>  }
> +
> +static inline struct scx_sched *scx_parent(struct scx_sched *sch) { return NULL; }
>  #endif	/* CONFIG_EXT_SUB_SCHED */
>  
>  #endif /* _KERNEL_SCHED_EXT_INTERNAL_H */
> -- 
> 2.54.0
> 

  reply	other threads:[~2026-06-22 18:45 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-22 17:39 [PATCH sched_ext/for-7.2 1/2] sched_ext: Make kernel/sched/ext/ sources self-contained for clangd Tejun Heo
2026-06-22 17:39 ` [PATCH sched_ext/for-7.2 2/2] sched_ext: Move shared helpers from ext.c into internal.h and cid.h Tejun Heo
2026-06-22 18:45   ` Andrea Righi [this message]
2026-06-22 18:26 ` [PATCH sched_ext/for-7.2 1/2] sched_ext: Make kernel/sched/ext/ sources self-contained for clangd Andrea Righi
2026-06-22 20:37 ` [PATCH v2 " Tejun Heo
2026-06-22 21:05 ` [PATCH " Tejun Heo
2026-06-23  7:52   ` Peter Zijlstra

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=ajmCzLPU6Jo_2iB9@gpd4 \
    --to=arighi@nvidia.com \
    --cc=changwoo@igalia.com \
    --cc=emil@etsalapatis.com \
    --cc=juri.lelli@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=sched-ext@lists.linux.dev \
    --cc=tj@kernel.org \
    --cc=torvalds@linux-foundation.org \
    --cc=vincent.guittot@linaro.org \
    --cc=void@manifault.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox