Add an annotation to emit more contextual messages per deprecated kfunc about which replacement kfunc can be used in its place. The macro itself takes the replacement kfunc as the argument. This uses BTF declaration tags, and is only supplied as a warning to the user when the kernel is compiled using LLVM, as GCC lacks equivalent support. That said, in all cases KF_DEPRECATED does produce a warning, so this strictly leads to an improved message where possible. Signed-off-by: Kumar Kartikeya Dwivedi --- include/linux/btf.h | 5 +++++ include/linux/compiler_types.h | 14 ++++++++++++-- kernel/bpf/helpers.c | 8 ++++++++ kernel/bpf/verifier.c | 9 +++++++++ .../testing/selftests/bpf/test_kmods/bpf_testmod.c | 1 + 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/include/linux/btf.h b/include/linux/btf.h index 86006a2d8b2a..50cc8aa50e7a 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -89,6 +89,11 @@ */ #define __bpf_kfunc __used __retain __noclone noinline +#define BPF_KFUNC_DECL_TAG_REPLACEMENT "bpf:kfunc:replacement:" + +#define __bpf_kfunc_replacement(replacement) \ + BTF_DECL_TAG(BPF_KFUNC_DECL_TAG_REPLACEMENT __stringify(replacement)) + #define __bpf_kfunc_start_defs() \ __diag_push(); \ __diag_ignore_all("-Wmissing-declarations", \ diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 890076d0974b..ef840212dc56 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -35,10 +35,20 @@ * see https://github.com/rust-lang/rust-bindgen/issues/2244. */ #if defined(CONFIG_DEBUG_INFO_BTF) && defined(CONFIG_PAHOLE_HAS_BTF_TAG) && \ - __has_attribute(btf_type_tag) && !defined(__BINDGEN__) -# define BTF_TYPE_TAG(value) __attribute__((btf_type_tag(#value))) + !defined(__BINDGEN__) +# if __has_attribute(btf_type_tag) +# define BTF_TYPE_TAG(value) __attribute__((btf_type_tag(#value))) +# else +# define BTF_TYPE_TAG(value) /* nothing */ +# endif +# if __has_attribute(btf_decl_tag) +# define BTF_DECL_TAG(value) __attribute__((btf_decl_tag(value))) +# else +# define BTF_DECL_TAG(value) /* nothing */ +# endif #else # define BTF_TYPE_TAG(value) /* nothing */ +# define BTF_DECL_TAG(value) /* nothing */ #endif #include diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 190c0b382f11..a07ebc0597a3 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2328,6 +2328,7 @@ __bpf_kfunc void *bpf_obj_new(u64 local_type_id__k, struct btf_struct_meta *meta return p; } +__bpf_kfunc_replacement(bpf_obj_new) __bpf_kfunc void *bpf_obj_new_impl(u64 local_type_id__k, void *meta__ign) { return bpf_obj_new(local_type_id__k, meta__ign); @@ -2352,6 +2353,7 @@ __bpf_kfunc void *bpf_percpu_obj_new(u64 local_type_id__k, struct btf_struct_met return bpf_mem_alloc(&bpf_global_percpu_ma, size); } +__bpf_kfunc_replacement(bpf_percpu_obj_new) __bpf_kfunc void *bpf_percpu_obj_new_impl(u64 local_type_id__k, void *meta__ign) { return bpf_percpu_obj_new(local_type_id__k, meta__ign); @@ -2395,6 +2397,7 @@ __bpf_kfunc void bpf_obj_drop(void *p__alloc, struct btf_struct_meta *meta) __bpf_obj_drop_impl(p, meta ? meta->record : NULL, false); } +__bpf_kfunc_replacement(bpf_obj_drop) __bpf_kfunc void bpf_obj_drop_impl(void *p__alloc, void *meta__ign) { return bpf_obj_drop(p__alloc, meta__ign); @@ -2413,6 +2416,7 @@ __bpf_kfunc void bpf_percpu_obj_drop(void *p__alloc, struct btf_struct_meta *met bpf_mem_free_rcu(&bpf_global_percpu_ma, p__alloc); } +__bpf_kfunc_replacement(bpf_percpu_obj_drop) __bpf_kfunc void bpf_percpu_obj_drop_impl(void *p__alloc, void *meta__ign) { bpf_percpu_obj_drop(p__alloc, meta__ign); @@ -2445,6 +2449,7 @@ __bpf_kfunc void *bpf_refcount_acquire(void *p__refcounted_kptr, struct btf_stru return (void *)p__refcounted_kptr; } +__bpf_kfunc_replacement(bpf_refcount_acquire) __bpf_kfunc void *bpf_refcount_acquire_impl(void *p__refcounted_kptr, void *meta__ign) { return bpf_refcount_acquire(p__refcounted_kptr, meta__ign); @@ -2499,6 +2504,7 @@ __bpf_kfunc int bpf_list_push_front(struct bpf_list_head *head, return __bpf_list_add(n, head, false, meta ? meta->record : NULL, off); } +__bpf_kfunc_replacement(bpf_list_push_front) __bpf_kfunc int bpf_list_push_front_impl(struct bpf_list_head *head, struct bpf_list_node *node, void *meta__ign, u64 off) @@ -2528,6 +2534,7 @@ __bpf_kfunc int bpf_list_push_back(struct bpf_list_head *head, return __bpf_list_add(n, head, true, meta ? meta->record : NULL, off); } +__bpf_kfunc_replacement(bpf_list_push_back) __bpf_kfunc int bpf_list_push_back_impl(struct bpf_list_head *head, struct bpf_list_node *node, void *meta__ign, u64 off) @@ -2668,6 +2675,7 @@ __bpf_kfunc int bpf_rbtree_add(struct bpf_rb_root *root, return __bpf_rbtree_add(root, n, (void *)less, meta ? meta->record : NULL, off); } +__bpf_kfunc_replacement(bpf_rbtree_add) __bpf_kfunc int bpf_rbtree_add_impl(struct bpf_rb_root *root, struct bpf_rb_node *node, bool (less)(struct bpf_rb_node *a, const struct bpf_rb_node *b), void *meta__ign, u64 off) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 267ab3c36f6f..535b4af710a8 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -14594,6 +14594,8 @@ static void warn_for_deprecated_kfuncs(struct bpf_verifier_env *env, int insn_idx, s16 offset) { const struct bpf_line_info *linfo; + const char *replacement; + const struct btf_type *t; struct bpf_kfunc_desc *desc; const char *file; int line_num; @@ -14612,6 +14614,13 @@ static void warn_for_deprecated_kfuncs(struct bpf_verifier_env *env, insn_idx, meta->func_name); } + t = btf_type_by_id(meta->btf, meta->func_id); + replacement = btf_find_decl_tag_value(meta->btf, t, -1, BPF_KFUNC_DECL_TAG_REPLACEMENT); + if (!IS_ERR(replacement) && !str_is_empty(replacement)) { + warn(env, "Switch to kfunc %s() instead.\n", replacement); + warn(env, "For older kernels, choose the correct kfunc using bpf_ksym_exists().\n"); + } + desc->warned_deprecated = true; } diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c index 6ad7b2cdfd05..7391247e3d18 100644 --- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c +++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c @@ -1252,6 +1252,7 @@ __bpf_kfunc int bpf_kfunc_multi_st_ops_test_1_assoc(struct st_ops_args *args, st __bpf_kfunc int bpf_kfunc_implicit_arg(int a, struct bpf_prog_aux *aux); __bpf_kfunc int bpf_kfunc_implicit_arg_legacy(int a, int b, struct bpf_prog_aux *aux); +__bpf_kfunc_replacement(bpf_kfunc_implicit_arg_legacy) __bpf_kfunc int bpf_kfunc_implicit_arg_legacy_impl(int a, int b, struct bpf_prog_aux *aux); /* hook targets */ -- 2.52.0