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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'bpf-resilient-split-btf-followups'

Alan Maguire says:

====================
bpf: resilient split BTF followups

Follow-up to resilient split BTF series [1],

- cleaning up libbpf relocation code (patch 1);
- adding 'struct module' support for base BTF data (patch 2);
- splitting out field iteration code into separate file (patch 3);
- sharing libbpf relocation code with the kernel (patch 4);
- adding a kbuild --btf_features flag to generate distilled base
BTF in the module-specific case where KBUILD_EXTMOD is true
(patch 5); and
- adding test coverage for module-based kfunc dtor (patch 6)

Generation of distilled base BTF for modules requires the pahole patch
at [2], but without it we just won't get distilled base BTF (and thus BTF
relocation on module load) for bpf_testmod.ko.

Changes since v1 [3]:

- fixed line lengths and made comparison an explicit == 0 (Andrii, patch 1)
- moved btf_iter.c changes to separate patch (Andrii, patch 3)
- grouped common targets in kernel/bpf/Makefile (Andrii, patch 4)
- updated bpf_testmod ctx alloc to use GFP_ATOMIC, and updated dtor
selftest to use map-based dtor cleanup (Eduard, patch 6)

[1] https://lore.kernel.org/bpf/20240613095014.357981-1-alan.maguire@oracle.com/
[2] https://lore.kernel.org/bpf/20240517102714.4072080-1-alan.maguire@oracle.com/
[3] https://lore.kernel.org/bpf/20240618162449.809994-1-alan.maguire@oracle.com/
====================

Link: https://lore.kernel.org/r/20240620091733.1967885-1-alan.maguire@oracle.com
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>

+533 -260
+64
include/linux/btf.h
··· 140 140 const char *btf_get_name(const struct btf *btf); 141 141 void btf_get(struct btf *btf); 142 142 void btf_put(struct btf *btf); 143 + const struct btf_header *btf_header(const struct btf *btf); 143 144 int btf_new_fd(const union bpf_attr *attr, bpfptr_t uattr, u32 uattr_sz); 144 145 struct btf *btf_get_by_fd(int fd); 145 146 int btf_get_info_by_fd(const struct btf *btf, ··· 213 212 u32 btf_obj_id(const struct btf *btf); 214 213 bool btf_is_kernel(const struct btf *btf); 215 214 bool btf_is_module(const struct btf *btf); 215 + bool btf_is_vmlinux(const struct btf *btf); 216 216 struct module *btf_try_get_module(const struct btf *btf); 217 217 u32 btf_nr_types(const struct btf *btf); 218 + struct btf *btf_base_btf(const struct btf *btf); 218 219 bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s, 219 220 const struct btf_member *m, 220 221 u32 expected_offset, u32 expected_size); ··· 340 337 static inline u8 btf_int_offset(const struct btf_type *t) 341 338 { 342 339 return BTF_INT_OFFSET(*(u32 *)(t + 1)); 340 + } 341 + 342 + static inline __u8 btf_int_bits(const struct btf_type *t) 343 + { 344 + return BTF_INT_BITS(*(__u32 *)(t + 1)); 343 345 } 344 346 345 347 static inline bool btf_type_is_scalar(const struct btf_type *t) ··· 486 478 return (struct btf_param *)(t + 1); 487 479 } 488 480 481 + static inline struct btf_decl_tag *btf_decl_tag(const struct btf_type *t) 482 + { 483 + return (struct btf_decl_tag *)(t + 1); 484 + } 485 + 489 486 static inline int btf_id_cmp_func(const void *a, const void *b) 490 487 { 491 488 const int *pa = a, *pb = b; ··· 528 515 } 529 516 #endif 530 517 518 + enum btf_field_iter_kind { 519 + BTF_FIELD_ITER_IDS, 520 + BTF_FIELD_ITER_STRS, 521 + }; 522 + 523 + struct btf_field_desc { 524 + /* once-per-type offsets */ 525 + int t_off_cnt, t_offs[2]; 526 + /* member struct size, or zero, if no members */ 527 + int m_sz; 528 + /* repeated per-member offsets */ 529 + int m_off_cnt, m_offs[1]; 530 + }; 531 + 532 + struct btf_field_iter { 533 + struct btf_field_desc desc; 534 + void *p; 535 + int m_idx; 536 + int off_idx; 537 + int vlen; 538 + }; 539 + 531 540 #ifdef CONFIG_BPF_SYSCALL 532 541 const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id); 542 + void btf_set_base_btf(struct btf *btf, const struct btf *base_btf); 543 + int btf_relocate(struct btf *btf, const struct btf *base_btf, __u32 **map_ids); 544 + int btf_field_iter_init(struct btf_field_iter *it, struct btf_type *t, 545 + enum btf_field_iter_kind iter_kind); 546 + __u32 *btf_field_iter_next(struct btf_field_iter *it); 547 + 533 548 const char *btf_name_by_offset(const struct btf *btf, u32 offset); 549 + const char *btf_str_by_offset(const struct btf *btf, u32 offset); 534 550 struct btf *btf_parse_vmlinux(void); 535 551 struct btf *bpf_prog_get_target_btf(const struct bpf_prog *prog); 536 552 u32 *btf_kfunc_id_set_contains(const struct btf *btf, u32 kfunc_btf_id, ··· 586 544 { 587 545 return NULL; 588 546 } 547 + 548 + static inline void btf_set_base_btf(struct btf *btf, const struct btf *base_btf) 549 + { 550 + } 551 + 552 + static inline int btf_relocate(void *log, struct btf *btf, const struct btf *base_btf, 553 + __u32 **map_ids) 554 + { 555 + return -EOPNOTSUPP; 556 + } 557 + 558 + static inline int btf_field_iter_init(struct btf_field_iter *it, struct btf_type *t, 559 + enum btf_field_iter_kind iter_kind) 560 + { 561 + return -EOPNOTSUPP; 562 + } 563 + 564 + static inline __u32 *btf_field_iter_next(struct btf_field_iter *it) 565 + { 566 + return NULL; 567 + } 568 + 589 569 static inline const char *btf_name_by_offset(const struct btf *btf, 590 570 u32 offset) 591 571 {
+2
include/linux/module.h
··· 509 509 #endif 510 510 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES 511 511 unsigned int btf_data_size; 512 + unsigned int btf_base_data_size; 512 513 void *btf_data; 514 + void *btf_base_data; 513 515 #endif 514 516 #ifdef CONFIG_JUMP_LABEL 515 517 struct jump_entry *jump_entries;
+7 -1
kernel/bpf/Makefile
··· 50 50 obj-$(CONFIG_BPF_PRELOAD) += preload/ 51 51 52 52 obj-$(CONFIG_BPF_SYSCALL) += relo_core.o 53 - $(obj)/relo_core.o: $(srctree)/tools/lib/bpf/relo_core.c FORCE 53 + obj-$(CONFIG_BPF_SYSCALL) += btf_iter.o 54 + obj-$(CONFIG_BPF_SYSCALL) += btf_relocate.o 55 + 56 + # Some source files are common to libbpf. 57 + vpath %.c $(srctree)/kernel/bpf:$(srctree)/tools/lib/bpf 58 + 59 + $(obj)/%.o: %.c FORCE 54 60 $(call if_changed_rule,cc_o_c)
+125 -53
kernel/bpf/btf.c
··· 274 274 u32 start_str_off; /* first string offset (0 for base BTF) */ 275 275 char name[MODULE_NAME_LEN]; 276 276 bool kernel_btf; 277 + __u32 *base_id_map; /* map from distilled base BTF -> vmlinux BTF ids */ 277 278 }; 278 279 279 280 enum verifier_phase { ··· 531 530 btf_type_is_var(t) || btf_type_is_typedef(t); 532 531 } 533 532 533 + bool btf_is_vmlinux(const struct btf *btf) 534 + { 535 + return btf->kernel_btf && !btf->base_btf; 536 + } 537 + 534 538 u32 btf_nr_types(const struct btf *btf) 535 539 { 536 540 u32 total = 0; ··· 778 772 return true; 779 773 } 780 774 781 - static const char *btf_str_by_offset(const struct btf *btf, u32 offset) 775 + const char *btf_str_by_offset(const struct btf *btf, u32 offset) 782 776 { 783 777 while (offset < btf->start_str_off) 784 778 btf = btf->base_btf; ··· 1676 1670 1677 1671 if (!tab) 1678 1672 return; 1679 - /* For module BTF, we directly assign the sets being registered, so 1680 - * there is nothing to free except kfunc_set_tab. 1681 - */ 1682 - if (btf_is_module(btf)) 1683 - goto free_tab; 1684 1673 for (hook = 0; hook < ARRAY_SIZE(tab->sets); hook++) 1685 1674 kfree(tab->sets[hook]); 1686 - free_tab: 1687 1675 kfree(tab); 1688 1676 btf->kfunc_set_tab = NULL; 1689 1677 } ··· 1735 1735 kvfree(btf->types); 1736 1736 kvfree(btf->resolved_sizes); 1737 1737 kvfree(btf->resolved_ids); 1738 - kvfree(btf->data); 1738 + /* vmlinux does not allocate btf->data, it simply points it at 1739 + * __start_BTF. 1740 + */ 1741 + if (!btf_is_vmlinux(btf)) 1742 + kvfree(btf->data); 1743 + kvfree(btf->base_id_map); 1739 1744 kfree(btf); 1740 1745 } 1741 1746 ··· 1767 1762 btf_free_id(btf); 1768 1763 call_rcu(&btf->rcu, btf_free_rcu); 1769 1764 } 1765 + } 1766 + 1767 + struct btf *btf_base_btf(const struct btf *btf) 1768 + { 1769 + return btf->base_btf; 1770 + } 1771 + 1772 + const struct btf_header *btf_header(const struct btf *btf) 1773 + { 1774 + return &btf->hdr; 1775 + } 1776 + 1777 + void btf_set_base_btf(struct btf *btf, const struct btf *base_btf) 1778 + { 1779 + btf->base_btf = (struct btf *)base_btf; 1780 + btf->start_id = btf_nr_types(base_btf); 1781 + btf->start_str_off = base_btf->hdr.str_len; 1770 1782 } 1771 1783 1772 1784 static int env_resolve_init(struct btf_verifier_env *env) ··· 6105 6083 BTF_ID_LIST(bpf_ctx_convert_btf_id) 6106 6084 BTF_ID(struct, bpf_ctx_convert) 6107 6085 6108 - struct btf *btf_parse_vmlinux(void) 6086 + static struct btf *btf_parse_base(struct btf_verifier_env *env, const char *name, 6087 + void *data, unsigned int data_size) 6109 6088 { 6110 - struct btf_verifier_env *env = NULL; 6111 - struct bpf_verifier_log *log; 6112 6089 struct btf *btf = NULL; 6113 6090 int err; 6114 6091 6115 6092 if (!IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) 6116 6093 return ERR_PTR(-ENOENT); 6117 - 6118 - env = kzalloc(sizeof(*env), GFP_KERNEL | __GFP_NOWARN); 6119 - if (!env) 6120 - return ERR_PTR(-ENOMEM); 6121 - 6122 - log = &env->log; 6123 - log->level = BPF_LOG_KERNEL; 6124 6094 6125 6095 btf = kzalloc(sizeof(*btf), GFP_KERNEL | __GFP_NOWARN); 6126 6096 if (!btf) { ··· 6121 6107 } 6122 6108 env->btf = btf; 6123 6109 6124 - btf->data = __start_BTF; 6125 - btf->data_size = __stop_BTF - __start_BTF; 6110 + btf->data = data; 6111 + btf->data_size = data_size; 6126 6112 btf->kernel_btf = true; 6127 - snprintf(btf->name, sizeof(btf->name), "vmlinux"); 6113 + snprintf(btf->name, sizeof(btf->name), "%s", name); 6128 6114 6129 6115 err = btf_parse_hdr(env); 6130 6116 if (err) ··· 6144 6130 if (err) 6145 6131 goto errout; 6146 6132 6147 - /* btf_parse_vmlinux() runs under bpf_verifier_lock */ 6148 - bpf_ctx_convert.t = btf_type_by_id(btf, bpf_ctx_convert_btf_id[0]); 6149 - 6150 6133 refcount_set(&btf->refcnt, 1); 6151 6134 6152 - err = btf_alloc_id(btf); 6153 - if (err) 6154 - goto errout; 6155 - 6156 - btf_verifier_env_free(env); 6157 6135 return btf; 6158 6136 6159 6137 errout: 6160 - btf_verifier_env_free(env); 6161 6138 if (btf) { 6162 6139 kvfree(btf->types); 6163 6140 kfree(btf); ··· 6156 6151 return ERR_PTR(err); 6157 6152 } 6158 6153 6159 - #ifdef CONFIG_DEBUG_INFO_BTF_MODULES 6160 - 6161 - static struct btf *btf_parse_module(const char *module_name, const void *data, unsigned int data_size) 6154 + struct btf *btf_parse_vmlinux(void) 6162 6155 { 6163 6156 struct btf_verifier_env *env = NULL; 6164 6157 struct bpf_verifier_log *log; 6165 - struct btf *btf = NULL, *base_btf; 6158 + struct btf *btf; 6166 6159 int err; 6167 6160 6168 - base_btf = bpf_get_btf_vmlinux(); 6169 - if (IS_ERR(base_btf)) 6170 - return base_btf; 6171 - if (!base_btf) 6161 + env = kzalloc(sizeof(*env), GFP_KERNEL | __GFP_NOWARN); 6162 + if (!env) 6163 + return ERR_PTR(-ENOMEM); 6164 + 6165 + log = &env->log; 6166 + log->level = BPF_LOG_KERNEL; 6167 + btf = btf_parse_base(env, "vmlinux", __start_BTF, __stop_BTF - __start_BTF); 6168 + if (IS_ERR(btf)) 6169 + goto err_out; 6170 + 6171 + /* btf_parse_vmlinux() runs under bpf_verifier_lock */ 6172 + bpf_ctx_convert.t = btf_type_by_id(btf, bpf_ctx_convert_btf_id[0]); 6173 + err = btf_alloc_id(btf); 6174 + if (err) { 6175 + btf_free(btf); 6176 + btf = ERR_PTR(err); 6177 + } 6178 + err_out: 6179 + btf_verifier_env_free(env); 6180 + return btf; 6181 + } 6182 + 6183 + #ifdef CONFIG_DEBUG_INFO_BTF_MODULES 6184 + 6185 + /* If .BTF_ids section was created with distilled base BTF, both base and 6186 + * split BTF ids will need to be mapped to actual base/split ids for 6187 + * BTF now that it has been relocated. 6188 + */ 6189 + static __u32 btf_relocate_id(const struct btf *btf, __u32 id) 6190 + { 6191 + if (!btf->base_btf || !btf->base_id_map) 6192 + return id; 6193 + return btf->base_id_map[id]; 6194 + } 6195 + 6196 + static struct btf *btf_parse_module(const char *module_name, const void *data, 6197 + unsigned int data_size, void *base_data, 6198 + unsigned int base_data_size) 6199 + { 6200 + struct btf *btf = NULL, *vmlinux_btf, *base_btf = NULL; 6201 + struct btf_verifier_env *env = NULL; 6202 + struct bpf_verifier_log *log; 6203 + int err = 0; 6204 + 6205 + vmlinux_btf = bpf_get_btf_vmlinux(); 6206 + if (IS_ERR(vmlinux_btf)) 6207 + return vmlinux_btf; 6208 + if (!vmlinux_btf) 6172 6209 return ERR_PTR(-EINVAL); 6173 6210 6174 6211 env = kzalloc(sizeof(*env), GFP_KERNEL | __GFP_NOWARN); ··· 6219 6172 6220 6173 log = &env->log; 6221 6174 log->level = BPF_LOG_KERNEL; 6175 + 6176 + if (base_data) { 6177 + base_btf = btf_parse_base(env, ".BTF.base", base_data, base_data_size); 6178 + if (IS_ERR(base_btf)) { 6179 + err = PTR_ERR(base_btf); 6180 + goto errout; 6181 + } 6182 + } else { 6183 + base_btf = vmlinux_btf; 6184 + } 6222 6185 6223 6186 btf = kzalloc(sizeof(*btf), GFP_KERNEL | __GFP_NOWARN); 6224 6187 if (!btf) { ··· 6269 6212 if (err) 6270 6213 goto errout; 6271 6214 6215 + if (base_btf != vmlinux_btf) { 6216 + err = btf_relocate(btf, vmlinux_btf, &btf->base_id_map); 6217 + if (err) 6218 + goto errout; 6219 + btf_free(base_btf); 6220 + base_btf = vmlinux_btf; 6221 + } 6222 + 6272 6223 btf_verifier_env_free(env); 6273 6224 refcount_set(&btf->refcnt, 1); 6274 6225 return btf; 6275 6226 6276 6227 errout: 6277 6228 btf_verifier_env_free(env); 6229 + if (base_btf != vmlinux_btf) 6230 + btf_free(base_btf); 6278 6231 if (btf) { 6279 6232 kvfree(btf->data); 6280 6233 kvfree(btf->types); ··· 7837 7770 err = -ENOMEM; 7838 7771 goto out; 7839 7772 } 7840 - btf = btf_parse_module(mod->name, mod->btf_data, mod->btf_data_size); 7773 + btf = btf_parse_module(mod->name, mod->btf_data, mod->btf_data_size, 7774 + mod->btf_base_data, mod->btf_base_data_size); 7841 7775 if (IS_ERR(btf)) { 7842 7776 kfree(btf_mod); 7843 7777 if (!IS_ENABLED(CONFIG_MODULE_ALLOW_BTF_MISMATCH)) { ··· 8162 8094 bool add_filter = !!kset->filter; 8163 8095 struct btf_kfunc_set_tab *tab; 8164 8096 struct btf_id_set8 *set; 8165 - u32 set_cnt; 8097 + u32 set_cnt, i; 8166 8098 int ret; 8167 8099 8168 8100 if (hook >= BTF_KFUNC_HOOK_MAX) { ··· 8208 8140 goto end; 8209 8141 } 8210 8142 8211 - /* We don't need to allocate, concatenate, and sort module sets, because 8212 - * only one is allowed per hook. Hence, we can directly assign the 8213 - * pointer and return. 8214 - */ 8215 - if (!vmlinux_set) { 8216 - tab->sets[hook] = add_set; 8217 - goto do_add_filter; 8218 - } 8219 - 8220 8143 /* In case of vmlinux sets, there may be more than one set being 8221 8144 * registered per hook. To create a unified set, we allocate a new set 8222 8145 * and concatenate all individual sets being registered. While each set 8223 8146 * is individually sorted, they may become unsorted when concatenated, 8224 8147 * hence re-sorting the final set again is required to make binary 8225 8148 * searching the set using btf_id_set8_contains function work. 8149 + * 8150 + * For module sets, we need to allocate as we may need to relocate 8151 + * BTF ids. 8226 8152 */ 8227 8153 set_cnt = set ? set->cnt : 0; 8228 8154 ··· 8246 8184 8247 8185 /* Concatenate the two sets */ 8248 8186 memcpy(set->pairs + set->cnt, add_set->pairs, add_set->cnt * sizeof(set->pairs[0])); 8187 + /* Now that the set is copied, update with relocated BTF ids */ 8188 + for (i = set->cnt; i < set->cnt + add_set->cnt; i++) 8189 + set->pairs[i].id = btf_relocate_id(btf, set->pairs[i].id); 8190 + 8249 8191 set->cnt += add_set->cnt; 8250 8192 8251 8193 sort(set->pairs, set->cnt, sizeof(set->pairs[0]), btf_id_cmp_func, NULL); 8252 8194 8253 - do_add_filter: 8254 8195 if (add_filter) { 8255 8196 hook_filter = &tab->hook_filters[hook]; 8256 8197 hook_filter->filters[hook_filter->nr_filters++] = kset->filter; ··· 8373 8308 return PTR_ERR(btf); 8374 8309 8375 8310 for (i = 0; i < kset->set->cnt; i++) { 8376 - ret = btf_check_kfunc_protos(btf, kset->set->pairs[i].id, 8311 + ret = btf_check_kfunc_protos(btf, btf_relocate_id(btf, kset->set->pairs[i].id), 8377 8312 kset->set->pairs[i].flags); 8378 8313 if (ret) 8379 8314 goto err_out; ··· 8437 8372 u32 nr_args, i; 8438 8373 8439 8374 for (i = 0; i < cnt; i++) { 8440 - dtor_btf_id = dtors[i].kfunc_btf_id; 8375 + dtor_btf_id = btf_relocate_id(btf, dtors[i].kfunc_btf_id); 8441 8376 8442 8377 dtor_func = btf_type_by_id(btf, dtor_btf_id); 8443 8378 if (!dtor_func || !btf_type_is_func(dtor_func)) ··· 8472 8407 { 8473 8408 struct btf_id_dtor_kfunc_tab *tab; 8474 8409 struct btf *btf; 8475 - u32 tab_cnt; 8410 + u32 tab_cnt, i; 8476 8411 int ret; 8477 8412 8478 8413 btf = btf_get_module_btf(owner); ··· 8523 8458 btf->dtor_kfunc_tab = tab; 8524 8459 8525 8460 memcpy(tab->dtors + tab->cnt, dtors, add_cnt * sizeof(tab->dtors[0])); 8461 + 8462 + /* remap BTF ids based on BTF relocation (if any) */ 8463 + for (i = tab_cnt; i < tab_cnt + add_cnt; i++) { 8464 + tab->dtors[i].btf_id = btf_relocate_id(btf, tab->dtors[i].btf_id); 8465 + tab->dtors[i].kfunc_btf_id = btf_relocate_id(btf, tab->dtors[i].kfunc_btf_id); 8466 + } 8467 + 8526 8468 tab->cnt += add_cnt; 8527 8469 8528 8470 sort(tab->dtors, tab->cnt, sizeof(tab->dtors[0]), btf_id_cmp_func, NULL);
+4 -1
kernel/module/main.c
··· 2166 2166 #endif 2167 2167 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES 2168 2168 mod->btf_data = any_section_objs(info, ".BTF", 1, &mod->btf_data_size); 2169 + mod->btf_base_data = any_section_objs(info, ".BTF.base", 1, 2170 + &mod->btf_base_data_size); 2169 2171 #endif 2170 2172 #ifdef CONFIG_JUMP_LABEL 2171 2173 mod->jump_entries = section_objs(info, "__jump_table", ··· 2592 2590 } 2593 2591 2594 2592 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES 2595 - /* .BTF is not SHF_ALLOC and will get removed, so sanitize pointer */ 2593 + /* .BTF is not SHF_ALLOC and will get removed, so sanitize pointers */ 2596 2594 mod->btf_data = NULL; 2595 + mod->btf_base_data = NULL; 2597 2596 #endif 2598 2597 /* 2599 2598 * We want to free module_init, but be aware that kallsyms may be
+5
scripts/Makefile.btf
··· 21 21 # Switch to using --btf_features for v1.26 and later. 22 22 pahole-flags-$(call test-ge, $(pahole-ver), 126) = -j --btf_features=encode_force,var,float,enum64,decl_tag,type_tag,optimized_func,consistent_func,decl_tag_kfuncs 23 23 24 + ifneq ($(KBUILD_EXTMOD),) 25 + module-pahole-flags-$(call test-ge, $(pahole-ver), 126) += --btf_features=distilled_base 26 + endif 27 + 24 28 endif 25 29 26 30 pahole-flags-$(CONFIG_PAHOLE_HAS_LANG_EXCLUDE) += --lang_exclude=rust 27 31 28 32 export PAHOLE_FLAGS := $(pahole-flags-y) 33 + export MODULE_PAHOLE_FLAGS := $(module-pahole-flags-y)
+1 -1
scripts/Makefile.modfinal
··· 41 41 if [ ! -f vmlinux ]; then \ 42 42 printf "Skipping BTF generation for %s due to unavailability of vmlinux\n" $@ 1>&2; \ 43 43 else \ 44 - LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) --btf_base vmlinux $@; \ 44 + LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) $(MODULE_PAHOLE_FLAGS) --btf_base vmlinux $@; \ 45 45 $(RESOLVE_BTFIDS) -b vmlinux $@; \ 46 46 fi; 47 47
+1 -1
tools/lib/bpf/Build
··· 1 1 libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o \ 2 2 netlink.o bpf_prog_linfo.o libbpf_probes.o hashmap.o \ 3 3 btf_dump.o ringbuf.o strset.o linker.o gen_loader.o relo_core.o \ 4 - usdt.o zip.o elf.o features.o btf_relocate.o 4 + usdt.o zip.o elf.o features.o btf_iter.o btf_relocate.o
-162
tools/lib/bpf/btf.c
··· 5093 5093 return btf__parse_split(path, vmlinux_btf); 5094 5094 } 5095 5095 5096 - int btf_field_iter_init(struct btf_field_iter *it, struct btf_type *t, enum btf_field_iter_kind iter_kind) 5097 - { 5098 - it->p = NULL; 5099 - it->m_idx = -1; 5100 - it->off_idx = 0; 5101 - it->vlen = 0; 5102 - 5103 - switch (iter_kind) { 5104 - case BTF_FIELD_ITER_IDS: 5105 - switch (btf_kind(t)) { 5106 - case BTF_KIND_UNKN: 5107 - case BTF_KIND_INT: 5108 - case BTF_KIND_FLOAT: 5109 - case BTF_KIND_ENUM: 5110 - case BTF_KIND_ENUM64: 5111 - it->desc = (struct btf_field_desc) {}; 5112 - break; 5113 - case BTF_KIND_FWD: 5114 - case BTF_KIND_CONST: 5115 - case BTF_KIND_VOLATILE: 5116 - case BTF_KIND_RESTRICT: 5117 - case BTF_KIND_PTR: 5118 - case BTF_KIND_TYPEDEF: 5119 - case BTF_KIND_FUNC: 5120 - case BTF_KIND_VAR: 5121 - case BTF_KIND_DECL_TAG: 5122 - case BTF_KIND_TYPE_TAG: 5123 - it->desc = (struct btf_field_desc) { 1, {offsetof(struct btf_type, type)} }; 5124 - break; 5125 - case BTF_KIND_ARRAY: 5126 - it->desc = (struct btf_field_desc) { 5127 - 2, {sizeof(struct btf_type) + offsetof(struct btf_array, type), 5128 - sizeof(struct btf_type) + offsetof(struct btf_array, index_type)} 5129 - }; 5130 - break; 5131 - case BTF_KIND_STRUCT: 5132 - case BTF_KIND_UNION: 5133 - it->desc = (struct btf_field_desc) { 5134 - 0, {}, 5135 - sizeof(struct btf_member), 5136 - 1, {offsetof(struct btf_member, type)} 5137 - }; 5138 - break; 5139 - case BTF_KIND_FUNC_PROTO: 5140 - it->desc = (struct btf_field_desc) { 5141 - 1, {offsetof(struct btf_type, type)}, 5142 - sizeof(struct btf_param), 5143 - 1, {offsetof(struct btf_param, type)} 5144 - }; 5145 - break; 5146 - case BTF_KIND_DATASEC: 5147 - it->desc = (struct btf_field_desc) { 5148 - 0, {}, 5149 - sizeof(struct btf_var_secinfo), 5150 - 1, {offsetof(struct btf_var_secinfo, type)} 5151 - }; 5152 - break; 5153 - default: 5154 - return -EINVAL; 5155 - } 5156 - break; 5157 - case BTF_FIELD_ITER_STRS: 5158 - switch (btf_kind(t)) { 5159 - case BTF_KIND_UNKN: 5160 - it->desc = (struct btf_field_desc) {}; 5161 - break; 5162 - case BTF_KIND_INT: 5163 - case BTF_KIND_FLOAT: 5164 - case BTF_KIND_FWD: 5165 - case BTF_KIND_ARRAY: 5166 - case BTF_KIND_CONST: 5167 - case BTF_KIND_VOLATILE: 5168 - case BTF_KIND_RESTRICT: 5169 - case BTF_KIND_PTR: 5170 - case BTF_KIND_TYPEDEF: 5171 - case BTF_KIND_FUNC: 5172 - case BTF_KIND_VAR: 5173 - case BTF_KIND_DECL_TAG: 5174 - case BTF_KIND_TYPE_TAG: 5175 - case BTF_KIND_DATASEC: 5176 - it->desc = (struct btf_field_desc) { 5177 - 1, {offsetof(struct btf_type, name_off)} 5178 - }; 5179 - break; 5180 - case BTF_KIND_ENUM: 5181 - it->desc = (struct btf_field_desc) { 5182 - 1, {offsetof(struct btf_type, name_off)}, 5183 - sizeof(struct btf_enum), 5184 - 1, {offsetof(struct btf_enum, name_off)} 5185 - }; 5186 - break; 5187 - case BTF_KIND_ENUM64: 5188 - it->desc = (struct btf_field_desc) { 5189 - 1, {offsetof(struct btf_type, name_off)}, 5190 - sizeof(struct btf_enum64), 5191 - 1, {offsetof(struct btf_enum64, name_off)} 5192 - }; 5193 - break; 5194 - case BTF_KIND_STRUCT: 5195 - case BTF_KIND_UNION: 5196 - it->desc = (struct btf_field_desc) { 5197 - 1, {offsetof(struct btf_type, name_off)}, 5198 - sizeof(struct btf_member), 5199 - 1, {offsetof(struct btf_member, name_off)} 5200 - }; 5201 - break; 5202 - case BTF_KIND_FUNC_PROTO: 5203 - it->desc = (struct btf_field_desc) { 5204 - 1, {offsetof(struct btf_type, name_off)}, 5205 - sizeof(struct btf_param), 5206 - 1, {offsetof(struct btf_param, name_off)} 5207 - }; 5208 - break; 5209 - default: 5210 - return -EINVAL; 5211 - } 5212 - break; 5213 - default: 5214 - return -EINVAL; 5215 - } 5216 - 5217 - if (it->desc.m_sz) 5218 - it->vlen = btf_vlen(t); 5219 - 5220 - it->p = t; 5221 - return 0; 5222 - } 5223 - 5224 - __u32 *btf_field_iter_next(struct btf_field_iter *it) 5225 - { 5226 - if (!it->p) 5227 - return NULL; 5228 - 5229 - if (it->m_idx < 0) { 5230 - if (it->off_idx < it->desc.t_off_cnt) 5231 - return it->p + it->desc.t_offs[it->off_idx++]; 5232 - /* move to per-member iteration */ 5233 - it->m_idx = 0; 5234 - it->p += sizeof(struct btf_type); 5235 - it->off_idx = 0; 5236 - } 5237 - 5238 - /* if type doesn't have members, stop */ 5239 - if (it->desc.m_sz == 0) { 5240 - it->p = NULL; 5241 - return NULL; 5242 - } 5243 - 5244 - if (it->off_idx >= it->desc.m_off_cnt) { 5245 - /* exhausted this member's fields, go to the next member */ 5246 - it->m_idx++; 5247 - it->p += it->desc.m_sz; 5248 - it->off_idx = 0; 5249 - } 5250 - 5251 - if (it->m_idx < it->vlen) 5252 - return it->p + it->desc.m_offs[it->off_idx++]; 5253 - 5254 - it->p = NULL; 5255 - return NULL; 5256 - } 5257 - 5258 5096 int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx) 5259 5097 { 5260 5098 const struct btf_ext_info *seg;
+177
tools/lib/bpf/btf_iter.c
··· 1 + // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 2 + /* Copyright (c) 2021 Facebook */ 3 + /* Copyright (c) 2024, Oracle and/or its affiliates. */ 4 + 5 + #ifdef __KERNEL__ 6 + #include <linux/bpf.h> 7 + #include <linux/btf.h> 8 + 9 + #define btf_var_secinfos(t) (struct btf_var_secinfo *)btf_type_var_secinfo(t) 10 + 11 + #else 12 + #include "btf.h" 13 + #include "libbpf_internal.h" 14 + #endif 15 + 16 + int btf_field_iter_init(struct btf_field_iter *it, struct btf_type *t, 17 + enum btf_field_iter_kind iter_kind) 18 + { 19 + it->p = NULL; 20 + it->m_idx = -1; 21 + it->off_idx = 0; 22 + it->vlen = 0; 23 + 24 + switch (iter_kind) { 25 + case BTF_FIELD_ITER_IDS: 26 + switch (btf_kind(t)) { 27 + case BTF_KIND_UNKN: 28 + case BTF_KIND_INT: 29 + case BTF_KIND_FLOAT: 30 + case BTF_KIND_ENUM: 31 + case BTF_KIND_ENUM64: 32 + it->desc = (struct btf_field_desc) {}; 33 + break; 34 + case BTF_KIND_FWD: 35 + case BTF_KIND_CONST: 36 + case BTF_KIND_VOLATILE: 37 + case BTF_KIND_RESTRICT: 38 + case BTF_KIND_PTR: 39 + case BTF_KIND_TYPEDEF: 40 + case BTF_KIND_FUNC: 41 + case BTF_KIND_VAR: 42 + case BTF_KIND_DECL_TAG: 43 + case BTF_KIND_TYPE_TAG: 44 + it->desc = (struct btf_field_desc) { 1, {offsetof(struct btf_type, type)} }; 45 + break; 46 + case BTF_KIND_ARRAY: 47 + it->desc = (struct btf_field_desc) { 48 + 2, {sizeof(struct btf_type) + offsetof(struct btf_array, type), 49 + sizeof(struct btf_type) + offsetof(struct btf_array, index_type)} 50 + }; 51 + break; 52 + case BTF_KIND_STRUCT: 53 + case BTF_KIND_UNION: 54 + it->desc = (struct btf_field_desc) { 55 + 0, {}, 56 + sizeof(struct btf_member), 57 + 1, {offsetof(struct btf_member, type)} 58 + }; 59 + break; 60 + case BTF_KIND_FUNC_PROTO: 61 + it->desc = (struct btf_field_desc) { 62 + 1, {offsetof(struct btf_type, type)}, 63 + sizeof(struct btf_param), 64 + 1, {offsetof(struct btf_param, type)} 65 + }; 66 + break; 67 + case BTF_KIND_DATASEC: 68 + it->desc = (struct btf_field_desc) { 69 + 0, {}, 70 + sizeof(struct btf_var_secinfo), 71 + 1, {offsetof(struct btf_var_secinfo, type)} 72 + }; 73 + break; 74 + default: 75 + return -EINVAL; 76 + } 77 + break; 78 + case BTF_FIELD_ITER_STRS: 79 + switch (btf_kind(t)) { 80 + case BTF_KIND_UNKN: 81 + it->desc = (struct btf_field_desc) {}; 82 + break; 83 + case BTF_KIND_INT: 84 + case BTF_KIND_FLOAT: 85 + case BTF_KIND_FWD: 86 + case BTF_KIND_ARRAY: 87 + case BTF_KIND_CONST: 88 + case BTF_KIND_VOLATILE: 89 + case BTF_KIND_RESTRICT: 90 + case BTF_KIND_PTR: 91 + case BTF_KIND_TYPEDEF: 92 + case BTF_KIND_FUNC: 93 + case BTF_KIND_VAR: 94 + case BTF_KIND_DECL_TAG: 95 + case BTF_KIND_TYPE_TAG: 96 + case BTF_KIND_DATASEC: 97 + it->desc = (struct btf_field_desc) { 98 + 1, {offsetof(struct btf_type, name_off)} 99 + }; 100 + break; 101 + case BTF_KIND_ENUM: 102 + it->desc = (struct btf_field_desc) { 103 + 1, {offsetof(struct btf_type, name_off)}, 104 + sizeof(struct btf_enum), 105 + 1, {offsetof(struct btf_enum, name_off)} 106 + }; 107 + break; 108 + case BTF_KIND_ENUM64: 109 + it->desc = (struct btf_field_desc) { 110 + 1, {offsetof(struct btf_type, name_off)}, 111 + sizeof(struct btf_enum64), 112 + 1, {offsetof(struct btf_enum64, name_off)} 113 + }; 114 + break; 115 + case BTF_KIND_STRUCT: 116 + case BTF_KIND_UNION: 117 + it->desc = (struct btf_field_desc) { 118 + 1, {offsetof(struct btf_type, name_off)}, 119 + sizeof(struct btf_member), 120 + 1, {offsetof(struct btf_member, name_off)} 121 + }; 122 + break; 123 + case BTF_KIND_FUNC_PROTO: 124 + it->desc = (struct btf_field_desc) { 125 + 1, {offsetof(struct btf_type, name_off)}, 126 + sizeof(struct btf_param), 127 + 1, {offsetof(struct btf_param, name_off)} 128 + }; 129 + break; 130 + default: 131 + return -EINVAL; 132 + } 133 + break; 134 + default: 135 + return -EINVAL; 136 + } 137 + 138 + if (it->desc.m_sz) 139 + it->vlen = btf_vlen(t); 140 + 141 + it->p = t; 142 + return 0; 143 + } 144 + 145 + __u32 *btf_field_iter_next(struct btf_field_iter *it) 146 + { 147 + if (!it->p) 148 + return NULL; 149 + 150 + if (it->m_idx < 0) { 151 + if (it->off_idx < it->desc.t_off_cnt) 152 + return it->p + it->desc.t_offs[it->off_idx++]; 153 + /* move to per-member iteration */ 154 + it->m_idx = 0; 155 + it->p += sizeof(struct btf_type); 156 + it->off_idx = 0; 157 + } 158 + 159 + /* if type doesn't have members, stop */ 160 + if (it->desc.m_sz == 0) { 161 + it->p = NULL; 162 + return NULL; 163 + } 164 + 165 + if (it->off_idx >= it->desc.m_off_cnt) { 166 + /* exhausted this member's fields, go to the next member */ 167 + it->m_idx++; 168 + it->p += it->desc.m_sz; 169 + it->off_idx = 0; 170 + } 171 + 172 + if (it->m_idx < it->vlen) 173 + return it->p + it->desc.m_offs[it->off_idx++]; 174 + 175 + it->p = NULL; 176 + return NULL; 177 + }
+54 -41
tools/lib/bpf/btf_relocate.c
··· 5 5 #define _GNU_SOURCE 6 6 #endif 7 7 8 + #ifdef __KERNEL__ 9 + #include <linux/bpf.h> 10 + #include <linux/bsearch.h> 11 + #include <linux/btf.h> 12 + #include <linux/sort.h> 13 + #include <linux/string.h> 14 + #include <linux/bpf_verifier.h> 15 + 16 + #define btf_type_by_id (struct btf_type *)btf_type_by_id 17 + #define btf__type_cnt btf_nr_types 18 + #define btf__base_btf btf_base_btf 19 + #define btf__name_by_offset btf_name_by_offset 20 + #define btf__str_by_offset btf_str_by_offset 21 + #define btf_kflag btf_type_kflag 22 + 23 + #define calloc(nmemb, sz) kvcalloc(nmemb, sz, GFP_KERNEL | __GFP_NOWARN) 24 + #define free(ptr) kvfree(ptr) 25 + #define qsort(base, num, sz, cmp) sort(base, num, sz, cmp, NULL) 26 + 27 + #else 28 + 8 29 #include "btf.h" 9 30 #include "bpf.h" 10 31 #include "libbpf.h" 11 32 #include "libbpf_internal.h" 33 + 34 + #endif /* __KERNEL__ */ 12 35 13 36 struct btf; 14 37 ··· 183 160 */ 184 161 static int btf_relocate_map_distilled_base(struct btf_relocate *r) 185 162 { 186 - struct btf_name_info *dist_base_info_sorted, *dist_base_info_sorted_end; 163 + struct btf_name_info *info, *info_end; 187 164 struct btf_type *base_t, *dist_t; 188 165 __u8 *base_name_cnt = NULL; 189 166 int err = 0; ··· 192 169 /* generate a sort index array of name/type ids sorted by name for 193 170 * distilled base BTF to speed name-based lookups. 194 171 */ 195 - dist_base_info_sorted = calloc(r->nr_dist_base_types, sizeof(*dist_base_info_sorted)); 196 - if (!dist_base_info_sorted) { 172 + info = calloc(r->nr_dist_base_types, sizeof(*info)); 173 + if (!info) { 197 174 err = -ENOMEM; 198 175 goto done; 199 176 } 200 - dist_base_info_sorted_end = dist_base_info_sorted + r->nr_dist_base_types; 177 + info_end = info + r->nr_dist_base_types; 201 178 for (id = 0; id < r->nr_dist_base_types; id++) { 202 179 dist_t = btf_type_by_id(r->dist_base_btf, id); 203 - dist_base_info_sorted[id].name = btf__name_by_offset(r->dist_base_btf, 204 - dist_t->name_off); 205 - dist_base_info_sorted[id].id = id; 206 - dist_base_info_sorted[id].size = dist_t->size; 207 - dist_base_info_sorted[id].needs_size = true; 180 + info[id].name = btf__name_by_offset(r->dist_base_btf, dist_t->name_off); 181 + info[id].id = id; 182 + info[id].size = dist_t->size; 183 + info[id].needs_size = true; 208 184 } 209 - qsort(dist_base_info_sorted, r->nr_dist_base_types, sizeof(*dist_base_info_sorted), 210 - cmp_btf_name_size); 185 + qsort(info, r->nr_dist_base_types, sizeof(*info), cmp_btf_name_size); 211 186 212 187 /* Mark distilled base struct/union members of split BTF structs/unions 213 188 * in id_map with BTF_IS_EMBEDDED; this signals that these types 214 - * need to match both name and size, otherwise embeddding the base 189 + * need to match both name and size, otherwise embedding the base 215 190 * struct/union in the split type is invalid. 216 191 */ 217 192 for (id = r->nr_dist_base_types; id < r->nr_split_types; id++) { ··· 237 216 238 217 /* Now search base BTF for matching distilled base BTF types. */ 239 218 for (id = 1; id < r->nr_base_types; id++) { 240 - struct btf_name_info *dist_name_info, *dist_name_info_next = NULL; 241 - struct btf_name_info base_name_info = {}; 219 + struct btf_name_info *dist_info, base_info = {}; 242 220 int dist_kind, base_kind; 243 221 244 222 base_t = btf_type_by_id(r->base_btf, id); ··· 245 225 if (!base_t->name_off) 246 226 continue; 247 227 base_kind = btf_kind(base_t); 248 - base_name_info.id = id; 249 - base_name_info.name = btf__name_by_offset(r->base_btf, base_t->name_off); 228 + base_info.id = id; 229 + base_info.name = btf__name_by_offset(r->base_btf, base_t->name_off); 250 230 switch (base_kind) { 251 231 case BTF_KIND_INT: 252 232 case BTF_KIND_FLOAT: 253 233 case BTF_KIND_ENUM: 254 234 case BTF_KIND_ENUM64: 255 235 /* These types should match both name and size */ 256 - base_name_info.needs_size = true; 257 - base_name_info.size = base_t->size; 236 + base_info.needs_size = true; 237 + base_info.size = base_t->size; 258 238 break; 259 239 case BTF_KIND_FWD: 260 240 /* No size considerations for fwds. */ ··· 268 248 * unless corresponding _base_ types to match them are 269 249 * missing. 270 250 */ 271 - base_name_info.needs_size = base_name_cnt[base_t->name_off] > 1; 272 - base_name_info.size = base_t->size; 251 + base_info.needs_size = base_name_cnt[base_t->name_off] > 1; 252 + base_info.size = base_t->size; 273 253 break; 274 254 default: 275 255 continue; 276 256 } 277 257 /* iterate over all matching distilled base types */ 278 - for (dist_name_info = search_btf_name_size(&base_name_info, dist_base_info_sorted, 279 - r->nr_dist_base_types); 280 - dist_name_info != NULL; dist_name_info = dist_name_info_next) { 281 - /* Are there more distilled matches to process after 282 - * this one? 283 - */ 284 - dist_name_info_next = dist_name_info + 1; 285 - if (dist_name_info_next >= dist_base_info_sorted_end || 286 - cmp_btf_name_size(&base_name_info, dist_name_info_next)) 287 - dist_name_info_next = NULL; 288 - 289 - if (!dist_name_info->id || dist_name_info->id > r->nr_dist_base_types) { 258 + for (dist_info = search_btf_name_size(&base_info, info, r->nr_dist_base_types); 259 + dist_info != NULL && dist_info < info_end && 260 + cmp_btf_name_size(&base_info, dist_info) == 0; 261 + dist_info++) { 262 + if (!dist_info->id || dist_info->id >= r->nr_dist_base_types) { 290 263 pr_warn("base BTF id [%d] maps to invalid distilled base BTF id [%d]\n", 291 - id, dist_name_info->id); 264 + id, dist_info->id); 292 265 err = -EINVAL; 293 266 goto done; 294 267 } 295 - dist_t = btf_type_by_id(r->dist_base_btf, dist_name_info->id); 268 + dist_t = btf_type_by_id(r->dist_base_btf, dist_info->id); 296 269 dist_kind = btf_kind(dist_t); 297 270 298 271 /* Validate that the found distilled type is compatible. ··· 332 319 /* size verification is required for embedded 333 320 * struct/unions. 334 321 */ 335 - if (r->id_map[dist_name_info->id] == BTF_IS_EMBEDDED && 322 + if (r->id_map[dist_info->id] == BTF_IS_EMBEDDED && 336 323 base_t->size != dist_t->size) 337 324 continue; 338 325 break; 339 326 default: 340 327 continue; 341 328 } 342 - if (r->id_map[dist_name_info->id] && 343 - r->id_map[dist_name_info->id] != BTF_IS_EMBEDDED) { 329 + if (r->id_map[dist_info->id] && 330 + r->id_map[dist_info->id] != BTF_IS_EMBEDDED) { 344 331 /* we already have a match; this tells us that 345 332 * multiple base types of the same name 346 333 * have the same size, since for cases where ··· 350 337 * to in base BTF, so error out. 351 338 */ 352 339 pr_warn("distilled base BTF type '%s' [%u], size %u has multiple candidates of the same size (ids [%u, %u]) in base BTF\n", 353 - base_name_info.name, dist_name_info->id, 354 - base_t->size, id, r->id_map[dist_name_info->id]); 340 + base_info.name, dist_info->id, 341 + base_t->size, id, r->id_map[dist_info->id]); 355 342 err = -EINVAL; 356 343 goto done; 357 344 } 358 345 /* map id and name */ 359 - r->id_map[dist_name_info->id] = id; 346 + r->id_map[dist_info->id] = id; 360 347 r->str_map[dist_t->name_off] = base_t->name_off; 361 348 } 362 349 } ··· 375 362 } 376 363 done: 377 364 free(base_name_cnt); 378 - free(dist_base_info_sorted); 365 + free(info); 379 366 return err; 380 367 } 381 368
+46
tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
··· 159 159 { 160 160 } 161 161 162 + __bpf_kfunc struct bpf_testmod_ctx * 163 + bpf_testmod_ctx_create(int *err) 164 + { 165 + struct bpf_testmod_ctx *ctx; 166 + 167 + ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC); 168 + if (!ctx) { 169 + *err = -ENOMEM; 170 + return NULL; 171 + } 172 + refcount_set(&ctx->usage, 1); 173 + 174 + return ctx; 175 + } 176 + 177 + static void testmod_free_cb(struct rcu_head *head) 178 + { 179 + struct bpf_testmod_ctx *ctx; 180 + 181 + ctx = container_of(head, struct bpf_testmod_ctx, rcu); 182 + kfree(ctx); 183 + } 184 + 185 + __bpf_kfunc void bpf_testmod_ctx_release(struct bpf_testmod_ctx *ctx) 186 + { 187 + if (!ctx) 188 + return; 189 + if (refcount_dec_and_test(&ctx->usage)) 190 + call_rcu(&ctx->rcu, testmod_free_cb); 191 + } 192 + 162 193 struct bpf_testmod_btf_type_tag_1 { 163 194 int a; 164 195 }; ··· 400 369 BTF_ID_FLAGS(func, bpf_iter_testmod_seq_destroy, KF_ITER_DESTROY) 401 370 BTF_ID_FLAGS(func, bpf_kfunc_common_test) 402 371 BTF_ID_FLAGS(func, bpf_kfunc_dynptr_test) 372 + BTF_ID_FLAGS(func, bpf_testmod_ctx_create, KF_ACQUIRE | KF_RET_NULL) 373 + BTF_ID_FLAGS(func, bpf_testmod_ctx_release, KF_RELEASE) 403 374 BTF_KFUNCS_END(bpf_testmod_common_kfunc_ids) 375 + 376 + BTF_ID_LIST(bpf_testmod_dtor_ids) 377 + BTF_ID(struct, bpf_testmod_ctx) 378 + BTF_ID(func, bpf_testmod_ctx_release) 404 379 405 380 static const struct btf_kfunc_id_set bpf_testmod_common_kfunc_set = { 406 381 .owner = THIS_MODULE, ··· 941 904 942 905 static int bpf_testmod_init(void) 943 906 { 907 + const struct btf_id_dtor_kfunc bpf_testmod_dtors[] = { 908 + { 909 + .btf_id = bpf_testmod_dtor_ids[0], 910 + .kfunc_btf_id = bpf_testmod_dtor_ids[1] 911 + }, 912 + }; 944 913 int ret; 945 914 946 915 ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_UNSPEC, &bpf_testmod_common_kfunc_set); ··· 955 912 ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &bpf_testmod_kfunc_set); 956 913 ret = ret ?: register_bpf_struct_ops(&bpf_bpf_testmod_ops, bpf_testmod_ops); 957 914 ret = ret ?: register_bpf_struct_ops(&bpf_testmod_ops2, bpf_testmod_ops2); 915 + ret = ret ?: register_btf_id_dtor_kfuncs(bpf_testmod_dtors, 916 + ARRAY_SIZE(bpf_testmod_dtors), 917 + THIS_MODULE); 958 918 if (ret < 0) 959 919 return ret; 960 920 if (bpf_fentry_test1(0) < 0)
+9
tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h
··· 80 80 int msglen; 81 81 }; 82 82 83 + struct bpf_testmod_ctx { 84 + struct callback_head rcu; 85 + refcount_t usage; 86 + }; 87 + 83 88 struct prog_test_ref_kfunc * 84 89 bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr) __ksym; 85 90 void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; ··· 140 135 int bpf_kfunc_call_kernel_getpeername(struct addr_args *args) __ksym; 141 136 142 137 void bpf_kfunc_dynptr_test(struct bpf_dynptr *ptr, struct bpf_dynptr *ptr__nullable) __ksym; 138 + 139 + struct bpf_testmod_ctx *bpf_testmod_ctx_create(int *err) __ksym; 140 + void bpf_testmod_ctx_release(struct bpf_testmod_ctx *ctx) __ksym; 141 + 143 142 #endif /* _BPF_TESTMOD_KFUNC_H */
+1
tools/testing/selftests/bpf/prog_tests/kfunc_call.c
··· 78 78 SYSCALL_TEST(kfunc_syscall_test, 0), 79 79 SYSCALL_NULL_CTX_TEST(kfunc_syscall_test_null, 0), 80 80 TC_TEST(kfunc_call_test_static_unused_arg, 0), 81 + TC_TEST(kfunc_call_ctx, 0), 81 82 }; 82 83 83 84 struct syscall_test_args {
+37
tools/testing/selftests/bpf/progs/kfunc_call_test.c
··· 177 177 return actual != expected ? -1 : 0; 178 178 } 179 179 180 + struct ctx_val { 181 + struct bpf_testmod_ctx __kptr *ctx; 182 + }; 183 + 184 + struct { 185 + __uint(type, BPF_MAP_TYPE_ARRAY); 186 + __uint(max_entries, 1); 187 + __type(key, int); 188 + __type(value, struct ctx_val); 189 + } ctx_map SEC(".maps"); 190 + 191 + SEC("tc") 192 + int kfunc_call_ctx(struct __sk_buff *skb) 193 + { 194 + struct bpf_testmod_ctx *ctx; 195 + int err = 0; 196 + 197 + ctx = bpf_testmod_ctx_create(&err); 198 + if (!ctx && !err) 199 + err = -1; 200 + if (ctx) { 201 + int key = 0; 202 + struct ctx_val *ctx_val = bpf_map_lookup_elem(&ctx_map, &key); 203 + 204 + /* Transfer ctx to map to be freed via implicit dtor call 205 + * on cleanup. 206 + */ 207 + if (ctx_val) 208 + ctx = bpf_kptr_xchg(&ctx_val->ctx, ctx); 209 + if (ctx) { 210 + bpf_testmod_ctx_release(ctx); 211 + err = -1; 212 + } 213 + } 214 + return err; 215 + } 216 + 180 217 char _license[] SEC("license") = "GPL";