On Mon, May 5, 2025 at 11:39 AM Lorenz Bauer lmb@isovalent.com wrote:
Teach libbpf to use mmap when parsing vmlinux BTF from /sys. We don't apply this to fall-back paths on the regular file system because there is no way to ensure that modifications underlying the MAP_PRIVATE mapping are not visible to the process.
Signed-off-by: Lorenz Bauer lmb@isovalent.com
tools/lib/bpf/btf.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 72 insertions(+), 11 deletions(-)
[...]
@@ -1030,7 +1045,7 @@ struct btf *btf__new_empty_split(struct btf *base_btf) return libbpf_ptr(btf_new_empty(base_btf)); }
-static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf) +static struct btf *btf_new_no_copy(void *data, __u32 size, struct btf *base_btf) { struct btf *btf; int err; @@ -1050,12 +1065,7 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf) btf->start_str_off = base_btf->hdr->str_len; }
btf->raw_data = malloc(size);
if (!btf->raw_data) {
err = -ENOMEM;
goto done;
}
memcpy(btf->raw_data, data, size);
btf->raw_data = data; btf->raw_size = size; btf->hdr = btf->raw_data;
@@ -1081,6 +1091,24 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf) return btf; }
+static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf)
btf_new() is internal, so I'd extend existing btf_new() with `bool is_mmap` and not add btf_new_no_copy(), I think it's simpler. Eventually we can turn is_mmap into some sort of flags, if we need more tuning of data ownership behavior
+{
struct btf *btf;
void *raw_data;
raw_data = malloc(size);
if (!raw_data)
return ERR_PTR(-ENOMEM);
memcpy(raw_data, data, size);
btf = btf_new_no_copy(raw_data, size, base_btf);
if (IS_ERR(btf))
free(raw_data);
return btf;
+}
struct btf *btf__new(const void *data, __u32 size) { return libbpf_ptr(btf_new(data, size, NULL)); @@ -1354,6 +1382,37 @@ struct btf *btf__parse_raw_split(const char *path, struct btf *base_btf) return libbpf_ptr(btf_parse_raw(path, base_btf)); }
+static struct btf *btf_parse_raw_mmap(const char *path, struct btf *base_btf) +{
struct stat st;
void *data;
struct btf *btf;
int fd;
fd = open(path, O_RDONLY);
if (fd < 0)
return libbpf_err_ptr(-errno);
if (fstat(fd, &st) < 0) {
close(fd);
close() can clobber errno, so save `err = -errno` before it
return libbpf_err_ptr(-errno);
}
data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
same, errno clobbering danger
if (data == MAP_FAILED)
return NULL;
btf = btf_new_no_copy(data, st.st_size, base_btf);
if (!btf)
btf_new_no_copy() is returning ERR_PTR() on error, no?
pw-bot: cr
munmap(data, st.st_size);
else
btf->raw_data_is_mmap = true;
return btf;
+}
static struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_ext **btf_ext) { struct btf *btf; @@ -1659,8 +1718,7 @@ struct btf *btf__load_from_kernel_by_id(__u32 id) static void btf_invalidate_raw_data(struct btf *btf) { if (btf->raw_data) {
free(btf->raw_data);
btf->raw_data = NULL;
btf_free_raw_data(btf); } if (btf->raw_data_swapped) { free(btf->raw_data_swapped);
@@ -5290,7 +5348,10 @@ struct btf *btf__load_vmlinux_btf(void) pr_warn("kernel BTF is missing at '%s', was CONFIG_DEBUG_INFO_BTF enabled?\n", sysfs_btf_path); } else {
btf = btf__parse(sysfs_btf_path, NULL);
btf = btf_parse_raw_mmap(sysfs_btf_path, NULL);
if (IS_ERR_OR_NULL(btf))
btf = btf__parse(sysfs_btf_path, NULL);
if (!btf) { err = -errno; pr_warn("failed to read kernel BTF from '%s': %s\n",
-- 2.49.0