On Fri, Apr 15, 2022 at 9:30 PM Kui-Feng Lee <kuifeng@xxxxxx> wrote: > > Replace struct bpf_tramp_progs with struct bpf_tramp_links to collect > struct bpf_tramp_link(s) for a trampoline. struct bpf_tramp_link > extends bpf_link to act as a linked list node. > > arch_prepare_bpf_trampoline() accepts a struct bpf_tramp_links to > collects all bpf_tramp_link(s) that a trampoline should call. > > Change BPF trampoline and bpf_struct_ops to pass bpf_tramp_links > instead of bpf_tramp_progs. > > Signed-off-by: Kui-Feng Lee <kuifeng@xxxxxx> > --- > arch/x86/net/bpf_jit_comp.c | 36 +++++++++-------- > include/linux/bpf.h | 36 +++++++++++------ > include/linux/bpf_types.h | 1 + > include/uapi/linux/bpf.h | 1 + > kernel/bpf/bpf_struct_ops.c | 69 ++++++++++++++++++++++---------- > kernel/bpf/syscall.c | 23 ++++------- > kernel/bpf/trampoline.c | 73 +++++++++++++++++++--------------- > net/bpf/bpf_dummy_struct_ops.c | 37 ++++++++++++++--- > tools/bpf/bpftool/link.c | 1 + > tools/include/uapi/linux/bpf.h | 1 + > 10 files changed, 175 insertions(+), 103 deletions(-) > [...] > @@ -385,6 +399,7 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, > for_each_member(i, t, member) { > const struct btf_type *mtype, *ptype; > struct bpf_prog *prog; > + struct bpf_tramp_link *link; > u32 moff; > > moff = __btf_member_bit_offset(t, member) / 8; > @@ -438,16 +453,26 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, > err = PTR_ERR(prog); > goto reset_unlock; > } > - st_map->progs[i] = prog; > > if (prog->type != BPF_PROG_TYPE_STRUCT_OPS || > prog->aux->attach_btf_id != st_ops->type_id || > prog->expected_attach_type != i) { > + bpf_prog_put(prog); > err = -EINVAL; > goto reset_unlock; > } > > - err = bpf_struct_ops_prepare_trampoline(tprogs, prog, > + link = kzalloc(sizeof(*link), GFP_USER); seems like you are leaking this link and all the links allocated in previous successful iterations of this loop? > + if (!link) { > + bpf_prog_put(prog); > + err = -ENOMEM; > + goto reset_unlock; > + } > + bpf_link_init(&link->link, BPF_LINK_TYPE_STRUCT_OPS, > + &bpf_struct_ops_link_lops, prog); > + st_map->links[i] = &link->link; > + > + err = bpf_struct_ops_prepare_trampoline(tlinks, link, > &st_ops->func_models[i], > image, image_end); > if (err < 0) > @@ -490,7 +515,7 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, > memset(uvalue, 0, map->value_size); > memset(kvalue, 0, map->value_size); > unlock: > - kfree(tprogs); > + kfree(tlinks); so you'll need to free those links inside tlinks (or wherever else they are stored) > mutex_unlock(&st_map->lock); > return err; > } > @@ -545,9 +570,9 @@ static void bpf_struct_ops_map_free(struct bpf_map *map) > { > struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map; > > - if (st_map->progs) > + if (st_map->links) > bpf_struct_ops_map_put_progs(st_map); > - bpf_map_area_free(st_map->progs); > + bpf_map_area_free(st_map->links); > bpf_jit_free_exec(st_map->image); > bpf_map_area_free(st_map->uvalue); > bpf_map_area_free(st_map); [...] > @@ -105,10 +120,20 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, > } > set_vm_flush_reset_perms(image); > > + link = kzalloc(sizeof(*link), GFP_USER); > + if (!link) { > + err = -ENOMEM; > + goto out; > + } > + /* prog doesn't take the ownership of the reference from caller */ > + bpf_prog_inc(prog); > + bpf_link_init(&link->link, BPF_LINK_TYPE_STRUCT_OPS, &bpf_struct_ops_link_lops, prog); > + > op_idx = prog->expected_attach_type; > - err = bpf_struct_ops_prepare_trampoline(tprogs, prog, > + err = bpf_struct_ops_prepare_trampoline(tlinks, link, > &st_ops->func_models[op_idx], > image, image + PAGE_SIZE); > + nit: no need for extra empty line here > if (err < 0) > goto out; > > @@ -124,7 +149,9 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, > out: > kfree(args); > bpf_jit_free_exec(image); > - kfree(tprogs); > + if (link) > + bpf_link_put(&link->link); you never to bpf_link_prime() and bpf_link_settle() for these "pseudo links" for struct_ops, so there is no need for bpf_link_put(), it can be just bpf_link_free(), right? > + kfree(tlinks); > return err; > } > > diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c > index 8fb0116f9136..6353a789322b 100644 > --- a/tools/bpf/bpftool/link.c > +++ b/tools/bpf/bpftool/link.c > @@ -23,6 +23,7 @@ static const char * const link_type_name[] = { > [BPF_LINK_TYPE_XDP] = "xdp", > [BPF_LINK_TYPE_PERF_EVENT] = "perf_event", > [BPF_LINK_TYPE_KPROBE_MULTI] = "kprobe_multi", > + [BPF_LINK_TYPE_STRUCT_OPS] = "struct_ops", > }; > > static struct hashmap *link_table; > diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h > index d14b10b85e51..a4f557338af7 100644 > --- a/tools/include/uapi/linux/bpf.h > +++ b/tools/include/uapi/linux/bpf.h > @@ -1013,6 +1013,7 @@ enum bpf_link_type { > BPF_LINK_TYPE_XDP = 6, > BPF_LINK_TYPE_PERF_EVENT = 7, > BPF_LINK_TYPE_KPROBE_MULTI = 8, > + BPF_LINK_TYPE_STRUCT_OPS = 9, > > MAX_BPF_LINK_TYPE, > }; > -- > 2.30.2 >