On Thu, Feb 08, 2024 at 06:37:49PM -0800, thinker.li@xxxxxxxxx wrote: SNIP > enum bpf_struct_ops_state { > @@ -1790,6 +1806,7 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, > struct btf *btf, > struct bpf_verifier_log *log); > void bpf_map_struct_ops_info_fill(struct bpf_map_info *info, struct bpf_map *map); > +void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_ops_desc); > #else > #define register_bpf_struct_ops(st_ops, type) ({ (void *)(st_ops); 0; }) > static inline bool bpf_try_module_get(const void *data, struct module *owner) > @@ -1814,6 +1831,10 @@ static inline void bpf_map_struct_ops_info_fill(struct bpf_map_info *info, struc > { > } > > +static inline void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_ops_desc, int len) > +{ > +} extra len argument? jirka SNIP > +/* Clean up the arg_info in a struct bpf_struct_ops_desc. */ > +void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_ops_desc) > +{ > + struct bpf_struct_ops_arg_info *arg_info; > + int i; > + > + arg_info = st_ops_desc->arg_info; > + if (!arg_info) > + return; > + > + for (i = 0; i < btf_type_vlen(st_ops_desc->type); i++) > + kfree(arg_info[i].info); > + > + kfree(arg_info); > +} > + > int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, > struct btf *btf, > struct bpf_verifier_log *log) > { > struct bpf_struct_ops *st_ops = st_ops_desc->st_ops; > + struct bpf_struct_ops_arg_info *arg_info; > const struct btf_member *member; > const struct btf_type *t; > s32 type_id, value_id; > char value_name[128]; > const char *mname; > - int i; > + int i, err; > > if (strlen(st_ops->name) + VALUE_PREFIX_LEN >= > sizeof(value_name)) { > @@ -160,6 +320,17 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, > if (!is_valid_value_type(btf, value_id, t, value_name)) > return -EINVAL; > > + arg_info = kcalloc(btf_type_vlen(t), sizeof(*arg_info), > + GFP_KERNEL); > + if (!arg_info) > + return -ENOMEM; > + > + st_ops_desc->arg_info = arg_info; > + st_ops_desc->type = t; > + st_ops_desc->type_id = type_id; > + st_ops_desc->value_id = value_id; > + st_ops_desc->value_type = btf_type_by_id(btf, value_id); > + > for_each_member(i, t, member) { > const struct btf_type *func_proto; > > @@ -167,40 +338,52 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, > if (!*mname) { > pr_warn("anon member in struct %s is not supported\n", > st_ops->name); > - return -EOPNOTSUPP; > + err = -EOPNOTSUPP; > + goto errout; > } > > if (__btf_member_bitfield_size(t, member)) { > pr_warn("bit field member %s in struct %s is not supported\n", > mname, st_ops->name); > - return -EOPNOTSUPP; > + err = -EOPNOTSUPP; > + goto errout; > } > > func_proto = btf_type_resolve_func_ptr(btf, > member->type, > NULL); > - if (func_proto && > - btf_distill_func_proto(log, btf, > + if (!func_proto) > + continue; > + > + if (btf_distill_func_proto(log, btf, > func_proto, mname, > &st_ops->func_models[i])) { > pr_warn("Error in parsing func ptr %s in struct %s\n", > mname, st_ops->name); > - return -EINVAL; > + err = -EINVAL; > + goto errout; > } > + > + err = prepare_arg_info(btf, st_ops->name, mname, > + func_proto, > + arg_info + i); > + if (err) > + goto errout; > } > > if (st_ops->init(btf)) { > pr_warn("Error in init bpf_struct_ops %s\n", > st_ops->name); > - return -EINVAL; > + err = -EINVAL; > + goto errout; > } > > - st_ops_desc->type_id = type_id; > - st_ops_desc->type = t; > - st_ops_desc->value_id = value_id; > - st_ops_desc->value_type = btf_type_by_id(btf, value_id); > - > return 0; > + > +errout: > + bpf_struct_ops_desc_release(st_ops_desc); > + > + return err; > } > > static int bpf_struct_ops_map_get_next_key(struct bpf_map *map, void *key, > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c > index db53bb76387e..533f02b92c94 100644 > --- a/kernel/bpf/btf.c > +++ b/kernel/bpf/btf.c > @@ -1699,6 +1699,13 @@ static void btf_free_struct_meta_tab(struct btf *btf) > static void btf_free_struct_ops_tab(struct btf *btf) > { > struct btf_struct_ops_tab *tab = btf->struct_ops_tab; > + int i; > + > + if (!tab) > + return; > + > + for (i = 0; i < tab->cnt; i++) > + bpf_struct_ops_desc_release(&tab->ops[i]); > > kfree(tab); > btf->struct_ops_tab = NULL; > @@ -6130,6 +6137,26 @@ static bool prog_args_trusted(const struct bpf_prog *prog) > } > } > > +int btf_ctx_arg_offset(struct btf *btf, const struct btf_type *func_proto, > + u32 arg_no) > +{ > + const struct btf_param *args; > + const struct btf_type *t; > + int off = 0, i; > + u32 sz; > + > + args = btf_params(func_proto); > + for (i = 0; i < arg_no; i++) { > + t = btf_type_by_id(btf, args[i].type); > + t = btf_resolve_size(btf, t, &sz); > + if (IS_ERR(t)) > + return PTR_ERR(t); > + off += roundup(sz, 8); > + } > + > + return off; > +} > + > bool btf_ctx_access(int off, int size, enum bpf_access_type type, > const struct bpf_prog *prog, > struct bpf_insn_access_aux *info) > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index c92d6af7d975..72ca27f49616 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -20419,6 +20419,12 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env) > } > } > > + /* btf_ctx_access() used this to provide argument type info */ > + prog->aux->ctx_arg_info = > + st_ops_desc->arg_info[member_idx].info; > + prog->aux->ctx_arg_info_size = > + st_ops_desc->arg_info[member_idx].cnt; > + > prog->aux->attach_func_proto = func_proto; > prog->aux->attach_func_name = mname; > env->ops = st_ops->verifier_ops; > -- > 2.34.1 > >