libbpf: Convert st_ops->data to shadow type.
[linux-2.6-microblaze.git] / tools / lib / bpf / libbpf.c
index c759628..6c2979f 100644 (file)
@@ -1014,6 +1014,19 @@ static bool bpf_map__is_struct_ops(const struct bpf_map *map)
        return map->def.type == BPF_MAP_TYPE_STRUCT_OPS;
 }
 
+static bool is_valid_st_ops_program(struct bpf_object *obj,
+                                   const struct bpf_program *prog)
+{
+       int i;
+
+       for (i = 0; i < obj->nr_programs; i++) {
+               if (&obj->programs[i] == prog)
+                       return prog->type == BPF_PROG_TYPE_STRUCT_OPS;
+       }
+
+       return false;
+}
+
 /* Init the map's fields that depend on kern_btf */
 static int bpf_map__init_kern_struct_ops(struct bpf_map *map)
 {
@@ -1102,9 +1115,16 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map)
                if (btf_is_ptr(mtype)) {
                        struct bpf_program *prog;
 
-                       prog = st_ops->progs[i];
+                       /* Update the value from the shadow type */
+                       prog = *(void **)mdata;
+                       st_ops->progs[i] = prog;
                        if (!prog)
                                continue;
+                       if (!is_valid_st_ops_program(obj, prog)) {
+                               pr_warn("struct_ops init_kern %s: member %s is not a struct_ops program\n",
+                                       map->name, mname);
+                               return -ENOTSUP;
+                       }
 
                        kern_mtype = skip_mods_and_typedefs(kern_btf,
                                                            kern_mtype->type,
@@ -9310,7 +9330,9 @@ static struct bpf_map *find_struct_ops_map_by_offset(struct bpf_object *obj,
        return NULL;
 }
 
-/* Collect the reloc from ELF and populate the st_ops->progs[] */
+/* Collect the reloc from ELF, populate the st_ops->progs[], and update
+ * st_ops->data for shadow type.
+ */
 static int bpf_object__collect_st_ops_relos(struct bpf_object *obj,
                                            Elf64_Shdr *shdr, Elf_Data *data)
 {
@@ -9424,6 +9446,14 @@ static int bpf_object__collect_st_ops_relos(struct bpf_object *obj,
                }
 
                st_ops->progs[member_idx] = prog;
+
+               /* st_ops->data will be exposed to users, being returned by
+                * bpf_map__initial_value() as a pointer to the shadow
+                * type. All function pointers in the original struct type
+                * should be converted to a pointer to struct bpf_program
+                * in the shadow type.
+                */
+               *((struct bpf_program **)(st_ops->data + moff)) = prog;
        }
 
        return 0;
@@ -9882,6 +9912,12 @@ int bpf_map__set_initial_value(struct bpf_map *map,
 
 void *bpf_map__initial_value(struct bpf_map *map, size_t *psize)
 {
+       if (bpf_map__is_struct_ops(map)) {
+               if (psize)
+                       *psize = map->def.value_size;
+               return map->st_ops->data;
+       }
+
        if (!map->mmaped)
                return NULL;
        *psize = map->def.value_size;