Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: support multiple tags per argument

Add ability to iterate multiple decl_tag types pointed to the same
function argument. Use this to support multiple __arg_xxx tags per
global subprog argument.

We leave btf_find_decl_tag_value() intact, but change its implementation
to use a new btf_find_next_decl_tag() which can be straightforwardly
used to find next BTF type ID of a matching btf_decl_tag type.
btf_prepare_func_args() is switched from btf_find_decl_tag_value() to
btf_find_next_decl_tag() to gain multiple tags per argument support.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20240105000909.2818934-5-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
522bb2c1 54c11ec4

+47 -27
+2
include/linux/bpf.h
··· 2472 2472 struct btf *btf, const struct btf_type *t); 2473 2473 const char *btf_find_decl_tag_value(const struct btf *btf, const struct btf_type *pt, 2474 2474 int comp_idx, const char *tag_key); 2475 + int btf_find_next_decl_tag(const struct btf *btf, const struct btf_type *pt, 2476 + int comp_idx, const char *tag_key, int last_id); 2475 2477 2476 2478 struct bpf_prog *bpf_prog_by_id(u32 id); 2477 2479 struct bpf_link *bpf_link_by_id(u32 id);
+45 -27
kernel/bpf/btf.c
··· 3310 3310 return BTF_FIELD_FOUND; 3311 3311 } 3312 3312 3313 + int btf_find_next_decl_tag(const struct btf *btf, const struct btf_type *pt, 3314 + int comp_idx, const char *tag_key, int last_id) 3315 + { 3316 + int len = strlen(tag_key); 3317 + int i, n; 3318 + 3319 + for (i = last_id + 1, n = btf_nr_types(btf); i < n; i++) { 3320 + const struct btf_type *t = btf_type_by_id(btf, i); 3321 + 3322 + if (!btf_type_is_decl_tag(t)) 3323 + continue; 3324 + if (pt != btf_type_by_id(btf, t->type)) 3325 + continue; 3326 + if (btf_type_decl_tag(t)->component_idx != comp_idx) 3327 + continue; 3328 + if (strncmp(__btf_name_by_offset(btf, t->name_off), tag_key, len)) 3329 + continue; 3330 + return i; 3331 + } 3332 + return -ENOENT; 3333 + } 3334 + 3313 3335 const char *btf_find_decl_tag_value(const struct btf *btf, const struct btf_type *pt, 3314 3336 int comp_idx, const char *tag_key) 3315 3337 { 3316 3338 const char *value = NULL; 3317 - int i; 3339 + const struct btf_type *t; 3340 + int len, id; 3318 3341 3319 - for (i = 1; i < btf_nr_types(btf); i++) { 3320 - const struct btf_type *t = btf_type_by_id(btf, i); 3321 - int len = strlen(tag_key); 3342 + id = btf_find_next_decl_tag(btf, pt, comp_idx, tag_key, 0); 3343 + if (id < 0) 3344 + return ERR_PTR(id); 3322 3345 3323 - if (!btf_type_is_decl_tag(t)) 3324 - continue; 3325 - if (pt != btf_type_by_id(btf, t->type) || 3326 - btf_type_decl_tag(t)->component_idx != comp_idx) 3327 - continue; 3328 - if (strncmp(__btf_name_by_offset(btf, t->name_off), tag_key, len)) 3329 - continue; 3330 - /* Prevent duplicate entries for same type */ 3331 - if (value) 3332 - return ERR_PTR(-EEXIST); 3333 - value = __btf_name_by_offset(btf, t->name_off) + len; 3334 - } 3335 - if (!value) 3336 - return ERR_PTR(-ENOENT); 3346 + t = btf_type_by_id(btf, id); 3347 + len = strlen(tag_key); 3348 + value = __btf_name_by_offset(btf, t->name_off) + len; 3349 + 3350 + /* Prevent duplicate entries for same type */ 3351 + id = btf_find_next_decl_tag(btf, pt, comp_idx, tag_key, id); 3352 + if (id >= 0) 3353 + return ERR_PTR(-EEXIST); 3354 + 3337 3355 return value; 3338 3356 } 3339 3357 ··· 7050 7032 * Only PTR_TO_CTX and SCALAR are supported atm. 7051 7033 */ 7052 7034 for (i = 0; i < nargs; i++) { 7053 - const char *tag; 7054 7035 u32 tags = 0; 7036 + int id = 0; 7055 7037 7056 - tag = btf_find_decl_tag_value(btf, fn_t, i, "arg:"); 7057 - if (IS_ERR(tag) && PTR_ERR(tag) == -ENOENT) { 7058 - tag = NULL; 7059 - } else if (IS_ERR(tag)) { 7060 - bpf_log(log, "arg#%d type's tag fetching failure: %ld\n", i, PTR_ERR(tag)); 7061 - return PTR_ERR(tag); 7062 - } 7063 7038 /* 'arg:<tag>' decl_tag takes precedence over derivation of 7064 7039 * register type from BTF type itself 7065 7040 */ 7066 - if (tag) { 7041 + while ((id = btf_find_next_decl_tag(btf, fn_t, i, "arg:", id)) > 0) { 7042 + const struct btf_type *tag_t = btf_type_by_id(btf, id); 7043 + const char *tag = __btf_name_by_offset(btf, tag_t->name_off) + 4; 7044 + 7067 7045 /* disallow arg tags in static subprogs */ 7068 7046 if (!is_global) { 7069 7047 bpf_log(log, "arg#%d type tag is not supported in static functions\n", i); ··· 7074 7060 bpf_log(log, "arg#%d has unsupported set of tags\n", i); 7075 7061 return -EOPNOTSUPP; 7076 7062 } 7063 + } 7064 + if (id != -ENOENT) { 7065 + bpf_log(log, "arg#%d type tag fetching failure: %d\n", i, id); 7066 + return id; 7077 7067 } 7078 7068 7079 7069 t = btf_type_by_id(btf, args[i].type);