mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
libbpf: Use mmap to parse vmlinux BTF from sysfs
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> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Tested-by: Alan Maguire <alan.maguire@oracle.com> Acked-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20250520-vmlinux-mmap-v5-3-e8c941acc414@isovalent.com
This commit is contained in:
parent
828226b69f
commit
3c0421c93c
1 changed files with 71 additions and 18 deletions
|
@ -12,6 +12,7 @@
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/btf.h>
|
#include <linux/btf.h>
|
||||||
|
@ -120,6 +121,9 @@ struct btf {
|
||||||
/* whether base_btf should be freed in btf_free for this instance */
|
/* whether base_btf should be freed in btf_free for this instance */
|
||||||
bool owns_base;
|
bool owns_base;
|
||||||
|
|
||||||
|
/* whether raw_data is a (read-only) mmap */
|
||||||
|
bool raw_data_is_mmap;
|
||||||
|
|
||||||
/* BTF object FD, if loaded into kernel */
|
/* BTF object FD, if loaded into kernel */
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
@ -951,6 +955,17 @@ static bool btf_is_modifiable(const struct btf *btf)
|
||||||
return (void *)btf->hdr != btf->raw_data;
|
return (void *)btf->hdr != btf->raw_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void btf_free_raw_data(struct btf *btf)
|
||||||
|
{
|
||||||
|
if (btf->raw_data_is_mmap) {
|
||||||
|
munmap(btf->raw_data, btf->raw_size);
|
||||||
|
btf->raw_data_is_mmap = false;
|
||||||
|
} else {
|
||||||
|
free(btf->raw_data);
|
||||||
|
}
|
||||||
|
btf->raw_data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void btf__free(struct btf *btf)
|
void btf__free(struct btf *btf)
|
||||||
{
|
{
|
||||||
if (IS_ERR_OR_NULL(btf))
|
if (IS_ERR_OR_NULL(btf))
|
||||||
|
@ -970,7 +985,7 @@ void btf__free(struct btf *btf)
|
||||||
free(btf->types_data);
|
free(btf->types_data);
|
||||||
strset__free(btf->strs_set);
|
strset__free(btf->strs_set);
|
||||||
}
|
}
|
||||||
free(btf->raw_data);
|
btf_free_raw_data(btf);
|
||||||
free(btf->raw_data_swapped);
|
free(btf->raw_data_swapped);
|
||||||
free(btf->type_offs);
|
free(btf->type_offs);
|
||||||
if (btf->owns_base)
|
if (btf->owns_base)
|
||||||
|
@ -1030,7 +1045,7 @@ struct btf *btf__new_empty_split(struct btf *base_btf)
|
||||||
return libbpf_ptr(btf_new_empty(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(const void *data, __u32 size, struct btf *base_btf, bool is_mmap)
|
||||||
{
|
{
|
||||||
struct btf *btf;
|
struct btf *btf;
|
||||||
int err;
|
int err;
|
||||||
|
@ -1050,12 +1065,18 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf)
|
||||||
btf->start_str_off = base_btf->hdr->str_len;
|
btf->start_str_off = base_btf->hdr->str_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
btf->raw_data = malloc(size);
|
if (is_mmap) {
|
||||||
if (!btf->raw_data) {
|
btf->raw_data = (void *)data;
|
||||||
err = -ENOMEM;
|
btf->raw_data_is_mmap = true;
|
||||||
goto done;
|
} else {
|
||||||
|
btf->raw_data = malloc(size);
|
||||||
|
if (!btf->raw_data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memcpy(btf->raw_data, data, size);
|
||||||
}
|
}
|
||||||
memcpy(btf->raw_data, data, size);
|
|
||||||
btf->raw_size = size;
|
btf->raw_size = size;
|
||||||
|
|
||||||
btf->hdr = btf->raw_data;
|
btf->hdr = btf->raw_data;
|
||||||
|
@ -1083,12 +1104,12 @@ done:
|
||||||
|
|
||||||
struct btf *btf__new(const void *data, __u32 size)
|
struct btf *btf__new(const void *data, __u32 size)
|
||||||
{
|
{
|
||||||
return libbpf_ptr(btf_new(data, size, NULL));
|
return libbpf_ptr(btf_new(data, size, NULL, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct btf *btf__new_split(const void *data, __u32 size, struct btf *base_btf)
|
struct btf *btf__new_split(const void *data, __u32 size, struct btf *base_btf)
|
||||||
{
|
{
|
||||||
return libbpf_ptr(btf_new(data, size, base_btf));
|
return libbpf_ptr(btf_new(data, size, base_btf, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct btf_elf_secs {
|
struct btf_elf_secs {
|
||||||
|
@ -1209,7 +1230,7 @@ static struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
|
||||||
|
|
||||||
if (secs.btf_base_data) {
|
if (secs.btf_base_data) {
|
||||||
dist_base_btf = btf_new(secs.btf_base_data->d_buf, secs.btf_base_data->d_size,
|
dist_base_btf = btf_new(secs.btf_base_data->d_buf, secs.btf_base_data->d_size,
|
||||||
NULL);
|
NULL, false);
|
||||||
if (IS_ERR(dist_base_btf)) {
|
if (IS_ERR(dist_base_btf)) {
|
||||||
err = PTR_ERR(dist_base_btf);
|
err = PTR_ERR(dist_base_btf);
|
||||||
dist_base_btf = NULL;
|
dist_base_btf = NULL;
|
||||||
|
@ -1218,7 +1239,7 @@ static struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
|
||||||
}
|
}
|
||||||
|
|
||||||
btf = btf_new(secs.btf_data->d_buf, secs.btf_data->d_size,
|
btf = btf_new(secs.btf_data->d_buf, secs.btf_data->d_size,
|
||||||
dist_base_btf ?: base_btf);
|
dist_base_btf ?: base_btf, false);
|
||||||
if (IS_ERR(btf)) {
|
if (IS_ERR(btf)) {
|
||||||
err = PTR_ERR(btf);
|
err = PTR_ERR(btf);
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -1335,7 +1356,7 @@ static struct btf *btf_parse_raw(const char *path, struct btf *base_btf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finally parse BTF data */
|
/* finally parse BTF data */
|
||||||
btf = btf_new(data, sz, base_btf);
|
btf = btf_new(data, sz, base_btf, false);
|
||||||
|
|
||||||
err_out:
|
err_out:
|
||||||
free(data);
|
free(data);
|
||||||
|
@ -1354,6 +1375,37 @@ struct btf *btf__parse_raw_split(const char *path, struct btf *base_btf)
|
||||||
return libbpf_ptr(btf_parse_raw(path, 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, err;
|
||||||
|
|
||||||
|
fd = open(path, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
return libbpf_err_ptr(-errno);
|
||||||
|
|
||||||
|
if (fstat(fd, &st) < 0) {
|
||||||
|
err = -errno;
|
||||||
|
close(fd);
|
||||||
|
return libbpf_err_ptr(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
|
err = -errno;
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (data == MAP_FAILED)
|
||||||
|
return libbpf_err_ptr(err);
|
||||||
|
|
||||||
|
btf = btf_new(data, st.st_size, base_btf, true);
|
||||||
|
if (IS_ERR(btf))
|
||||||
|
munmap(data, st.st_size);
|
||||||
|
|
||||||
|
return btf;
|
||||||
|
}
|
||||||
|
|
||||||
static struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_ext **btf_ext)
|
static struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_ext **btf_ext)
|
||||||
{
|
{
|
||||||
struct btf *btf;
|
struct btf *btf;
|
||||||
|
@ -1618,7 +1670,7 @@ struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf)
|
||||||
goto exit_free;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
btf = btf_new(ptr, btf_info.btf_size, base_btf);
|
btf = btf_new(ptr, btf_info.btf_size, base_btf, false);
|
||||||
|
|
||||||
exit_free:
|
exit_free:
|
||||||
free(ptr);
|
free(ptr);
|
||||||
|
@ -1658,10 +1710,8 @@ struct btf *btf__load_from_kernel_by_id(__u32 id)
|
||||||
|
|
||||||
static void btf_invalidate_raw_data(struct btf *btf)
|
static void btf_invalidate_raw_data(struct btf *btf)
|
||||||
{
|
{
|
||||||
if (btf->raw_data) {
|
if (btf->raw_data)
|
||||||
free(btf->raw_data);
|
btf_free_raw_data(btf);
|
||||||
btf->raw_data = NULL;
|
|
||||||
}
|
|
||||||
if (btf->raw_data_swapped) {
|
if (btf->raw_data_swapped) {
|
||||||
free(btf->raw_data_swapped);
|
free(btf->raw_data_swapped);
|
||||||
btf->raw_data_swapped = NULL;
|
btf->raw_data_swapped = NULL;
|
||||||
|
@ -5331,7 +5381,10 @@ struct btf *btf__load_vmlinux_btf(void)
|
||||||
pr_warn("kernel BTF is missing at '%s', was CONFIG_DEBUG_INFO_BTF enabled?\n",
|
pr_warn("kernel BTF is missing at '%s', was CONFIG_DEBUG_INFO_BTF enabled?\n",
|
||||||
sysfs_btf_path);
|
sysfs_btf_path);
|
||||||
} else {
|
} else {
|
||||||
btf = btf__parse(sysfs_btf_path, NULL);
|
btf = btf_parse_raw_mmap(sysfs_btf_path, NULL);
|
||||||
|
if (IS_ERR(btf))
|
||||||
|
btf = btf__parse(sysfs_btf_path, NULL);
|
||||||
|
|
||||||
if (!btf) {
|
if (!btf) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
pr_warn("failed to read kernel BTF from '%s': %s\n",
|
pr_warn("failed to read kernel BTF from '%s': %s\n",
|
||||||
|
|
Loading…
Add table
Reference in a new issue