aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorRoman Gushchin <guro@fb.com>2018-09-28 10:45:36 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2018-10-01 10:18:32 -0400
commit8bad74f9840f87661f20ced3dc80c84ab4fd55a1 (patch)
tree1ac3ef2547d12f0fd6a232fbc1daac2672537907 /kernel
parent5bf7a60b8e70969f65c961d7e2c4eb40eb2c664d (diff)
bpf: extend cgroup bpf core to allow multiple cgroup storage types
In order to introduce per-cpu cgroup storage, let's generalize bpf cgroup core to support multiple cgroup storage types. Potentially, per-node cgroup storage can be added later. This commit is mostly a formal change that replaces cgroup_storage pointer with a array of cgroup_storage pointers. It doesn't actually introduce a new storage type, it will be done later. Each bpf program is now able to have one cgroup storage of each type. Signed-off-by: Roman Gushchin <guro@fb.com> Acked-by: Song Liu <songliubraving@fb.com> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/cgroup.c74
-rw-r--r--kernel/bpf/helpers.c15
-rw-r--r--kernel/bpf/local_storage.c18
-rw-r--r--kernel/bpf/syscall.c9
-rw-r--r--kernel/bpf/verifier.c8
5 files changed, 85 insertions, 39 deletions
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 549f6fbcc461..00f6ed2e4f9a 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -25,6 +25,7 @@ EXPORT_SYMBOL(cgroup_bpf_enabled_key);
25 */ 25 */
26void cgroup_bpf_put(struct cgroup *cgrp) 26void cgroup_bpf_put(struct cgroup *cgrp)
27{ 27{
28 enum bpf_cgroup_storage_type stype;
28 unsigned int type; 29 unsigned int type;
29 30
30 for (type = 0; type < ARRAY_SIZE(cgrp->bpf.progs); type++) { 31 for (type = 0; type < ARRAY_SIZE(cgrp->bpf.progs); type++) {
@@ -34,8 +35,10 @@ void cgroup_bpf_put(struct cgroup *cgrp)
34 list_for_each_entry_safe(pl, tmp, progs, node) { 35 list_for_each_entry_safe(pl, tmp, progs, node) {
35 list_del(&pl->node); 36 list_del(&pl->node);
36 bpf_prog_put(pl->prog); 37 bpf_prog_put(pl->prog);
37 bpf_cgroup_storage_unlink(pl->storage); 38 for_each_cgroup_storage_type(stype) {
38 bpf_cgroup_storage_free(pl->storage); 39 bpf_cgroup_storage_unlink(pl->storage[stype]);
40 bpf_cgroup_storage_free(pl->storage[stype]);
41 }
39 kfree(pl); 42 kfree(pl);
40 static_branch_dec(&cgroup_bpf_enabled_key); 43 static_branch_dec(&cgroup_bpf_enabled_key);
41 } 44 }
@@ -97,6 +100,7 @@ static int compute_effective_progs(struct cgroup *cgrp,
97 enum bpf_attach_type type, 100 enum bpf_attach_type type,
98 struct bpf_prog_array __rcu **array) 101 struct bpf_prog_array __rcu **array)
99{ 102{
103 enum bpf_cgroup_storage_type stype;
100 struct bpf_prog_array *progs; 104 struct bpf_prog_array *progs;
101 struct bpf_prog_list *pl; 105 struct bpf_prog_list *pl;
102 struct cgroup *p = cgrp; 106 struct cgroup *p = cgrp;
@@ -125,7 +129,9 @@ static int compute_effective_progs(struct cgroup *cgrp,
125 continue; 129 continue;
126 130
127 progs->items[cnt].prog = pl->prog; 131 progs->items[cnt].prog = pl->prog;
128 progs->items[cnt].cgroup_storage = pl->storage; 132 for_each_cgroup_storage_type(stype)
133 progs->items[cnt].cgroup_storage[stype] =
134 pl->storage[stype];
129 cnt++; 135 cnt++;
130 } 136 }
131 } while ((p = cgroup_parent(p))); 137 } while ((p = cgroup_parent(p)));
@@ -232,7 +238,9 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
232{ 238{
233 struct list_head *progs = &cgrp->bpf.progs[type]; 239 struct list_head *progs = &cgrp->bpf.progs[type];
234 struct bpf_prog *old_prog = NULL; 240 struct bpf_prog *old_prog = NULL;
235 struct bpf_cgroup_storage *storage, *old_storage = NULL; 241 struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE],
242 *old_storage[MAX_BPF_CGROUP_STORAGE_TYPE] = {NULL};
243 enum bpf_cgroup_storage_type stype;
236 struct bpf_prog_list *pl; 244 struct bpf_prog_list *pl;
237 bool pl_was_allocated; 245 bool pl_was_allocated;
238 int err; 246 int err;
@@ -254,34 +262,44 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
254 if (prog_list_length(progs) >= BPF_CGROUP_MAX_PROGS) 262 if (prog_list_length(progs) >= BPF_CGROUP_MAX_PROGS)
255 return -E2BIG; 263 return -E2BIG;
256 264
257 storage = bpf_cgroup_storage_alloc(prog); 265 for_each_cgroup_storage_type(stype) {
258 if (IS_ERR(storage)) 266 storage[stype] = bpf_cgroup_storage_alloc(prog, stype);
259 return -ENOMEM; 267 if (IS_ERR(storage[stype])) {
268 storage[stype] = NULL;
269 for_each_cgroup_storage_type(stype)
270 bpf_cgroup_storage_free(storage[stype]);
271 return -ENOMEM;
272 }
273 }
260 274
261 if (flags & BPF_F_ALLOW_MULTI) { 275 if (flags & BPF_F_ALLOW_MULTI) {
262 list_for_each_entry(pl, progs, node) { 276 list_for_each_entry(pl, progs, node) {
263 if (pl->prog == prog) { 277 if (pl->prog == prog) {
264 /* disallow attaching the same prog twice */ 278 /* disallow attaching the same prog twice */
265 bpf_cgroup_storage_free(storage); 279 for_each_cgroup_storage_type(stype)
280 bpf_cgroup_storage_free(storage[stype]);
266 return -EINVAL; 281 return -EINVAL;
267 } 282 }
268 } 283 }
269 284
270 pl = kmalloc(sizeof(*pl), GFP_KERNEL); 285 pl = kmalloc(sizeof(*pl), GFP_KERNEL);
271 if (!pl) { 286 if (!pl) {
272 bpf_cgroup_storage_free(storage); 287 for_each_cgroup_storage_type(stype)
288 bpf_cgroup_storage_free(storage[stype]);
273 return -ENOMEM; 289 return -ENOMEM;
274 } 290 }
275 291
276 pl_was_allocated = true; 292 pl_was_allocated = true;
277 pl->prog = prog; 293 pl->prog = prog;
278 pl->storage = storage; 294 for_each_cgroup_storage_type(stype)
295 pl->storage[stype] = storage[stype];
279 list_add_tail(&pl->node, progs); 296 list_add_tail(&pl->node, progs);
280 } else { 297 } else {
281 if (list_empty(progs)) { 298 if (list_empty(progs)) {
282 pl = kmalloc(sizeof(*pl), GFP_KERNEL); 299 pl = kmalloc(sizeof(*pl), GFP_KERNEL);
283 if (!pl) { 300 if (!pl) {
284 bpf_cgroup_storage_free(storage); 301 for_each_cgroup_storage_type(stype)
302 bpf_cgroup_storage_free(storage[stype]);
285 return -ENOMEM; 303 return -ENOMEM;
286 } 304 }
287 pl_was_allocated = true; 305 pl_was_allocated = true;
@@ -289,12 +307,15 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
289 } else { 307 } else {
290 pl = list_first_entry(progs, typeof(*pl), node); 308 pl = list_first_entry(progs, typeof(*pl), node);
291 old_prog = pl->prog; 309 old_prog = pl->prog;
292 old_storage = pl->storage; 310 for_each_cgroup_storage_type(stype) {
293 bpf_cgroup_storage_unlink(old_storage); 311 old_storage[stype] = pl->storage[stype];
312 bpf_cgroup_storage_unlink(old_storage[stype]);
313 }
294 pl_was_allocated = false; 314 pl_was_allocated = false;
295 } 315 }
296 pl->prog = prog; 316 pl->prog = prog;
297 pl->storage = storage; 317 for_each_cgroup_storage_type(stype)
318 pl->storage[stype] = storage[stype];
298 } 319 }
299 320
300 cgrp->bpf.flags[type] = flags; 321 cgrp->bpf.flags[type] = flags;
@@ -304,21 +325,27 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
304 goto cleanup; 325 goto cleanup;
305 326
306 static_branch_inc(&cgroup_bpf_enabled_key); 327 static_branch_inc(&cgroup_bpf_enabled_key);
307 if (old_storage) 328 for_each_cgroup_storage_type(stype) {
308 bpf_cgroup_storage_free(old_storage); 329 if (!old_storage[stype])
330 continue;
331 bpf_cgroup_storage_free(old_storage[stype]);
332 }
309 if (old_prog) { 333 if (old_prog) {
310 bpf_prog_put(old_prog); 334 bpf_prog_put(old_prog);
311 static_branch_dec(&cgroup_bpf_enabled_key); 335 static_branch_dec(&cgroup_bpf_enabled_key);
312 } 336 }
313 bpf_cgroup_storage_link(storage, cgrp, type); 337 for_each_cgroup_storage_type(stype)
338 bpf_cgroup_storage_link(storage[stype], cgrp, type);
314 return 0; 339 return 0;
315 340
316cleanup: 341cleanup:
317 /* and cleanup the prog list */ 342 /* and cleanup the prog list */
318 pl->prog = old_prog; 343 pl->prog = old_prog;
319 bpf_cgroup_storage_free(pl->storage); 344 for_each_cgroup_storage_type(stype) {
320 pl->storage = old_storage; 345 bpf_cgroup_storage_free(pl->storage[stype]);
321 bpf_cgroup_storage_link(old_storage, cgrp, type); 346 pl->storage[stype] = old_storage[stype];
347 bpf_cgroup_storage_link(old_storage[stype], cgrp, type);
348 }
322 if (pl_was_allocated) { 349 if (pl_was_allocated) {
323 list_del(&pl->node); 350 list_del(&pl->node);
324 kfree(pl); 351 kfree(pl);
@@ -339,6 +366,7 @@ int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
339 enum bpf_attach_type type, u32 unused_flags) 366 enum bpf_attach_type type, u32 unused_flags)
340{ 367{
341 struct list_head *progs = &cgrp->bpf.progs[type]; 368 struct list_head *progs = &cgrp->bpf.progs[type];
369 enum bpf_cgroup_storage_type stype;
342 u32 flags = cgrp->bpf.flags[type]; 370 u32 flags = cgrp->bpf.flags[type];
343 struct bpf_prog *old_prog = NULL; 371 struct bpf_prog *old_prog = NULL;
344 struct bpf_prog_list *pl; 372 struct bpf_prog_list *pl;
@@ -385,8 +413,10 @@ int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
385 413
386 /* now can actually delete it from this cgroup list */ 414 /* now can actually delete it from this cgroup list */
387 list_del(&pl->node); 415 list_del(&pl->node);
388 bpf_cgroup_storage_unlink(pl->storage); 416 for_each_cgroup_storage_type(stype) {
389 bpf_cgroup_storage_free(pl->storage); 417 bpf_cgroup_storage_unlink(pl->storage[stype]);
418 bpf_cgroup_storage_free(pl->storage[stype]);
419 }
390 kfree(pl); 420 kfree(pl);
391 if (list_empty(progs)) 421 if (list_empty(progs))
392 /* last program was detached, reset flags to zero */ 422 /* last program was detached, reset flags to zero */
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 1991466b8327..9070b2ace6aa 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -194,16 +194,18 @@ const struct bpf_func_proto bpf_get_current_cgroup_id_proto = {
194 .ret_type = RET_INTEGER, 194 .ret_type = RET_INTEGER,
195}; 195};
196 196
197DECLARE_PER_CPU(void*, bpf_cgroup_storage); 197#ifdef CONFIG_CGROUP_BPF
198DECLARE_PER_CPU(void*, bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]);
198 199
199BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags) 200BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags)
200{ 201{
201 /* map and flags arguments are not used now, 202 /* flags argument is not used now,
202 * but provide an ability to extend the API 203 * but provides an ability to extend the API.
203 * for other types of local storages. 204 * verifier checks that its value is correct.
204 * verifier checks that their values are correct.
205 */ 205 */
206 return (unsigned long) this_cpu_read(bpf_cgroup_storage); 206 enum bpf_cgroup_storage_type stype = cgroup_storage_type(map);
207
208 return (unsigned long) this_cpu_read(bpf_cgroup_storage[stype]);
207} 209}
208 210
209const struct bpf_func_proto bpf_get_local_storage_proto = { 211const struct bpf_func_proto bpf_get_local_storage_proto = {
@@ -214,3 +216,4 @@ const struct bpf_func_proto bpf_get_local_storage_proto = {
214 .arg2_type = ARG_ANYTHING, 216 .arg2_type = ARG_ANYTHING,
215}; 217};
216#endif 218#endif
219#endif
diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c
index 22ad967d1e5f..0bd9f19fc557 100644
--- a/kernel/bpf/local_storage.c
+++ b/kernel/bpf/local_storage.c
@@ -7,7 +7,7 @@
7#include <linux/rbtree.h> 7#include <linux/rbtree.h>
8#include <linux/slab.h> 8#include <linux/slab.h>
9 9
10DEFINE_PER_CPU(void*, bpf_cgroup_storage); 10DEFINE_PER_CPU(void*, bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]);
11 11
12#ifdef CONFIG_CGROUP_BPF 12#ifdef CONFIG_CGROUP_BPF
13 13
@@ -251,6 +251,7 @@ const struct bpf_map_ops cgroup_storage_map_ops = {
251 251
252int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *_map) 252int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *_map)
253{ 253{
254 enum bpf_cgroup_storage_type stype = cgroup_storage_type(_map);
254 struct bpf_cgroup_storage_map *map = map_to_storage(_map); 255 struct bpf_cgroup_storage_map *map = map_to_storage(_map);
255 int ret = -EBUSY; 256 int ret = -EBUSY;
256 257
@@ -258,11 +259,12 @@ int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *_map)
258 259
259 if (map->prog && map->prog != prog) 260 if (map->prog && map->prog != prog)
260 goto unlock; 261 goto unlock;
261 if (prog->aux->cgroup_storage && prog->aux->cgroup_storage != _map) 262 if (prog->aux->cgroup_storage[stype] &&
263 prog->aux->cgroup_storage[stype] != _map)
262 goto unlock; 264 goto unlock;
263 265
264 map->prog = prog; 266 map->prog = prog;
265 prog->aux->cgroup_storage = _map; 267 prog->aux->cgroup_storage[stype] = _map;
266 ret = 0; 268 ret = 0;
267unlock: 269unlock:
268 spin_unlock_bh(&map->lock); 270 spin_unlock_bh(&map->lock);
@@ -272,24 +274,26 @@ unlock:
272 274
273void bpf_cgroup_storage_release(struct bpf_prog *prog, struct bpf_map *_map) 275void bpf_cgroup_storage_release(struct bpf_prog *prog, struct bpf_map *_map)
274{ 276{
277 enum bpf_cgroup_storage_type stype = cgroup_storage_type(_map);
275 struct bpf_cgroup_storage_map *map = map_to_storage(_map); 278 struct bpf_cgroup_storage_map *map = map_to_storage(_map);
276 279
277 spin_lock_bh(&map->lock); 280 spin_lock_bh(&map->lock);
278 if (map->prog == prog) { 281 if (map->prog == prog) {
279 WARN_ON(prog->aux->cgroup_storage != _map); 282 WARN_ON(prog->aux->cgroup_storage[stype] != _map);
280 map->prog = NULL; 283 map->prog = NULL;
281 prog->aux->cgroup_storage = NULL; 284 prog->aux->cgroup_storage[stype] = NULL;
282 } 285 }
283 spin_unlock_bh(&map->lock); 286 spin_unlock_bh(&map->lock);
284} 287}
285 288
286struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog) 289struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog,
290 enum bpf_cgroup_storage_type stype)
287{ 291{
288 struct bpf_cgroup_storage *storage; 292 struct bpf_cgroup_storage *storage;
289 struct bpf_map *map; 293 struct bpf_map *map;
290 u32 pages; 294 u32 pages;
291 295
292 map = prog->aux->cgroup_storage; 296 map = prog->aux->cgroup_storage[stype];
293 if (!map) 297 if (!map)
294 return NULL; 298 return NULL;
295 299
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index b3c2d09bcf7a..8c91d2b41b1e 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -988,10 +988,15 @@ static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
988/* drop refcnt on maps used by eBPF program and free auxilary data */ 988/* drop refcnt on maps used by eBPF program and free auxilary data */
989static void free_used_maps(struct bpf_prog_aux *aux) 989static void free_used_maps(struct bpf_prog_aux *aux)
990{ 990{
991 enum bpf_cgroup_storage_type stype;
991 int i; 992 int i;
992 993
993 if (aux->cgroup_storage) 994 for_each_cgroup_storage_type(stype) {
994 bpf_cgroup_storage_release(aux->prog, aux->cgroup_storage); 995 if (!aux->cgroup_storage[stype])
996 continue;
997 bpf_cgroup_storage_release(aux->prog,
998 aux->cgroup_storage[stype]);
999 }
995 1000
996 for (i = 0; i < aux->used_map_cnt; i++) 1001 for (i = 0; i < aux->used_map_cnt; i++)
997 bpf_map_put(aux->used_maps[i]); 1002 bpf_map_put(aux->used_maps[i]);
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index e986518d7bc3..e90899df585d 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5171,11 +5171,15 @@ next_insn:
5171/* drop refcnt of maps used by the rejected program */ 5171/* drop refcnt of maps used by the rejected program */
5172static void release_maps(struct bpf_verifier_env *env) 5172static void release_maps(struct bpf_verifier_env *env)
5173{ 5173{
5174 enum bpf_cgroup_storage_type stype;
5174 int i; 5175 int i;
5175 5176
5176 if (env->prog->aux->cgroup_storage) 5177 for_each_cgroup_storage_type(stype) {
5178 if (!env->prog->aux->cgroup_storage[stype])
5179 continue;
5177 bpf_cgroup_storage_release(env->prog, 5180 bpf_cgroup_storage_release(env->prog,
5178 env->prog->aux->cgroup_storage); 5181 env->prog->aux->cgroup_storage[stype]);
5182 }
5179 5183
5180 for (i = 0; i < env->used_map_cnt; i++) 5184 for (i = 0; i < env->used_map_cnt; i++)
5181 bpf_map_put(env->used_maps[i]); 5185 bpf_map_put(env->used_maps[i]);