Commit 2d39d7c5 authored by Andrii Nakryiko's avatar Andrii Nakryiko Committed by Alexei Starovoitov

libbpf: Refactor map creation logic and fix cleanup leak

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: 57a00f41 ("libbpf: Add auto-pinning of maps when loading BPF objects")
Signed-off-by: default avatarAndrii Nakryiko <andriin@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarToke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/bpf/20200429002739.48006-3-andriin@fb.com
parent 41017e56
...@@ -3493,34 +3493,14 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map) ...@@ -3493,34 +3493,14 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map)
return 0; return 0;
} }
static int static void bpf_map__destroy(struct bpf_map *map);
bpf_object__create_maps(struct bpf_object *obj)
{
struct bpf_create_map_attr create_attr = {};
int nr_cpus = 0;
unsigned int i;
int err;
for (i = 0; i < obj->nr_maps; i++) { static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map)
struct bpf_map *map = &obj->maps[i]; {
struct bpf_create_map_attr create_attr;
struct bpf_map_def *def = &map->def; 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) { memset(&create_attr, 0, sizeof(create_attr));
pr_debug("skip map create (preset) %s: fd=%d\n",
map->name, map->fd);
continue;
}
if (obj->caps.name) if (obj->caps.name)
create_attr.name = map->name; create_attr.name = map->name;
...@@ -3529,42 +3509,41 @@ bpf_object__create_maps(struct bpf_object *obj) ...@@ -3529,42 +3509,41 @@ bpf_object__create_maps(struct bpf_object *obj)
create_attr.map_flags = def->map_flags; create_attr.map_flags = def->map_flags;
create_attr.key_size = def->key_size; create_attr.key_size = def->key_size;
create_attr.value_size = def->value_size; create_attr.value_size = def->value_size;
if (def->type == BPF_MAP_TYPE_PERF_EVENT_ARRAY &&
!def->max_entries) { if (def->type == BPF_MAP_TYPE_PERF_EVENT_ARRAY && !def->max_entries) {
if (!nr_cpus) int nr_cpus;
nr_cpus = libbpf_num_possible_cpus(); nr_cpus = libbpf_num_possible_cpus();
if (nr_cpus < 0) { if (nr_cpus < 0) {
pr_warn("failed to determine number of system CPUs: %d\n", pr_warn("map '%s': 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",
map->name, nr_cpus); 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; create_attr.max_entries = nr_cpus;
} else { } else {
create_attr.max_entries = def->max_entries; 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)) if (bpf_map__is_struct_ops(map))
create_attr.btf_vmlinux_value_type_id = create_attr.btf_vmlinux_value_type_id =
map->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)) { if (obj->btf && !bpf_map_find_btf_info(obj, map)) {
create_attr.btf_fd = btf__fd(obj->btf); create_attr.btf_fd = btf__fd(obj->btf);
create_attr.btf_key_type_id = map->btf_key_type_id; create_attr.btf_key_type_id = map->btf_key_type_id;
create_attr.btf_value_type_id = map->btf_value_type_id; create_attr.btf_value_type_id = map->btf_value_type_id;
} }
*pfd = bpf_create_map_xattr(&create_attr); map->fd = bpf_create_map_xattr(&create_attr);
if (*pfd < 0 && (create_attr.btf_key_type_id || if (map->fd < 0 && (create_attr.btf_key_type_id ||
create_attr.btf_value_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)); cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg));
pr_warn("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n", pr_warn("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n",
map->name, cp, err); map->name, cp, err);
...@@ -3573,27 +3552,52 @@ bpf_object__create_maps(struct bpf_object *obj) ...@@ -3573,27 +3552,52 @@ bpf_object__create_maps(struct bpf_object *obj)
create_attr.btf_value_type_id = 0; create_attr.btf_value_type_id = 0;
map->btf_key_type_id = 0; map->btf_key_type_id = 0;
map->btf_value_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) { if (map->fd < 0)
size_t j; return -errno;
err = -errno; return 0;
err_out: }
cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg));
pr_warn("failed to create map (name: '%s'): %s(%d)\n", static int
map->name, cp, err); bpf_object__create_maps(struct bpf_object *obj)
pr_perm_msg(err); {
for (j = 0; j < i; j++) struct bpf_map *map;
zclose(obj->maps[j].fd); char *cp, errmsg[STRERR_BUFSIZE];
return err; 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)) { if (bpf_map__is_internal(map)) {
err = bpf_object__populate_internal_map(obj, map); err = bpf_object__populate_internal_map(obj, map);
if (err < 0) { if (err < 0) {
zclose(*pfd); zclose(map->fd);
goto err_out; goto err_out;
} }
} }
...@@ -3601,16 +3605,23 @@ bpf_object__create_maps(struct bpf_object *obj) ...@@ -3601,16 +3605,23 @@ bpf_object__create_maps(struct bpf_object *obj)
if (map->pin_path && !map->pinned) { if (map->pin_path && !map->pinned) {
err = bpf_map__pin(map, NULL); err = bpf_map__pin(map, NULL);
if (err) { if (err) {
pr_warn("failed to auto-pin map name '%s' at '%s'\n", pr_warn("map '%s': failed to auto-pin at '%s': %d\n",
map->name, map->pin_path); map->name, map->pin_path, err);
return err; zclose(map->fd);
goto err_out;
} }
} }
pr_debug("created map %s: fd=%d\n", map->name, *pfd);
} }
return 0; 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 static int
...@@ -5966,24 +5977,8 @@ int bpf_object__pin(struct bpf_object *obj, const char *path) ...@@ -5966,24 +5977,8 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
return 0; 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) if (map->clear_priv)
map->clear_priv(map, map->priv); map->clear_priv(map, map->priv);
map->priv = NULL; map->priv = NULL;
...@@ -6003,7 +5998,28 @@ void bpf_object__close(struct bpf_object *obj) ...@@ -6003,7 +5998,28 @@ void bpf_object__close(struct bpf_object *obj)
zfree(&map->name); zfree(&map->name);
zfree(&map->pin_path); 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->kconfig);
zfree(&obj->externs); zfree(&obj->externs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment