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.

veristat: Load struct_ops programs only once

libbpf automatically adjusts autoload for struct_ops programs,
see libbpf.c:bpf_object_adjust_struct_ops_autoload.

For example, if there is a map:

SEC(".struct_ops.link")
struct sched_ext_ops ops = {
.enqueue = foo,
.tick = bar,
};

Both 'foo' and 'bar' would be loaded if 'ops' autocreate is true,
both 'foo' and 'bar' would be skipped if 'ops' autocreate is false.

This means that when veristat processes object file with 'ops',
it would load 4 programs in total: two programs per each
'process_prog' call.

The adjustment occurs at object load time, and libbpf remembers
association between 'ops' and 'foo'/'bar' at object open time.
The only way to persuade libbpf to load one of two is to adjust map
initial value, such that only one program is referenced.
This patch does exactly that, significantly reducing time to process
object files with big number of struct_ops programs.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20250115223835.919989-1-eddyz87@gmail.com

authored by

Eduard Zingerman and committed by
Andrii Nakryiko
7c311b7c a8d1c48d

+38
+38
tools/testing/selftests/bpf/veristat.c
··· 1062 1062 return -ESRCH; 1063 1063 } 1064 1064 1065 + /* Make sure only target program is referenced from struct_ops map, 1066 + * otherwise libbpf would automatically set autocreate for all 1067 + * referenced programs. 1068 + * See libbpf.c:bpf_object_adjust_struct_ops_autoload. 1069 + */ 1070 + static void mask_unrelated_struct_ops_progs(struct bpf_object *obj, 1071 + struct bpf_map *map, 1072 + struct bpf_program *prog) 1073 + { 1074 + struct btf *btf = bpf_object__btf(obj); 1075 + const struct btf_type *t, *mt; 1076 + struct btf_member *m; 1077 + int i, moff; 1078 + size_t data_sz, ptr_sz = sizeof(void *); 1079 + void *data; 1080 + 1081 + t = btf__type_by_id(btf, bpf_map__btf_value_type_id(map)); 1082 + if (!btf_is_struct(t)) 1083 + return; 1084 + 1085 + data = bpf_map__initial_value(map, &data_sz); 1086 + for (i = 0; i < btf_vlen(t); i++) { 1087 + m = &btf_members(t)[i]; 1088 + mt = btf__type_by_id(btf, m->type); 1089 + if (!btf_is_ptr(mt)) 1090 + continue; 1091 + moff = m->offset / 8; 1092 + if (moff + ptr_sz > data_sz) 1093 + continue; 1094 + if (memcmp(data + moff, &prog, ptr_sz) == 0) 1095 + continue; 1096 + memset(data + moff, 0, ptr_sz); 1097 + } 1098 + } 1099 + 1065 1100 static void fixup_obj(struct bpf_object *obj, struct bpf_program *prog, const char *filename) 1066 1101 { 1067 1102 struct bpf_map *map; ··· 1111 1076 case BPF_MAP_TYPE_TASK_STORAGE: 1112 1077 case BPF_MAP_TYPE_INODE_STORAGE: 1113 1078 case BPF_MAP_TYPE_CGROUP_STORAGE: 1079 + break; 1080 + case BPF_MAP_TYPE_STRUCT_OPS: 1081 + mask_unrelated_struct_ops_progs(obj, map, prog); 1114 1082 break; 1115 1083 default: 1116 1084 if (bpf_map__max_entries(map) == 0)