From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: Usama Arif <usama.arif@bytedance.com>
Cc: bpf@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net,
andrii.nakryiko@gmail.com, fam.zheng@bytedance.com,
cong.wang@bytedance.com, song@kernel.org
Subject: Re: [RFC bpf-next 1/3] bpf: btf: Introduce infrastructure for module helpers
Date: Sat, 22 Jan 2022 08:53:39 +0530 [thread overview]
Message-ID: <20220122032053.pb7lk5wvrfg2bo75@thp> (raw)
In-Reply-To: <20220121193956.198120-2-usama.arif@bytedance.com>
On Sat, Jan 22, 2022 at 01:09:54AM IST, Usama Arif wrote:
> This adds support for calling helper functions in eBPF applications
> that have been declared in a kernel module. The corresponding
> verifier changes for module helpers will be added in a later patch.
>
> Module helpers are useful as:
> - They support more argument and return types when compared to module
> kfunc.
> - This adds a way to have helper functions that would be too specialized
> for a specific usecase to merge upstream, but are functions that can have
> a constant API and can be maintained in-kernel modules.
> - The number of in-kernel helpers have grown to a large number
> (187 at the time of writing this commit). Having module helper functions
> could possibly reduce the number of in-kernel helper functions growing
> in the future and maintained upstream.
>
> When the kernel module registers the helper, the module owner,
> BTF id set of the function and function proto is stored as part of a
> btf_mod_helper entry in a btf_mod_helper_list which is part of
> struct btf. This entry can be removed in the unregister function
> while exiting the module, and can be used by the bpf verifier to
> check the helper call and get function proto.
>
> Signed-off-by: Usama Arif <usama.arif@bytedance.com>
> ---
> include/linux/btf.h | 44 +++++++++++++++++++++++
> kernel/bpf/btf.c | 88 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 132 insertions(+)
>
> diff --git a/include/linux/btf.h b/include/linux/btf.h
> index b12cfe3b12bb..c3a814404112 100644
> --- a/include/linux/btf.h
> +++ b/include/linux/btf.h
> @@ -40,6 +40,18 @@ struct btf_kfunc_id_set {
> };
> };
>
> +struct btf_mod_helper {
> + struct list_head list;
> + struct module *owner;
> + struct btf_id_set *set;
> + struct bpf_func_proto *func_proto;
> +};
> +
> +struct btf_mod_helper_list {
> + struct list_head list;
> + struct mutex mutex;
> +};
> +
> extern const struct file_operations btf_fops;
>
> void btf_get(struct btf *btf);
> @@ -359,4 +371,36 @@ static inline int register_btf_kfunc_id_set(enum bpf_prog_type prog_type,
> }
> #endif
>
> +#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
> +int register_mod_helper(struct btf_mod_helper *mod_helper);
> +int unregister_mod_helper(struct btf_mod_helper *mod_helper);
> +const struct bpf_func_proto *get_mod_helper_proto(const struct btf *btf,
> + const u32 kfunc_btf_id);
> +
> +#define DEFINE_MOD_HELPER(mod_helper, owner, helper_func, func_proto) \
> +BTF_SET_START(helper_func##__id_set) \
> +BTF_ID(func, helper_func) \
> +BTF_SET_END(helper_func##__id_set) \
> +struct btf_mod_helper mod_helper = { \
> + LIST_HEAD_INIT(mod_helper.list), \
> + (owner), \
> + (&(helper_func##__id_set)), \
> + (&(func_proto)) \
> +}
This macro needs to be outside the ifdef, otherwise when
CONFIG_DEBUG_INFO_BTF_MODULES is not set, code will fail to compile. Also, I
would use static and const on the variable, so that compiler can optimize it out
when the config option is disabled.
> +#else
> +int register_mod_helper(struct btf_mod_helper *mod_helper)
> +{
> + return -EPERM;
> +}
> +int unregister_mod_helper(struct btf_mod_helper *mod_helper)
> +{
> + return -EPERM;
> +}
> +const struct bpf_func_proto *get_mod_helper_proto(const struct btf *btf,
> + const u32 kfunc_btf_id)
> +{
> + return NULL;
> +}
In the else block, these need to be static inline functions, otherwise you'll
get a warning and link time error because the same symbol will be present in
multiple objects.
> +#endif
> +
> #endif
> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index 57f5fd5af2f9..f9aa6ba85f3f 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -228,6 +228,7 @@ struct btf {
> u32 id;
> struct rcu_head rcu;
> struct btf_kfunc_set_tab *kfunc_set_tab;
> + struct btf_mod_helper_list *mod_helper_list;
What will free this struct when btf goes away? I don't see any cleanup code in
btf_free.
>
> /* split BTF support */
> struct btf *base_btf;
> @@ -6752,6 +6753,93 @@ int register_btf_kfunc_id_set(enum bpf_prog_type prog_type,
> }
> EXPORT_SYMBOL_GPL(register_btf_kfunc_id_set);
>
> +#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
> +int register_mod_helper(struct btf_mod_helper *mod_helper)
> +{
> + struct btf_mod_helper *s;
> + struct btf *btf;
> + struct btf_mod_helper_list *mod_helper_list;
> +
> + btf = btf_get_module_btf(mod_helper->owner);
> + if (!btf_is_module(btf)) {
You need to check for IS_ERR_OR_NULL before calling btf_is_module.
Also, this would fail if the module is compiled as built-in, because
mod_helper->owner will be NULL, and btf_get_module_btf will return btf_vmlinux.
> + pr_err("%s can only be called from kernel module", __func__);
> + return -EINVAL;
> + }
> +
> + if (IS_ERR_OR_NULL(btf))
> + return btf ? PTR_ERR(btf) : -ENOENT;
> +
> + mod_helper_list = btf->mod_helper_list;
> + if (!mod_helper_list) {
> + mod_helper_list = kzalloc(sizeof(*mod_helper_list), GFP_KERNEL | __GFP_NOWARN);
> + if (!mod_helper_list)
> + return -ENOMEM;
Here, you are not doing btf_put for module btf. Also, you'll have to guard the
btf_put with `if (btf_is_module(btf))` because reference is not raised for
btf_vmlinux.
> + INIT_LIST_HEAD(&mod_helper_list->list);
> + mutex_init(&mod_helper_list->mutex);
> + btf->mod_helper_list = mod_helper_list;
> + }
> +
> + // Check if btf id is already registered
No C++ style comments.
> + mutex_lock(&mod_helper_list->mutex);
> + list_for_each_entry(s, &mod_helper_list->list, list) {
> + if (mod_helper->set->ids[0] == s->set->ids[0]) {
> + pr_warn("Dynamic helper %u is already registered\n", s->set->ids[0]);
> + mutex_unlock(&mod_helper_list->mutex);
> + return -EINVAL;
Need to free mod_helper_list and conditionally btf_put before returning.
> + }
> + }
> + list_add(&mod_helper->list, &mod_helper_list->list);
> + mutex_unlock(&mod_helper_list->mutex);
> + btf_put(btf);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(register_mod_helper);
> +
> +int unregister_mod_helper(struct btf_mod_helper *mod_helper)
> +{
> + struct btf *btf;
> + struct btf_mod_helper_list *mod_helper_list;
> +
> + btf = btf_get_module_btf(mod_helper->owner);
> + if (!btf_is_module(btf)) {
Same error as above, need the IS_ERR_OR_NULL check to be before this.
> + pr_err("%s can only be called from kernel module", __func__);
> + return -EINVAL;
> + }
> +
> + if (IS_ERR_OR_NULL(btf))
> + return btf ? PTR_ERR(btf) : -ENOENT;
> +
> + mod_helper_list = btf->mod_helper_list;
> + mutex_lock(&mod_helper_list->mutex);
> + list_del(&mod_helper->list);
> + mutex_unlock(&mod_helper_list->mutex);
> + btf_put(btf);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(unregister_mod_helper);
> +const struct bpf_func_proto *get_mod_helper_proto(const struct btf *btf, const u32 kfunc_btf_id)
> +{
> + struct btf_mod_helper *s;
> + struct btf_mod_helper_list *mod_helper_list;
> +
> + mod_helper_list = btf->mod_helper_list;
> + if (!mod_helper_list)
> + return NULL;
> +
> + mutex_lock(&mod_helper_list->mutex);
> + list_for_each_entry(s, &mod_helper_list->list, list) {
> + if (s->set->ids[0] == kfunc_btf_id) {
If there is only one BTF ID, I think you can just use BTF_ID_LIST instead.
> + mutex_unlock(&mod_helper_list->mutex);
> + return s->func_proto;
> + }
> + }
> + mutex_unlock(&mod_helper_list->mutex);
> + return NULL;
> +}
> +#endif /* CONFIG_DEBUG_INFO_BTF_MODULES */
> +
> int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
> const struct btf *targ_btf, __u32 targ_id)
> {
> --
> 2.25.1
>
next prev parent reply other threads:[~2022-01-22 3:23 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-21 19:39 [RFC bpf-next 0/3] bpf: Introduce module helper functions Usama Arif
2022-01-21 19:39 ` [RFC bpf-next 1/3] bpf: btf: Introduce infrastructure for module helpers Usama Arif
2022-01-21 22:47 ` kernel test robot
2022-01-21 22:47 ` kernel test robot
2022-01-21 22:47 ` kernel test robot
2022-01-21 22:47 ` kernel test robot
2022-01-22 3:23 ` Kumar Kartikeya Dwivedi [this message]
2022-01-21 19:39 ` [RFC bpf-next 2/3] bpf: add support for module helpers in verifier Usama Arif
2022-01-22 3:31 ` Kumar Kartikeya Dwivedi
2022-01-22 3:56 ` Kumar Kartikeya Dwivedi
2022-01-24 16:23 ` Usama Arif
2022-01-21 19:39 ` [RFC bpf-next 3/3] selftests/bpf: add test for module helper Usama Arif
2022-01-21 22:48 ` [RFC bpf-next 0/3] bpf: Introduce module helper functions Alexei Starovoitov
2022-01-22 4:04 ` Kumar Kartikeya Dwivedi
2022-01-24 16:33 ` [External] " Usama Arif
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220122032053.pb7lk5wvrfg2bo75@thp \
--to=memxor@gmail.com \
--cc=andrii.nakryiko@gmail.com \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=cong.wang@bytedance.com \
--cc=daniel@iogearbox.net \
--cc=fam.zheng@bytedance.com \
--cc=song@kernel.org \
--cc=usama.arif@bytedance.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.