There is no LoongArch support for get_preempt_count() currently and its fallback path always returns 0, just add it so that bpf_in_interrupt(), bpf_in_nmi(), bpf_in_hardirq(), bpf_in_serving_softirq(), bpf_in_task() work for LoongArch as well. Since LoongArch is transitioning to CONFIG_THREAD_INFO_IN_TASK, use bpf_core_field_exists() to provide compatibility for both legacy and future kernels. A struct flavor "task_struct___local" is introduced to bypass static compiler checks when thread_info is missing from the base task_struct. For the newer kernels that select CONFIG_THREAD_INFO_IN_TASK, it reads preempt_count from the thread_info embedded within task_struct. For the older kernels without selecting CONFIG_THREAD_INFO_IN_TASK, it retrieves the thread_info pointer from the bottom of the kernel stack (task->stack) and then reads the preempt_count. This ensures the BPF selftests remain functional across various LoongArch kernel versions. With this patch, "./test_progs -t exe_ctx" passes on LoongArch regardless of whether CONFIG_THREAD_INFO_IN_TASK is set. Signed-off-by: Tiezhu Yang --- .../testing/selftests/bpf/bpf_experimental.h | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tools/testing/selftests/bpf/bpf_experimental.h b/tools/testing/selftests/bpf/bpf_experimental.h index d1db355e872b..1d0b29a9acb8 100644 --- a/tools/testing/selftests/bpf/bpf_experimental.h +++ b/tools/testing/selftests/bpf/bpf_experimental.h @@ -401,6 +401,12 @@ struct task_struct___preempt_rt { extern struct lowcore *bpf_get_lowcore(void) __weak __ksym; #endif +#ifdef bpf_target_loongarch +struct task_struct___local { + struct thread_info thread_info; +} __attribute__((preserve_access_index)); +#endif + static inline int get_preempt_count(void) { #if defined(bpf_target_x86) @@ -423,6 +429,18 @@ static inline int get_preempt_count(void) return bpf_get_current_task_btf()->thread_info.preempt_count; #elif defined(bpf_target_s390) return bpf_get_lowcore()->preempt_count; +#elif defined(bpf_target_loongarch) + struct task_struct *task = bpf_get_current_task_btf(); + struct task_struct___local *task_alt = (void *)task; + + if (bpf_core_field_exists(task_alt->thread_info)) { + return BPF_CORE_READ(task_alt, thread_info.preempt_count); + } else { + void *stack = BPF_CORE_READ(task, stack); + struct thread_info *ti = (void *)stack; + + return BPF_CORE_READ(ti, preempt_count); + } #endif return 0; } @@ -433,6 +451,7 @@ static inline int get_preempt_count(void) * * arm64 * * powerpc64 * * s390x + * * loongarch */ static inline int bpf_in_interrupt(void) { @@ -454,6 +473,7 @@ static inline int bpf_in_interrupt(void) * * arm64 * * powerpc64 * * s390x + * * loongarch */ static inline int bpf_in_nmi(void) { @@ -466,6 +486,7 @@ static inline int bpf_in_nmi(void) * * arm64 * * powerpc64 * * s390x + * * loongarch */ static inline int bpf_in_hardirq(void) { @@ -478,6 +499,7 @@ static inline int bpf_in_hardirq(void) * * arm64 * * powerpc64 * * s390x + * * loongarch */ static inline int bpf_in_serving_softirq(void) { @@ -498,6 +520,7 @@ static inline int bpf_in_serving_softirq(void) * * arm64 * * powerpc64 * * s390x + * * loongarch */ static inline int bpf_in_task(void) { -- 2.42.0