diff options
| -rw-r--r-- | Documentation/bpf/kfuncs.rst | 4 | ||||
| -rw-r--r-- | tools/bpf/resolve_btfids/main.c | 72 | ||||
| -rw-r--r-- | tools/testing/selftests/bpf/prog_tests/resolve_btfids.c | 41 | ||||
| -rw-r--r-- | tools/testing/selftests/bpf/progs/btf_data.c | 20 |
4 files changed, 99 insertions, 38 deletions
diff --git a/Documentation/bpf/kfuncs.rst b/Documentation/bpf/kfuncs.rst index 1004eb0bec61..10e725cbe64c 100644 --- a/Documentation/bpf/kfuncs.rst +++ b/Documentation/bpf/kfuncs.rst @@ -513,8 +513,8 @@ At kernel build time the ``resolve_btfids`` tool finds all kfuncs declared with ``BTF_KFUNCS_START()`` and emits their BTF annotations into the kernel's BTF. For each kfunc it emits a ``bpf_kfunc`` BTF decl tag, a ``bpf_fastcall`` decl tag when the kfunc is flagged ``KF_FASTCALL``, and the ``address_space(1)`` type -attribute on the return value and/or arguments flagged ``KF_ARENA_RET``, -``KF_ARENA_ARG1`` or ``KF_ARENA_ARG2`` (see section 2.8). +attribute on the return value and/or arguments that use arena pointers (see +sections 2.3.8 and 2.8). 2.7 Specifying no-cast aliases with ___init -------------------------------------------- diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c index d2e4176339da..37d7e7224207 100644 --- a/tools/bpf/resolve_btfids/main.c +++ b/tools/bpf/resolve_btfids/main.c @@ -64,8 +64,8 @@ * each such kfunc it: * * - emits a "bpf_kfunc" decl tag, and "bpf_fastcall" when KF_FASTCALL is set; - * - wraps the return value and/or arguments flagged KF_ARENA_RET, - * KF_ARENA_ARG1 or KF_ARENA_ARG2 with the "address_space(1)" type attribute; + * - wraps the return value and/or arguments that use arena pointers + * with the "address_space(1)" type attribute; * - rewrites the prototype of KF_IMPLICIT_ARGS kfuncs. * * These kfunc annotations were historically produced by pahole. @@ -182,6 +182,8 @@ struct object { #define KF_IMPLICIT_ARGS (1 << 16) #define KF_IMPL_SUFFIX "_impl" #define TYPE_ATTR_ARENA "address_space(1)" +#define PARAM_SUFFIX_ARENA "__arena" +#define PARAM_SUFFIX_ARENA_NULLABLE "__arena__nullable" struct kfunc { struct rb_node rb_node; @@ -1067,6 +1069,22 @@ static int collect_decl_tags(struct btf2btf_context *ctx) return 0; } +static bool param_name_has_suffix(const char *name, const char *suffix) +{ + size_t name_len = strlen(name); + size_t suffix_len = strlen(suffix); + + return name_len >= suffix_len && !strcmp(name + name_len - suffix_len, suffix); +} + +static bool is_arena_param(const struct btf *btf, const struct btf_param *param) +{ + const char *name = btf__name_by_offset(btf, param->name_off); + + return param_name_has_suffix(name, PARAM_SUFFIX_ARENA) || + param_name_has_suffix(name, PARAM_SUFFIX_ARENA_NULLABLE); +} + static int collect_kfuncs(struct object *obj, struct btf2btf_context *ctx) { Elf_Data *idlist = obj->efile.idlist; @@ -1299,8 +1317,12 @@ add_new_proto: return 0; } -static bool is_arena_arg(struct kfunc *kfunc, u32 idx) +static bool is_arena_arg(const struct btf *btf, const struct kfunc *kfunc, + const struct btf_param *param, u32 idx) { + if (is_arena_param(btf, param)) + return true; + switch (idx) { case 0: return kfunc->flags & KF_ARENA_ARG1; @@ -1339,23 +1361,36 @@ static s32 arena_tag_ptr(struct btf *btf, u32 ptr_id, struct kfunc *kfunc) } /* - * Add a FUNC_PROTO for @kfunc with each relevant pointer tagged with - * an "address_space(1)" attribute. The original proto may be shared - * with other FUNCs, so it is never modified in place. + * Add a FUNC_PROTO for @kfunc with each arena pointer tagged with an + * "address_space(1)" attribute. The original proto may be shared with + * other FUNCs, so it is never modified in place. Returns the original + * proto id when @kfunc has no arena return value or arguments. */ static s32 add_arena_tagged_proto(struct btf *btf, struct kfunc *kfunc) { const struct btf_type *func = btf__type_by_id(btf, kfunc->btf_id); u32 proto_id = func->type; const struct btf_type *proto = btf__type_by_id(btf, proto_id); + const struct btf_param *params = btf_params(proto); u32 nr_params = btf_vlen(proto); s32 ret_type_id = proto->type; const struct btf_type *t; - struct btf_param *params; + struct btf_param *tag_params; s32 new_proto_id, id; const char *name; + bool has_arena_arg = false; int err, i; + for (i = 0; i < nr_params; i++) { + if (is_arena_arg(btf, kfunc, ¶ms[i], i)) { + has_arena_arg = true; + break; + } + } + + if (!(kfunc->flags & KF_ARENA_RET) && !has_arena_arg) + return proto_id; + if (kfunc->flags & KF_ARENA_RET) { ret_type_id = arena_tag_ptr(btf, ret_type_id, kfunc); if (ret_type_id < 0) @@ -1383,19 +1418,18 @@ static s32 add_arena_tagged_proto(struct btf *btf, struct kfunc *kfunc) } for (i = 0; i < nr_params; i++) { - if (!is_arena_arg(kfunc, i)) - continue; - t = btf__type_by_id(btf, new_proto_id); - params = btf_params(t); + tag_params = btf_params(t); + if (!is_arena_arg(btf, kfunc, &tag_params[i], i)) + continue; - id = arena_tag_ptr(btf, params[i].type, kfunc); + id = arena_tag_ptr(btf, tag_params[i].type, kfunc); if (id < 0) return id; t = btf__type_by_id(btf, new_proto_id); - params = btf_params(t); - params[i].type = id; + tag_params = btf_params(t); + tag_params[i].type = id; } pr_debug("added arena-tagged proto for kfunc %s: %d\n", kfunc->name, new_proto_id); @@ -1403,7 +1437,7 @@ static s32 add_arena_tagged_proto(struct btf *btf, struct kfunc *kfunc) return new_proto_id; } -static int process_kfunc_with_arena_flags(struct btf2btf_context *ctx, +static int process_kfunc_with_arena_attrs(struct btf2btf_context *ctx, struct kfunc *kfunc) { struct btf_type *t; @@ -1463,11 +1497,9 @@ static int btf2btf(struct object *obj) goto out; } - if (kfunc->flags & (KF_ARENA_RET | KF_ARENA_ARG1 | KF_ARENA_ARG2)) { - err = process_kfunc_with_arena_flags(&ctx, kfunc); - if (err) - goto out; - } + err = process_kfunc_with_arena_attrs(&ctx, kfunc); + if (err) + goto out; } err = 0; diff --git a/tools/testing/selftests/bpf/prog_tests/resolve_btfids.c b/tools/testing/selftests/bpf/prog_tests/resolve_btfids.c index 732cfed35e1c..3f9949e8227d 100644 --- a/tools/testing/selftests/bpf/prog_tests/resolve_btfids.c +++ b/tools/testing/selftests/bpf/prog_tests/resolve_btfids.c @@ -15,6 +15,7 @@ #define DECL_TAG_FASTCALL "bpf_fastcall" #define DECL_TAG_KFUNC "bpf_kfunc" #define TYPE_ATTR_ARENA "address_space(1)" +#define ARENA_ARG(n) (1U << (n)) #ifndef KF_FASTCALL #define KF_FASTCALL (1 << 12) @@ -49,13 +50,20 @@ struct kfunc_symbol { const char *name; s32 id; u32 flags; + u32 arena_args; + bool arena_ret; }; static struct kfunc_symbol kfunc_symbols[] = { - { "kfunc_a", -1, 0 }, - { "kfunc_b", -1, KF_FASTCALL }, - { "kfunc_c", -1, KF_ARENA_RET | KF_ARENA_ARG1 | KF_ARENA_ARG2 }, - { "kfunc_d", -1, KF_ARENA_ARG2 }, + { "kfunc_a", -1, 0, 0, false }, + { "kfunc_b", -1, KF_FASTCALL, 0, false }, + { "kfunc_c", -1, KF_ARENA_RET | KF_ARENA_ARG1 | KF_ARENA_ARG2, + ARENA_ARG(0) | ARENA_ARG(1), true }, + { "kfunc_d", -1, KF_ARENA_ARG2, ARENA_ARG(1), false }, + { "kfunc_e", -1, 0, ARENA_ARG(0) | ARENA_ARG(1) | ARENA_ARG(2) | + ARENA_ARG(3) | ARENA_ARG(4), false }, + { "kfunc_f", -1, 0, ARENA_ARG(1), false }, + { "kfunc_g", -1, KF_ARENA_RET, ARENA_ARG(0) | ARENA_ARG(1), true }, }; /* Align the .BTF_ids section to 4 bytes */ @@ -105,6 +113,9 @@ BTF_ID_FLAGS(func, kfunc_a) BTF_ID_FLAGS(func, kfunc_b, KF_FASTCALL) BTF_ID_FLAGS(func, kfunc_c, KF_ARENA_RET | KF_ARENA_ARG1 | KF_ARENA_ARG2) BTF_ID_FLAGS(func, kfunc_d, KF_ARENA_ARG2) +BTF_ID_FLAGS(func, kfunc_e) +BTF_ID_FLAGS(func, kfunc_f) +BTF_ID_FLAGS(func, kfunc_g, KF_ARENA_RET) BTF_KFUNCS_END(test_kfunc_set) /* @@ -112,6 +123,9 @@ BTF_KFUNCS_END(test_kfunc_set) * actually sort at least one of the two sets. */ BTF_KFUNCS_START(test_kfunc_set_rev) +BTF_ID_FLAGS(func, kfunc_g, KF_ARENA_RET) +BTF_ID_FLAGS(func, kfunc_f) +BTF_ID_FLAGS(func, kfunc_e) BTF_ID_FLAGS(func, kfunc_d, KF_ARENA_ARG2) BTF_ID_FLAGS(func, kfunc_c, KF_ARENA_RET | KF_ARENA_ARG1 | KF_ARENA_ARG2) BTF_ID_FLAGS(func, kfunc_b, KF_FASTCALL) @@ -301,15 +315,15 @@ void test_resolve_btfids(void) } /* - * Check resolve_btfids wrapped exactly the arena-flagged return/args - * with the address_space(1) type attribute, and left other + * Check resolve_btfids wrapped exactly the arena-flagged or suffixed + * return/args with the address_space(1) type attribute, and left other * pointers/returns untouched. */ for (i = 0; i < ARRAY_SIZE(kfunc_symbols); i++) { const struct btf_type *fn, *proto; const struct btf_param *params; const char *name = kfunc_symbols[i].name; - u32 fl = kfunc_symbols[i].flags; + u32 arena_args = kfunc_symbols[i].arena_args; __u32 nr; fn = btf__type_by_id(btf, kfunc_symbols[i].id); @@ -322,15 +336,10 @@ void test_resolve_btfids(void) nr = btf_vlen(proto); ASSERT_EQ(is_arena_tagged_ptr(btf, proto->type), - !!(fl & KF_ARENA_RET), name); - if (nr > 0) { - ASSERT_EQ(is_arena_tagged_ptr(btf, params[0].type), - !!(fl & KF_ARENA_ARG1), name); - } - if (nr > 1) { - ASSERT_EQ(is_arena_tagged_ptr(btf, params[1].type), - !!(fl & KF_ARENA_ARG2), name); - } + kfunc_symbols[i].arena_ret, name); + for (j = 0; j < nr; j++) + ASSERT_EQ(is_arena_tagged_ptr(btf, params[j].type), + !!(arena_args & ARENA_ARG(j)), name); } out: diff --git a/tools/testing/selftests/bpf/progs/btf_data.c b/tools/testing/selftests/bpf/progs/btf_data.c index ec34f7a6e038..8082c13490ab 100644 --- a/tools/testing/selftests/bpf/progs/btf_data.c +++ b/tools/testing/selftests/bpf/progs/btf_data.c @@ -68,3 +68,23 @@ int kfunc_d(struct root_struct *a, struct root_struct *b) { return 0; } + +int kfunc_e(struct root_struct *a__arena, + struct root_struct *b__arena__nullable, + struct root_struct *c__arena, + struct root_struct *d__arena__nullable, + struct root_struct *e__arena) +{ + return 0; +} + +int kfunc_f(struct root_struct *a, struct root_struct *b__arena, int flags) +{ + return 0; +} + +struct root_struct *kfunc_g(struct root_struct *a__arena, + struct root_struct *b__arena__nullable) +{ + return a__arena; +} |
