]>
git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - kernel/bpf/map_in_map.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2017 Facebook
4 #include <linux/slab.h>
8 #include "map_in_map.h"
10 struct bpf_map
*bpf_map_meta_alloc(int inner_map_ufd
)
12 struct bpf_map
*inner_map
, *inner_map_meta
;
13 u32 inner_map_meta_size
;
16 f
= fdget(inner_map_ufd
);
17 inner_map
= __bpf_map_get(f
);
18 if (IS_ERR(inner_map
))
21 /* Does not support >1 level map-in-map */
22 if (inner_map
->inner_map_meta
) {
24 return ERR_PTR(-EINVAL
);
27 if (!inner_map
->ops
->map_meta_equal
) {
29 return ERR_PTR(-ENOTSUPP
);
32 if (map_value_has_spin_lock(inner_map
)) {
34 return ERR_PTR(-ENOTSUPP
);
37 inner_map_meta_size
= sizeof(*inner_map_meta
);
38 /* In some cases verifier needs to access beyond just base map. */
39 if (inner_map
->ops
== &array_map_ops
)
40 inner_map_meta_size
= sizeof(struct bpf_array
);
42 inner_map_meta
= kzalloc(inner_map_meta_size
, GFP_USER
);
43 if (!inner_map_meta
) {
45 return ERR_PTR(-ENOMEM
);
48 inner_map_meta
->map_type
= inner_map
->map_type
;
49 inner_map_meta
->key_size
= inner_map
->key_size
;
50 inner_map_meta
->value_size
= inner_map
->value_size
;
51 inner_map_meta
->map_flags
= inner_map
->map_flags
;
52 inner_map_meta
->max_entries
= inner_map
->max_entries
;
53 inner_map_meta
->spin_lock_off
= inner_map
->spin_lock_off
;
54 inner_map_meta
->timer_off
= inner_map
->timer_off
;
56 btf_get(inner_map
->btf
);
57 inner_map_meta
->btf
= inner_map
->btf
;
60 /* Misc members not needed in bpf_map_meta_equal() check. */
61 inner_map_meta
->ops
= inner_map
->ops
;
62 if (inner_map
->ops
== &array_map_ops
) {
63 inner_map_meta
->bypass_spec_v1
= inner_map
->bypass_spec_v1
;
64 container_of(inner_map_meta
, struct bpf_array
, map
)->index_mask
=
65 container_of(inner_map
, struct bpf_array
, map
)->index_mask
;
69 return inner_map_meta
;
72 void bpf_map_meta_free(struct bpf_map
*map_meta
)
74 btf_put(map_meta
->btf
);
78 bool bpf_map_meta_equal(const struct bpf_map
*meta0
,
79 const struct bpf_map
*meta1
)
81 /* No need to compare ops because it is covered by map_type */
82 return meta0
->map_type
== meta1
->map_type
&&
83 meta0
->key_size
== meta1
->key_size
&&
84 meta0
->value_size
== meta1
->value_size
&&
85 meta0
->timer_off
== meta1
->timer_off
&&
86 meta0
->map_flags
== meta1
->map_flags
;
89 void *bpf_map_fd_get_ptr(struct bpf_map
*map
,
90 struct file
*map_file
/* not used */,
93 struct bpf_map
*inner_map
, *inner_map_meta
;
97 inner_map
= __bpf_map_get(f
);
98 if (IS_ERR(inner_map
))
101 inner_map_meta
= map
->inner_map_meta
;
102 if (inner_map_meta
->ops
->map_meta_equal(inner_map_meta
, inner_map
))
103 bpf_map_inc(inner_map
);
105 inner_map
= ERR_PTR(-EINVAL
);
111 void bpf_map_fd_put_ptr(void *ptr
)
113 /* ptr->ops->map_free() has to go through one
114 * rcu grace period by itself.
119 u32
bpf_map_fd_sys_lookup_elem(void *ptr
)
121 return ((struct bpf_map
*)ptr
)->id
;