Skip to content

Commit cd77618

Browse files
multics69Alexei Starovoitov
authored andcommitted
selftests/bpf: Make bpf get_preempt_count() work for v6.14+ kernels
Recent x86 kernels export __preempt_count as a ksym, while some old kernels between v6.1 and v6.14 expose the preemption counter via pcpu_hot.preempt_count. The existing selftest helper unconditionally dereferenced __preempt_count, which breaks BPF program loading on such old kernels. Make the x86 preemption count lookup version-agnostic by: - Marking __preempt_count and pcpu_hot as weak ksyms. - Introducing a BTF-described pcpu_hot___local layout with preserve_access_index. - Selecting the appropriate access path at runtime using ksym availability and bpf_ksym_exists() and bpf_core_field_exists(). This allows a single BPF binary to run correctly across kernel versions (e.g., v6.18 vs. v6.13) without relying on compile-time version checks. Signed-off-by: Changwoo Min <changwoo@igalia.com> Link: https://lore.kernel.org/r/20260130021843.154885-1-changwoo@igalia.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent b18a761 commit cd77618

1 file changed

Lines changed: 20 additions & 2 deletions

File tree

tools/testing/selftests/bpf/bpf_experimental.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,13 @@ extern int bpf_cgroup_read_xattr(struct cgroup *cgroup, const char *name__str,
614614

615615
extern bool CONFIG_PREEMPT_RT __kconfig __weak;
616616
#ifdef bpf_target_x86
617-
extern const int __preempt_count __ksym;
617+
extern const int __preempt_count __ksym __weak;
618+
619+
struct pcpu_hot___local {
620+
int preempt_count;
621+
} __attribute__((preserve_access_index));
622+
623+
extern struct pcpu_hot___local pcpu_hot __ksym __weak;
618624
#endif
619625

620626
struct task_struct___preempt_rt {
@@ -624,7 +630,19 @@ struct task_struct___preempt_rt {
624630
static inline int get_preempt_count(void)
625631
{
626632
#if defined(bpf_target_x86)
627-
return *(int *) bpf_this_cpu_ptr(&__preempt_count);
633+
/* By default, read the per-CPU __preempt_count. */
634+
if (bpf_ksym_exists(&__preempt_count))
635+
return *(int *) bpf_this_cpu_ptr(&__preempt_count);
636+
637+
/*
638+
* If __preempt_count does not exist, try to read preempt_count under
639+
* struct pcpu_hot. Between v6.1 and v6.14 -- more specifically,
640+
* [64701838bf057, 46e8fff6d45fe), preempt_count had been managed
641+
* under struct pcpu_hot.
642+
*/
643+
if (bpf_core_field_exists(pcpu_hot.preempt_count))
644+
return ((struct pcpu_hot___local *)
645+
bpf_this_cpu_ptr(&pcpu_hot))->preempt_count;
628646
#elif defined(bpf_target_arm64)
629647
return bpf_get_current_task_btf()->thread_info.preempt.count;
630648
#endif

0 commit comments

Comments
 (0)