mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
libbpf: Refactor map creation logic and fix cleanup leak
[ Upstream commit2d39d7c56f] Factor out map creation and destruction logic to simplify code and especially error handling. Also fix map FD leak in case of partially successful map creation during bpf_object load operation. Fixes:57a00f4164("libbpf: Add auto-pinning of maps when loading BPF objects") Signed-off-by: Andrii Nakryiko <andriin@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Toke Høiland-Jørgensen <toke@redhat.com> Link: https://lore.kernel.org/bpf/20200429002739.48006-3-andriin@fb.com Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
dbf0a8fce6
commit
0a849ce1bd
@@ -3482,34 +3482,14 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__create_maps(struct bpf_object *obj)
|
||||
static void bpf_map__destroy(struct bpf_map *map);
|
||||
|
||||
static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map)
|
||||
{
|
||||
struct bpf_create_map_attr create_attr = {};
|
||||
int nr_cpus = 0;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < obj->nr_maps; i++) {
|
||||
struct bpf_map *map = &obj->maps[i];
|
||||
struct bpf_create_map_attr create_attr;
|
||||
struct bpf_map_def *def = &map->def;
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
int *pfd = &map->fd;
|
||||
|
||||
if (map->pin_path) {
|
||||
err = bpf_object__reuse_map(map);
|
||||
if (err) {
|
||||
pr_warn("error reusing pinned map %s\n",
|
||||
map->name);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (map->fd >= 0) {
|
||||
pr_debug("skip map create (preset) %s: fd=%d\n",
|
||||
map->name, map->fd);
|
||||
continue;
|
||||
}
|
||||
memset(&create_attr, 0, sizeof(create_attr));
|
||||
|
||||
if (obj->caps.name)
|
||||
create_attr.name = map->name;
|
||||
@@ -3518,42 +3498,41 @@ bpf_object__create_maps(struct bpf_object *obj)
|
||||
create_attr.map_flags = def->map_flags;
|
||||
create_attr.key_size = def->key_size;
|
||||
create_attr.value_size = def->value_size;
|
||||
if (def->type == BPF_MAP_TYPE_PERF_EVENT_ARRAY &&
|
||||
!def->max_entries) {
|
||||
if (!nr_cpus)
|
||||
|
||||
if (def->type == BPF_MAP_TYPE_PERF_EVENT_ARRAY && !def->max_entries) {
|
||||
int nr_cpus;
|
||||
|
||||
nr_cpus = libbpf_num_possible_cpus();
|
||||
if (nr_cpus < 0) {
|
||||
pr_warn("failed to determine number of system CPUs: %d\n",
|
||||
nr_cpus);
|
||||
err = nr_cpus;
|
||||
goto err_out;
|
||||
}
|
||||
pr_debug("map '%s': setting size to %d\n",
|
||||
pr_warn("map '%s': failed to determine number of system CPUs: %d\n",
|
||||
map->name, nr_cpus);
|
||||
return nr_cpus;
|
||||
}
|
||||
pr_debug("map '%s': setting size to %d\n", map->name, nr_cpus);
|
||||
create_attr.max_entries = nr_cpus;
|
||||
} else {
|
||||
create_attr.max_entries = def->max_entries;
|
||||
}
|
||||
create_attr.btf_fd = 0;
|
||||
create_attr.btf_key_type_id = 0;
|
||||
create_attr.btf_value_type_id = 0;
|
||||
if (bpf_map_type__is_map_in_map(def->type) &&
|
||||
map->inner_map_fd >= 0)
|
||||
create_attr.inner_map_fd = map->inner_map_fd;
|
||||
|
||||
if (bpf_map__is_struct_ops(map))
|
||||
create_attr.btf_vmlinux_value_type_id =
|
||||
map->btf_vmlinux_value_type_id;
|
||||
|
||||
create_attr.btf_fd = 0;
|
||||
create_attr.btf_key_type_id = 0;
|
||||
create_attr.btf_value_type_id = 0;
|
||||
if (obj->btf && !bpf_map_find_btf_info(obj, map)) {
|
||||
create_attr.btf_fd = btf__fd(obj->btf);
|
||||
create_attr.btf_key_type_id = map->btf_key_type_id;
|
||||
create_attr.btf_value_type_id = map->btf_value_type_id;
|
||||
}
|
||||
|
||||
*pfd = bpf_create_map_xattr(&create_attr);
|
||||
if (*pfd < 0 && (create_attr.btf_key_type_id ||
|
||||
map->fd = bpf_create_map_xattr(&create_attr);
|
||||
if (map->fd < 0 && (create_attr.btf_key_type_id ||
|
||||
create_attr.btf_value_type_id)) {
|
||||
err = -errno;
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
int err = -errno;
|
||||
|
||||
cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg));
|
||||
pr_warn("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n",
|
||||
map->name, cp, err);
|
||||
@@ -3562,27 +3541,52 @@ bpf_object__create_maps(struct bpf_object *obj)
|
||||
create_attr.btf_value_type_id = 0;
|
||||
map->btf_key_type_id = 0;
|
||||
map->btf_value_type_id = 0;
|
||||
*pfd = bpf_create_map_xattr(&create_attr);
|
||||
map->fd = bpf_create_map_xattr(&create_attr);
|
||||
}
|
||||
|
||||
if (*pfd < 0) {
|
||||
size_t j;
|
||||
if (map->fd < 0)
|
||||
return -errno;
|
||||
|
||||
err = -errno;
|
||||
err_out:
|
||||
cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg));
|
||||
pr_warn("failed to create map (name: '%s'): %s(%d)\n",
|
||||
map->name, cp, err);
|
||||
pr_perm_msg(err);
|
||||
for (j = 0; j < i; j++)
|
||||
zclose(obj->maps[j].fd);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__create_maps(struct bpf_object *obj)
|
||||
{
|
||||
struct bpf_map *map;
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
unsigned int i, j;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < obj->nr_maps; i++) {
|
||||
map = &obj->maps[i];
|
||||
|
||||
if (map->pin_path) {
|
||||
err = bpf_object__reuse_map(map);
|
||||
if (err) {
|
||||
pr_warn("map '%s': error reusing pinned map\n",
|
||||
map->name);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
if (map->fd >= 0) {
|
||||
pr_debug("map '%s': skipping creation (preset fd=%d)\n",
|
||||
map->name, map->fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
err = bpf_object__create_map(obj, map);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
pr_debug("map '%s': created successfully, fd=%d\n", map->name,
|
||||
map->fd);
|
||||
|
||||
if (bpf_map__is_internal(map)) {
|
||||
err = bpf_object__populate_internal_map(obj, map);
|
||||
if (err < 0) {
|
||||
zclose(*pfd);
|
||||
zclose(map->fd);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
@@ -3590,16 +3594,23 @@ err_out:
|
||||
if (map->pin_path && !map->pinned) {
|
||||
err = bpf_map__pin(map, NULL);
|
||||
if (err) {
|
||||
pr_warn("failed to auto-pin map name '%s' at '%s'\n",
|
||||
map->name, map->pin_path);
|
||||
return err;
|
||||
pr_warn("map '%s': failed to auto-pin at '%s': %d\n",
|
||||
map->name, map->pin_path, err);
|
||||
zclose(map->fd);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("created map %s: fd=%d\n", map->name, *pfd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg));
|
||||
pr_warn("map '%s': failed to create: %s(%d)\n", map->name, cp, err);
|
||||
pr_perm_msg(err);
|
||||
for (j = 0; j < i; j++)
|
||||
zclose(obj->maps[j].fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -5955,24 +5966,8 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bpf_object__close(struct bpf_object *obj)
|
||||
static void bpf_map__destroy(struct bpf_map *map)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
if (obj->clear_priv)
|
||||
obj->clear_priv(obj, obj->priv);
|
||||
|
||||
bpf_object__elf_finish(obj);
|
||||
bpf_object__unload(obj);
|
||||
btf__free(obj->btf);
|
||||
btf_ext__free(obj->btf_ext);
|
||||
|
||||
for (i = 0; i < obj->nr_maps; i++) {
|
||||
struct bpf_map *map = &obj->maps[i];
|
||||
|
||||
if (map->clear_priv)
|
||||
map->clear_priv(map, map->priv);
|
||||
map->priv = NULL;
|
||||
@@ -5992,8 +5987,29 @@ void bpf_object__close(struct bpf_object *obj)
|
||||
|
||||
zfree(&map->name);
|
||||
zfree(&map->pin_path);
|
||||
|
||||
if (map->fd >= 0)
|
||||
zclose(map->fd);
|
||||
}
|
||||
|
||||
void bpf_object__close(struct bpf_object *obj)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
if (obj->clear_priv)
|
||||
obj->clear_priv(obj, obj->priv);
|
||||
|
||||
bpf_object__elf_finish(obj);
|
||||
bpf_object__unload(obj);
|
||||
btf__free(obj->btf);
|
||||
btf_ext__free(obj->btf_ext);
|
||||
|
||||
for (i = 0; i < obj->nr_maps; i++)
|
||||
bpf_map__destroy(&obj->maps[i]);
|
||||
|
||||
zfree(&obj->kconfig);
|
||||
zfree(&obj->externs);
|
||||
obj->nr_extern = 0;
|
||||
|
||||
Reference in New Issue
Block a user