libbpf: Fix BPF_MAP_TYPE_PERF_EVENT_ARRAY auto-pinning
authorStijn Tintel <stijn@linux-ipv6.be>
Fri, 25 Feb 2022 15:23:55 +0000 (17:23 +0200)
committerDaniel Borkmann <daniel@iogearbox.net>
Mon, 28 Feb 2022 16:20:52 +0000 (17:20 +0100)
When a BPF map of type BPF_MAP_TYPE_PERF_EVENT_ARRAY doesn't have the
max_entries parameter set, the map will be created with max_entries set
to the number of available CPUs. When we try to reuse such a pinned map,
map_is_reuse_compat will return false, as max_entries in the map
definition differs from max_entries of the existing map, causing the
following error:

  libbpf: couldn't reuse pinned map at '/sys/fs/bpf/m_logging': parameter mismatch

Fix this by overwriting max_entries in the map definition. For this to
work, we need to do this in bpf_object__create_maps, before calling
bpf_object__reuse_map.

Fixes: 57a00f41644f ("libbpf: Add auto-pinning of maps when loading BPF objects")
Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Song Liu <songliubraving@fb.com>
Link: https://lore.kernel.org/bpf/20220225152355.315204-1-stijn@linux-ipv6.be
tools/lib/bpf/libbpf.c

index 776b8e034d626ef25f2803f23e9c339814196781..be6480e260c422b4455a4d4a3d05972b0ece422d 100644 (file)
@@ -4859,7 +4859,6 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
        LIBBPF_OPTS(bpf_map_create_opts, create_attr);
        struct bpf_map_def *def = &map->def;
        const char *map_name = NULL;
-       __u32 max_entries;
        int err = 0;
 
        if (kernel_supports(obj, FEAT_PROG_NAME))
@@ -4869,21 +4868,6 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
        create_attr.numa_node = map->numa_node;
        create_attr.map_extra = map->map_extra;
 
-       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("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);
-               max_entries = nr_cpus;
-       } else {
-               max_entries = def->max_entries;
-       }
-
        if (bpf_map__is_struct_ops(map))
                create_attr.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id;
 
@@ -4933,7 +4917,7 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
 
        if (obj->gen_loader) {
                bpf_gen__map_create(obj->gen_loader, def->type, map_name,
-                                   def->key_size, def->value_size, max_entries,
+                                   def->key_size, def->value_size, def->max_entries,
                                    &create_attr, is_inner ? -1 : map - obj->maps);
                /* Pretend to have valid FD to pass various fd >= 0 checks.
                 * This fd == 0 will not be used with any syscall and will be reset to -1 eventually.
@@ -4942,7 +4926,7 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
        } else {
                map->fd = bpf_map_create(def->type, map_name,
                                         def->key_size, def->value_size,
-                                        max_entries, &create_attr);
+                                        def->max_entries, &create_attr);
        }
        if (map->fd < 0 && (create_attr.btf_key_type_id ||
                            create_attr.btf_value_type_id)) {
@@ -4959,7 +4943,7 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
                map->btf_value_type_id = 0;
                map->fd = bpf_map_create(def->type, map_name,
                                         def->key_size, def->value_size,
-                                        max_entries, &create_attr);
+                                        def->max_entries, &create_attr);
        }
 
        err = map->fd < 0 ? -errno : 0;
@@ -5063,6 +5047,24 @@ static int bpf_object_init_prog_arrays(struct bpf_object *obj)
        return 0;
 }
 
+static int map_set_def_max_entries(struct bpf_map *map)
+{
+       if (map->def.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY && !map->def.max_entries) {
+               int nr_cpus;
+
+               nr_cpus = libbpf_num_possible_cpus();
+               if (nr_cpus < 0) {
+                       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);
+               map->def.max_entries = nr_cpus;
+       }
+
+       return 0;
+}
+
 static int
 bpf_object__create_maps(struct bpf_object *obj)
 {
@@ -5095,6 +5097,10 @@ bpf_object__create_maps(struct bpf_object *obj)
                        continue;
                }
 
+               err = map_set_def_max_entries(map);
+               if (err)
+                       goto err_out;
+
                retried = false;
 retry:
                if (map->pin_path) {