All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alan Maguire <alan.maguire@oracle.com>
To: Fuyu Zhao <zhaofuyu@vivo.com>, bpf@vger.kernel.org
Cc: eddyz87@gmail.com, andrii.nakryiko@gmail.com
Subject: Re: [PATCH bpf-next v6 1/2] libbpf: support selective kernel module BTF loading via bpf_object_open_opts
Date: Mon, 31 Aug 2026 15:46:47 +0100	[thread overview]
Message-ID: <ccb5d732-90ef-4acb-b11d-75da7f1d21ce@oracle.com> (raw)
In-Reply-To: <20260831133809.1161-2-zhaofuyu@vivo.com>



On 31/08/2026 14:38, Fuyu Zhao wrote:
> 
> Add btf_module_names and nr_btf_module_names fields to
> bpf_object_open_opts to support selective kernel module BTF loading.
> 
> With btf_module_names:
> - when provided, only the specified kernel module BTFs are loaded;
> - when an empty list is provided, no module BTFs are loaded;
> - when NULL, all module BTFs are loaded as before.
> 
> This avoids unnecessary module BTF loading and reduces BPF object
> loading time when only a subset of kernel module BTFs is needed.
> 
> Suggested-by: Andrii Nakryiko <andrii.nakryiko@gmail.com>
> Signed-off-by: Fuyu Zhao <zhaofuyu@vivo.com>
> ---
>  tools/lib/bpf/libbpf.c | 117 +++++++++++++++++++++++++++++++++++++++++
>  tools/lib/bpf/libbpf.h |  24 ++++++++-
>  2 files changed, 140 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 514e4e9daa82..e19d0afd2592 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -779,6 +779,9 @@ struct bpf_object {
>  	char *token_path;
>  	int token_fd;
>  
> +	char **btf_module_names;
> +	size_t nr_btf_module_names;
> +
>  	char path[];
>  };
>  
> @@ -5803,6 +5806,103 @@ int bpf_core_add_cands(struct bpf_core_cand *local_cand,
>  	return 0;
>  }
>  
> +static void bpf_object_free_btf_module_names(struct bpf_object *obj)
> +{
> +	size_t i;
> +
> +	if (!obj->btf_module_names)
> +		return;
> +
> +	for (i = 0; i < obj->nr_btf_module_names; i++)
> +		zfree(&obj->btf_module_names[i]);
> +	zfree(&obj->btf_module_names);
> +	obj->nr_btf_module_names = 0;
> +}
> +
> +static int bpf_object_init_btf_module_names(struct bpf_object *obj,
> +					    const struct bpf_object_open_opts *opts)
> +{
> +	const char **names;
> +	size_t i, j, cnt;
> +	int err;
> +
> +	names = OPTS_GET(opts, btf_module_names, NULL);
> +	if (!names)
> +		return 0;
> +
> +	cnt = OPTS_GET(opts, nr_btf_module_names, 0);
> +
> +	/*
> +	 * Allocate one entry for an empty list to distinguish it from the
> +	 * default behavior.
> +	 */
> +	obj->btf_module_names = calloc(cnt ?: 1,
> +				       sizeof(*obj->btf_module_names));
> +	if (!obj->btf_module_names)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < cnt; i++) {
> +		if (!names[i] || !names[i][0]) {
> +			pr_warn("invalid kernel module BTF name at index %zu\n", i);
> +			err = -EINVAL;
> +			goto err_out;
> +		}
> +
> +		/*
> +		 * The list is expected to be small, so a simple nested scan is
> +		 * sufficient for duplicate detection.
> +		 */
> +		for (j = 0; j < i; j++) {
> +			if (strcmp(obj->btf_module_names[j], names[i]) == 0) {
> +				pr_warn("duplicate kernel module BTF name '%s'\n",
> +					names[i]);
> +				err = -EINVAL;
> +				goto err_out;
> +			}
> +		}
> +
> +		obj->btf_module_names[i] = strdup(names[i]);
> +		if (!obj->btf_module_names[i]) {
> +			err = -ENOMEM;
> +			goto err_out;
> +		}
> +
> +		obj->nr_btf_module_names++;
> +	}
> +	return 0;
> +
> +err_out:
> +	bpf_object_free_btf_module_names(obj);
> +	return err;
> +}
> +
> +static bool is_module_btf_needed(const struct bpf_object *obj, const char *name)
> +{
> +	size_t i;
> +
> +	if (!obj->btf_module_names)
> +		return true;
> +
> +	for (i = 0; i < obj->nr_btf_module_names; i++) {
> +		if (strcmp(obj->btf_module_names[i], name) == 0)
> +			return true;
> +	}
> +
> +	pr_debug("skipping module BTF '%s', not in btf_module_names\n", name);
> +	return false;
> +}
> +
> +static bool no_module_btfs_needed(const struct bpf_object *obj)
> +{
> +	return obj->btf_module_names && !obj->nr_btf_module_names;
> +}
> +
> +static bool all_needed_module_btfs_loaded(const struct bpf_object *obj)
> +{
> +	return obj->btf_module_names &&
> +	       obj->nr_btf_module_names == obj->btf_module_cnt;
> +}
> +
>  static int load_module_btfs(struct bpf_object *obj)
>  {
>  	struct bpf_btf_info info;
> @@ -5825,6 +5925,9 @@ static int load_module_btfs(struct bpf_object *obj)
>  	if (!kernel_supports(obj, FEAT_MODULE_BTF))
>  		return 0;
>  
> +	if (no_module_btfs_needed(obj))
> +		return 0;
> +
>  	while (true) {
>  		err = bpf_btf_get_next_id(id, &id);
>  		if (err && errno == ENOENT)
> @@ -5867,6 +5970,11 @@ static int load_module_btfs(struct bpf_object *obj)
>  			continue;
>  		}
>  
> +		if (!is_module_btf_needed(obj, name)) {
> +			close(fd);
> +			continue;
> +		}
> +
>  		btf = btf_get_from_fd(fd, obj->btf_vmlinux);
>  		err = libbpf_get_error(btf);
>  		if (err) {
> @@ -5891,6 +5999,9 @@ static int load_module_btfs(struct bpf_object *obj)
>  			break;
>  		}
>  		obj->btf_module_cnt++;
> +
> +		if (all_needed_module_btfs_loaded(obj))
> +			break;
>  	}
>  

I was looking at the selftest in patch 2 and was a bit confused as to why
specifying just "nonexistent_module" in the module list was a way to test 
the scenario where we fail to specify a module that is needed ("bpf_testmod"
in that case). I think I see the answer here - we don't look at the module
count and check it against the number we asked for after the loop completes.
In the case of "nonexistent_module" our obj->btf_module_cnt is 0. Since 
all_needed_module_btfs_loaded() will evaluate to false in that case,
we keep iterating over BTF ids.

On loop exit shouldn't we check obj->btf_module_cnt in the case we asked
for specific modules, and make sure it matches the requested number?
  
>  	if (err) {
> @@ -8508,6 +8619,10 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf,
>  		}
>  	}
>  
> +	err = bpf_object_init_btf_module_names(obj, opts);
> +	if (err)
> +		goto out;
> +
>  	err = bpf_object__elf_init(obj);
>  	err = err ? : bpf_object__elf_collect(obj);
>  	err = err ? : bpf_object__collect_externs(obj);
> @@ -9629,6 +9744,8 @@ void bpf_object__close(struct bpf_object *obj)
>  		close(obj->jumptable_maps[i].fd);
>  	zfree(&obj->jumptable_maps);
>  
> +	bpf_object_free_btf_module_names(obj);
> +
>  	free(obj);
>  }
>  
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index b965ad571540..1cabf7e46554 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -224,10 +224,32 @@ struct bpf_object_open_opts {
>  	 * point (/sys/fs/bpf), in case this default behavior is undesirable.
>  	 */
>  	const char *bpf_token_path;
> +	/*
> +	 * Optional list of kernel module names whose BTFs should be loaded.
> +	 * nr_btf_module_names specifies the number of entries in
> +	 * btf_module_names.
> +	 *
> +	 * With btf_module_names:
> +	 * - when provided, only the BTFs of the specified modules are loaded;
> +	 * - when an empty list is provided, no module BTFs are loaded;
> +	 * - when NULL, all module BTFs are loaded as before.
> +	 *
> +	 * The list must contain valid, non-empty module names and must not
> +	 * contain duplicate entries; otherwise -EINVAL is returned.
> +	 *
> +	 * This affects:
> +	 * - BPF CO-RE relocations against types defined in modules;
> +	 * - BTF-based resolution of attach targets;
> +	 * - module-qualified tracing multi-attach targets;
> +	 * - struct_ops kernel type resolution;
> +	 * - extern (ksym) resolution for kernel symbols defined in modules.
> +	 */
> +	const char **btf_module_names;
> +	size_t nr_btf_module_names;
>  
>  	size_t :0;
>  };
> -#define bpf_object_open_opts__last_field bpf_token_path
> +#define bpf_object_open_opts__last_field nr_btf_module_names
>  
>  /**
>   * @brief **bpf_object__open()** creates a bpf_object by opening
> -- 
> 2.34.1
> 


  parent reply	other threads:[~2026-08-31 14:47 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31 13:38 [PATCH bpf-next v6 0/2] libbpf: Improve BPF load performance by selectively loading module BTFs Fuyu Zhao
2026-08-31 13:38 ` [PATCH bpf-next v6 1/2] libbpf: support selective kernel module BTF loading via bpf_object_open_opts Fuyu Zhao
2026-08-31 14:46   ` bot+bpf-ci
2026-09-01  3:55     ` Fuyu Zhao
2026-08-31 14:46   ` Alan Maguire [this message]
2026-09-01  3:15     ` Fuyu Zhao
2026-09-01  7:33       ` Alan Maguire
2026-09-03  0:12   ` Andrii Nakryiko
2026-09-03 12:52     ` Fuyu Zhao
2026-08-31 13:38 ` [PATCH bpf-next v6 2/2] selftests/bpf: add tests for selective module BTF loading Fuyu Zhao
2026-08-31 14:46   ` bot+bpf-ci
2026-09-01  3:56     ` Fuyu Zhao
2026-09-03  0:12   ` Andrii Nakryiko
2026-09-03 12:52     ` Fuyu Zhao

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=ccb5d732-90ef-4acb-b11d-75da7f1d21ce@oracle.com \
    --to=alan.maguire@oracle.com \
    --cc=andrii.nakryiko@gmail.com \
    --cc=bpf@vger.kernel.org \
    --cc=eddyz87@gmail.com \
    --cc=zhaofuyu@vivo.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.