diff options
Diffstat (limited to 'kernel/bpf/arraymap.c')
-rw-r--r-- | kernel/bpf/arraymap.c | 80 |
1 files changed, 49 insertions, 31 deletions
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index cb31229a6fa4..45df6572ecfd 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c | |||
@@ -150,15 +150,15 @@ static int __init register_array_map(void) | |||
150 | } | 150 | } |
151 | late_initcall(register_array_map); | 151 | late_initcall(register_array_map); |
152 | 152 | ||
153 | static struct bpf_map *prog_array_map_alloc(union bpf_attr *attr) | 153 | static struct bpf_map *fd_array_map_alloc(union bpf_attr *attr) |
154 | { | 154 | { |
155 | /* only bpf_prog file descriptors can be stored in prog_array map */ | 155 | /* only file descriptors can be stored in this type of map */ |
156 | if (attr->value_size != sizeof(u32)) | 156 | if (attr->value_size != sizeof(u32)) |
157 | return ERR_PTR(-EINVAL); | 157 | return ERR_PTR(-EINVAL); |
158 | return array_map_alloc(attr); | 158 | return array_map_alloc(attr); |
159 | } | 159 | } |
160 | 160 | ||
161 | static void prog_array_map_free(struct bpf_map *map) | 161 | static void fd_array_map_free(struct bpf_map *map) |
162 | { | 162 | { |
163 | struct bpf_array *array = container_of(map, struct bpf_array, map); | 163 | struct bpf_array *array = container_of(map, struct bpf_array, map); |
164 | int i; | 164 | int i; |
@@ -167,21 +167,21 @@ static void prog_array_map_free(struct bpf_map *map) | |||
167 | 167 | ||
168 | /* make sure it's empty */ | 168 | /* make sure it's empty */ |
169 | for (i = 0; i < array->map.max_entries; i++) | 169 | for (i = 0; i < array->map.max_entries; i++) |
170 | BUG_ON(array->prog[i] != NULL); | 170 | BUG_ON(array->ptrs[i] != NULL); |
171 | kvfree(array); | 171 | kvfree(array); |
172 | } | 172 | } |
173 | 173 | ||
174 | static void *prog_array_map_lookup_elem(struct bpf_map *map, void *key) | 174 | static void *fd_array_map_lookup_elem(struct bpf_map *map, void *key) |
175 | { | 175 | { |
176 | return NULL; | 176 | return NULL; |
177 | } | 177 | } |
178 | 178 | ||
179 | /* only called from syscall */ | 179 | /* only called from syscall */ |
180 | static int prog_array_map_update_elem(struct bpf_map *map, void *key, | 180 | static int fd_array_map_update_elem(struct bpf_map *map, void *key, |
181 | void *value, u64 map_flags) | 181 | void *value, u64 map_flags) |
182 | { | 182 | { |
183 | struct bpf_array *array = container_of(map, struct bpf_array, map); | 183 | struct bpf_array *array = container_of(map, struct bpf_array, map); |
184 | struct bpf_prog *prog, *old_prog; | 184 | void *new_ptr, *old_ptr; |
185 | u32 index = *(u32 *)key, ufd; | 185 | u32 index = *(u32 *)key, ufd; |
186 | 186 | ||
187 | if (map_flags != BPF_ANY) | 187 | if (map_flags != BPF_ANY) |
@@ -191,57 +191,75 @@ static int prog_array_map_update_elem(struct bpf_map *map, void *key, | |||
191 | return -E2BIG; | 191 | return -E2BIG; |
192 | 192 | ||
193 | ufd = *(u32 *)value; | 193 | ufd = *(u32 *)value; |
194 | prog = bpf_prog_get(ufd); | 194 | new_ptr = map->ops->map_fd_get_ptr(map, ufd); |
195 | if (IS_ERR(prog)) | 195 | if (IS_ERR(new_ptr)) |
196 | return PTR_ERR(prog); | 196 | return PTR_ERR(new_ptr); |
197 | |||
198 | if (!bpf_prog_array_compatible(array, prog)) { | ||
199 | bpf_prog_put(prog); | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | 197 | ||
203 | old_prog = xchg(array->prog + index, prog); | 198 | old_ptr = xchg(array->ptrs + index, new_ptr); |
204 | if (old_prog) | 199 | if (old_ptr) |
205 | bpf_prog_put_rcu(old_prog); | 200 | map->ops->map_fd_put_ptr(old_ptr); |
206 | 201 | ||
207 | return 0; | 202 | return 0; |
208 | } | 203 | } |
209 | 204 | ||
210 | static int prog_array_map_delete_elem(struct bpf_map *map, void *key) | 205 | static int fd_array_map_delete_elem(struct bpf_map *map, void *key) |
211 | { | 206 | { |
212 | struct bpf_array *array = container_of(map, struct bpf_array, map); | 207 | struct bpf_array *array = container_of(map, struct bpf_array, map); |
213 | struct bpf_prog *old_prog; | 208 | void *old_ptr; |
214 | u32 index = *(u32 *)key; | 209 | u32 index = *(u32 *)key; |
215 | 210 | ||
216 | if (index >= array->map.max_entries) | 211 | if (index >= array->map.max_entries) |
217 | return -E2BIG; | 212 | return -E2BIG; |
218 | 213 | ||
219 | old_prog = xchg(array->prog + index, NULL); | 214 | old_ptr = xchg(array->ptrs + index, NULL); |
220 | if (old_prog) { | 215 | if (old_ptr) { |
221 | bpf_prog_put_rcu(old_prog); | 216 | map->ops->map_fd_put_ptr(old_ptr); |
222 | return 0; | 217 | return 0; |
223 | } else { | 218 | } else { |
224 | return -ENOENT; | 219 | return -ENOENT; |
225 | } | 220 | } |
226 | } | 221 | } |
227 | 222 | ||
223 | static void *prog_fd_array_get_ptr(struct bpf_map *map, int fd) | ||
224 | { | ||
225 | struct bpf_array *array = container_of(map, struct bpf_array, map); | ||
226 | struct bpf_prog *prog = bpf_prog_get(fd); | ||
227 | if (IS_ERR(prog)) | ||
228 | return prog; | ||
229 | |||
230 | if (!bpf_prog_array_compatible(array, prog)) { | ||
231 | bpf_prog_put(prog); | ||
232 | return ERR_PTR(-EINVAL); | ||
233 | } | ||
234 | return prog; | ||
235 | } | ||
236 | |||
237 | static void prog_fd_array_put_ptr(void *ptr) | ||
238 | { | ||
239 | struct bpf_prog *prog = ptr; | ||
240 | |||
241 | bpf_prog_put_rcu(prog); | ||
242 | } | ||
243 | |||
228 | /* decrement refcnt of all bpf_progs that are stored in this map */ | 244 | /* decrement refcnt of all bpf_progs that are stored in this map */ |
229 | void bpf_prog_array_map_clear(struct bpf_map *map) | 245 | void bpf_fd_array_map_clear(struct bpf_map *map) |
230 | { | 246 | { |
231 | struct bpf_array *array = container_of(map, struct bpf_array, map); | 247 | struct bpf_array *array = container_of(map, struct bpf_array, map); |
232 | int i; | 248 | int i; |
233 | 249 | ||
234 | for (i = 0; i < array->map.max_entries; i++) | 250 | for (i = 0; i < array->map.max_entries; i++) |
235 | prog_array_map_delete_elem(map, &i); | 251 | fd_array_map_delete_elem(map, &i); |
236 | } | 252 | } |
237 | 253 | ||
238 | static const struct bpf_map_ops prog_array_ops = { | 254 | static const struct bpf_map_ops prog_array_ops = { |
239 | .map_alloc = prog_array_map_alloc, | 255 | .map_alloc = fd_array_map_alloc, |
240 | .map_free = prog_array_map_free, | 256 | .map_free = fd_array_map_free, |
241 | .map_get_next_key = array_map_get_next_key, | 257 | .map_get_next_key = array_map_get_next_key, |
242 | .map_lookup_elem = prog_array_map_lookup_elem, | 258 | .map_lookup_elem = fd_array_map_lookup_elem, |
243 | .map_update_elem = prog_array_map_update_elem, | 259 | .map_update_elem = fd_array_map_update_elem, |
244 | .map_delete_elem = prog_array_map_delete_elem, | 260 | .map_delete_elem = fd_array_map_delete_elem, |
261 | .map_fd_get_ptr = prog_fd_array_get_ptr, | ||
262 | .map_fd_put_ptr = prog_fd_array_put_ptr, | ||
245 | }; | 263 | }; |
246 | 264 | ||
247 | static struct bpf_map_type_list prog_array_type __read_mostly = { | 265 | static struct bpf_map_type_list prog_array_type __read_mostly = { |