mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									5bf7a60b8e
								
							
						
					
					
						commit
						8bad74f984
					
				
					 8 changed files with 139 additions and 60 deletions
				
			
		| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
#ifndef _BPF_CGROUP_H
 | 
					#ifndef _BPF_CGROUP_H
 | 
				
			||||||
#define _BPF_CGROUP_H
 | 
					#define _BPF_CGROUP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/bpf.h>
 | 
				
			||||||
#include <linux/errno.h>
 | 
					#include <linux/errno.h>
 | 
				
			||||||
#include <linux/jump_label.h>
 | 
					#include <linux/jump_label.h>
 | 
				
			||||||
#include <linux/percpu.h>
 | 
					#include <linux/percpu.h>
 | 
				
			||||||
| 
						 | 
					@ -22,7 +23,10 @@ struct bpf_cgroup_storage;
 | 
				
			||||||
extern struct static_key_false cgroup_bpf_enabled_key;
 | 
					extern struct static_key_false cgroup_bpf_enabled_key;
 | 
				
			||||||
#define cgroup_bpf_enabled static_branch_unlikely(&cgroup_bpf_enabled_key)
 | 
					#define cgroup_bpf_enabled static_branch_unlikely(&cgroup_bpf_enabled_key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DECLARE_PER_CPU(void*, bpf_cgroup_storage);
 | 
					DECLARE_PER_CPU(void*, bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define for_each_cgroup_storage_type(stype) \
 | 
				
			||||||
 | 
						for (stype = 0; stype < MAX_BPF_CGROUP_STORAGE_TYPE; stype++)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct bpf_cgroup_storage_map;
 | 
					struct bpf_cgroup_storage_map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,7 +47,7 @@ struct bpf_cgroup_storage {
 | 
				
			||||||
struct bpf_prog_list {
 | 
					struct bpf_prog_list {
 | 
				
			||||||
	struct list_head node;
 | 
						struct list_head node;
 | 
				
			||||||
	struct bpf_prog *prog;
 | 
						struct bpf_prog *prog;
 | 
				
			||||||
	struct bpf_cgroup_storage *storage;
 | 
						struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct bpf_prog_array;
 | 
					struct bpf_prog_array;
 | 
				
			||||||
| 
						 | 
					@ -101,18 +105,29 @@ int __cgroup_bpf_run_filter_sock_ops(struct sock *sk,
 | 
				
			||||||
int __cgroup_bpf_check_dev_permission(short dev_type, u32 major, u32 minor,
 | 
					int __cgroup_bpf_check_dev_permission(short dev_type, u32 major, u32 minor,
 | 
				
			||||||
				      short access, enum bpf_attach_type type);
 | 
									      short access, enum bpf_attach_type type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void bpf_cgroup_storage_set(struct bpf_cgroup_storage *storage)
 | 
					static inline enum bpf_cgroup_storage_type cgroup_storage_type(
 | 
				
			||||||
 | 
						struct bpf_map *map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct bpf_storage_buffer *buf;
 | 
						return BPF_CGROUP_STORAGE_SHARED;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!storage)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	buf = READ_ONCE(storage->buf);
 | 
					 | 
				
			||||||
	this_cpu_write(bpf_cgroup_storage, &buf->data[0]);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog);
 | 
					static inline void bpf_cgroup_storage_set(struct bpf_cgroup_storage
 | 
				
			||||||
 | 
										  *storage[MAX_BPF_CGROUP_STORAGE_TYPE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						enum bpf_cgroup_storage_type stype;
 | 
				
			||||||
 | 
						struct bpf_storage_buffer *buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for_each_cgroup_storage_type(stype) {
 | 
				
			||||||
 | 
							if (!storage[stype])
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							buf = READ_ONCE(storage[stype]->buf);
 | 
				
			||||||
 | 
							this_cpu_write(bpf_cgroup_storage[stype], &buf->data[0]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog,
 | 
				
			||||||
 | 
										enum bpf_cgroup_storage_type stype);
 | 
				
			||||||
void bpf_cgroup_storage_free(struct bpf_cgroup_storage *storage);
 | 
					void bpf_cgroup_storage_free(struct bpf_cgroup_storage *storage);
 | 
				
			||||||
void bpf_cgroup_storage_link(struct bpf_cgroup_storage *storage,
 | 
					void bpf_cgroup_storage_link(struct bpf_cgroup_storage *storage,
 | 
				
			||||||
			     struct cgroup *cgroup,
 | 
								     struct cgroup *cgroup,
 | 
				
			||||||
| 
						 | 
					@ -265,13 +280,14 @@ static inline int cgroup_bpf_prog_query(const union bpf_attr *attr,
 | 
				
			||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void bpf_cgroup_storage_set(struct bpf_cgroup_storage *storage) {}
 | 
					static inline void bpf_cgroup_storage_set(
 | 
				
			||||||
 | 
						struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE]) {}
 | 
				
			||||||
static inline int bpf_cgroup_storage_assign(struct bpf_prog *prog,
 | 
					static inline int bpf_cgroup_storage_assign(struct bpf_prog *prog,
 | 
				
			||||||
					    struct bpf_map *map) { return 0; }
 | 
										    struct bpf_map *map) { return 0; }
 | 
				
			||||||
static inline void bpf_cgroup_storage_release(struct bpf_prog *prog,
 | 
					static inline void bpf_cgroup_storage_release(struct bpf_prog *prog,
 | 
				
			||||||
					      struct bpf_map *map) {}
 | 
										      struct bpf_map *map) {}
 | 
				
			||||||
static inline struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(
 | 
					static inline struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(
 | 
				
			||||||
	struct bpf_prog *prog) { return 0; }
 | 
						struct bpf_prog *prog, enum bpf_cgroup_storage_type stype) { return 0; }
 | 
				
			||||||
static inline void bpf_cgroup_storage_free(
 | 
					static inline void bpf_cgroup_storage_free(
 | 
				
			||||||
	struct bpf_cgroup_storage *storage) {}
 | 
						struct bpf_cgroup_storage *storage) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -293,6 +309,8 @@ static inline void bpf_cgroup_storage_free(
 | 
				
			||||||
#define BPF_CGROUP_RUN_PROG_SOCK_OPS(sock_ops) ({ 0; })
 | 
					#define BPF_CGROUP_RUN_PROG_SOCK_OPS(sock_ops) ({ 0; })
 | 
				
			||||||
#define BPF_CGROUP_RUN_PROG_DEVICE_CGROUP(type,major,minor,access) ({ 0; })
 | 
					#define BPF_CGROUP_RUN_PROG_DEVICE_CGROUP(type,major,minor,access) ({ 0; })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define for_each_cgroup_storage_type(stype) for (; false; )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* CONFIG_CGROUP_BPF */
 | 
					#endif /* CONFIG_CGROUP_BPF */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _BPF_CGROUP_H */
 | 
					#endif /* _BPF_CGROUP_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -272,6 +272,13 @@ struct bpf_prog_offload {
 | 
				
			||||||
	u32			jited_len;
 | 
						u32			jited_len;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum bpf_cgroup_storage_type {
 | 
				
			||||||
 | 
						BPF_CGROUP_STORAGE_SHARED,
 | 
				
			||||||
 | 
						__BPF_CGROUP_STORAGE_MAX
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_BPF_CGROUP_STORAGE_TYPE __BPF_CGROUP_STORAGE_MAX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct bpf_prog_aux {
 | 
					struct bpf_prog_aux {
 | 
				
			||||||
	atomic_t refcnt;
 | 
						atomic_t refcnt;
 | 
				
			||||||
	u32 used_map_cnt;
 | 
						u32 used_map_cnt;
 | 
				
			||||||
| 
						 | 
					@ -289,7 +296,7 @@ struct bpf_prog_aux {
 | 
				
			||||||
	struct bpf_prog *prog;
 | 
						struct bpf_prog *prog;
 | 
				
			||||||
	struct user_struct *user;
 | 
						struct user_struct *user;
 | 
				
			||||||
	u64 load_time; /* ns since boottime */
 | 
						u64 load_time; /* ns since boottime */
 | 
				
			||||||
	struct bpf_map *cgroup_storage;
 | 
						struct bpf_map *cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE];
 | 
				
			||||||
	char name[BPF_OBJ_NAME_LEN];
 | 
						char name[BPF_OBJ_NAME_LEN];
 | 
				
			||||||
#ifdef CONFIG_SECURITY
 | 
					#ifdef CONFIG_SECURITY
 | 
				
			||||||
	void *security;
 | 
						void *security;
 | 
				
			||||||
| 
						 | 
					@ -358,7 +365,7 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct bpf_prog_array_item {
 | 
					struct bpf_prog_array_item {
 | 
				
			||||||
	struct bpf_prog *prog;
 | 
						struct bpf_prog *prog;
 | 
				
			||||||
	struct bpf_cgroup_storage *cgroup_storage;
 | 
						struct bpf_cgroup_storage *cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct bpf_prog_array {
 | 
					struct bpf_prog_array {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@ EXPORT_SYMBOL(cgroup_bpf_enabled_key);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void cgroup_bpf_put(struct cgroup *cgrp)
 | 
					void cgroup_bpf_put(struct cgroup *cgrp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						enum bpf_cgroup_storage_type stype;
 | 
				
			||||||
	unsigned int type;
 | 
						unsigned int type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (type = 0; type < ARRAY_SIZE(cgrp->bpf.progs); type++) {
 | 
						for (type = 0; type < ARRAY_SIZE(cgrp->bpf.progs); type++) {
 | 
				
			||||||
| 
						 | 
					@ -34,8 +35,10 @@ void cgroup_bpf_put(struct cgroup *cgrp)
 | 
				
			||||||
		list_for_each_entry_safe(pl, tmp, progs, node) {
 | 
							list_for_each_entry_safe(pl, tmp, progs, node) {
 | 
				
			||||||
			list_del(&pl->node);
 | 
								list_del(&pl->node);
 | 
				
			||||||
			bpf_prog_put(pl->prog);
 | 
								bpf_prog_put(pl->prog);
 | 
				
			||||||
			bpf_cgroup_storage_unlink(pl->storage);
 | 
								for_each_cgroup_storage_type(stype) {
 | 
				
			||||||
			bpf_cgroup_storage_free(pl->storage);
 | 
									bpf_cgroup_storage_unlink(pl->storage[stype]);
 | 
				
			||||||
 | 
									bpf_cgroup_storage_free(pl->storage[stype]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			kfree(pl);
 | 
								kfree(pl);
 | 
				
			||||||
			static_branch_dec(&cgroup_bpf_enabled_key);
 | 
								static_branch_dec(&cgroup_bpf_enabled_key);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -97,6 +100,7 @@ static int compute_effective_progs(struct cgroup *cgrp,
 | 
				
			||||||
				   enum bpf_attach_type type,
 | 
									   enum bpf_attach_type type,
 | 
				
			||||||
				   struct bpf_prog_array __rcu **array)
 | 
									   struct bpf_prog_array __rcu **array)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						enum bpf_cgroup_storage_type stype;
 | 
				
			||||||
	struct bpf_prog_array *progs;
 | 
						struct bpf_prog_array *progs;
 | 
				
			||||||
	struct bpf_prog_list *pl;
 | 
						struct bpf_prog_list *pl;
 | 
				
			||||||
	struct cgroup *p = cgrp;
 | 
						struct cgroup *p = cgrp;
 | 
				
			||||||
| 
						 | 
					@ -125,7 +129,9 @@ static int compute_effective_progs(struct cgroup *cgrp,
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			progs->items[cnt].prog = pl->prog;
 | 
								progs->items[cnt].prog = pl->prog;
 | 
				
			||||||
			progs->items[cnt].cgroup_storage = pl->storage;
 | 
								for_each_cgroup_storage_type(stype)
 | 
				
			||||||
 | 
									progs->items[cnt].cgroup_storage[stype] =
 | 
				
			||||||
 | 
										pl->storage[stype];
 | 
				
			||||||
			cnt++;
 | 
								cnt++;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} while ((p = cgroup_parent(p)));
 | 
						} while ((p = cgroup_parent(p)));
 | 
				
			||||||
| 
						 | 
					@ -232,7 +238,9 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct list_head *progs = &cgrp->bpf.progs[type];
 | 
						struct list_head *progs = &cgrp->bpf.progs[type];
 | 
				
			||||||
	struct bpf_prog *old_prog = NULL;
 | 
						struct bpf_prog *old_prog = NULL;
 | 
				
			||||||
	struct bpf_cgroup_storage *storage, *old_storage = NULL;
 | 
						struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE],
 | 
				
			||||||
 | 
							*old_storage[MAX_BPF_CGROUP_STORAGE_TYPE] = {NULL};
 | 
				
			||||||
 | 
						enum bpf_cgroup_storage_type stype;
 | 
				
			||||||
	struct bpf_prog_list *pl;
 | 
						struct bpf_prog_list *pl;
 | 
				
			||||||
	bool pl_was_allocated;
 | 
						bool pl_was_allocated;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
| 
						 | 
					@ -254,34 +262,44 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
 | 
				
			||||||
	if (prog_list_length(progs) >= BPF_CGROUP_MAX_PROGS)
 | 
						if (prog_list_length(progs) >= BPF_CGROUP_MAX_PROGS)
 | 
				
			||||||
		return -E2BIG;
 | 
							return -E2BIG;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	storage = bpf_cgroup_storage_alloc(prog);
 | 
						for_each_cgroup_storage_type(stype) {
 | 
				
			||||||
	if (IS_ERR(storage))
 | 
							storage[stype] = bpf_cgroup_storage_alloc(prog, stype);
 | 
				
			||||||
		return -ENOMEM;
 | 
							if (IS_ERR(storage[stype])) {
 | 
				
			||||||
 | 
								storage[stype] = NULL;
 | 
				
			||||||
 | 
								for_each_cgroup_storage_type(stype)
 | 
				
			||||||
 | 
									bpf_cgroup_storage_free(storage[stype]);
 | 
				
			||||||
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (flags & BPF_F_ALLOW_MULTI) {
 | 
						if (flags & BPF_F_ALLOW_MULTI) {
 | 
				
			||||||
		list_for_each_entry(pl, progs, node) {
 | 
							list_for_each_entry(pl, progs, node) {
 | 
				
			||||||
			if (pl->prog == prog) {
 | 
								if (pl->prog == prog) {
 | 
				
			||||||
				/* disallow attaching the same prog twice */
 | 
									/* disallow attaching the same prog twice */
 | 
				
			||||||
				bpf_cgroup_storage_free(storage);
 | 
									for_each_cgroup_storage_type(stype)
 | 
				
			||||||
 | 
										bpf_cgroup_storage_free(storage[stype]);
 | 
				
			||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pl = kmalloc(sizeof(*pl), GFP_KERNEL);
 | 
							pl = kmalloc(sizeof(*pl), GFP_KERNEL);
 | 
				
			||||||
		if (!pl) {
 | 
							if (!pl) {
 | 
				
			||||||
			bpf_cgroup_storage_free(storage);
 | 
								for_each_cgroup_storage_type(stype)
 | 
				
			||||||
 | 
									bpf_cgroup_storage_free(storage[stype]);
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pl_was_allocated = true;
 | 
							pl_was_allocated = true;
 | 
				
			||||||
		pl->prog = prog;
 | 
							pl->prog = prog;
 | 
				
			||||||
		pl->storage = storage;
 | 
							for_each_cgroup_storage_type(stype)
 | 
				
			||||||
 | 
								pl->storage[stype] = storage[stype];
 | 
				
			||||||
		list_add_tail(&pl->node, progs);
 | 
							list_add_tail(&pl->node, progs);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if (list_empty(progs)) {
 | 
							if (list_empty(progs)) {
 | 
				
			||||||
			pl = kmalloc(sizeof(*pl), GFP_KERNEL);
 | 
								pl = kmalloc(sizeof(*pl), GFP_KERNEL);
 | 
				
			||||||
			if (!pl) {
 | 
								if (!pl) {
 | 
				
			||||||
				bpf_cgroup_storage_free(storage);
 | 
									for_each_cgroup_storage_type(stype)
 | 
				
			||||||
 | 
										bpf_cgroup_storage_free(storage[stype]);
 | 
				
			||||||
				return -ENOMEM;
 | 
									return -ENOMEM;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			pl_was_allocated = true;
 | 
								pl_was_allocated = true;
 | 
				
			||||||
| 
						 | 
					@ -289,12 +307,15 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			pl = list_first_entry(progs, typeof(*pl), node);
 | 
								pl = list_first_entry(progs, typeof(*pl), node);
 | 
				
			||||||
			old_prog = pl->prog;
 | 
								old_prog = pl->prog;
 | 
				
			||||||
			old_storage = pl->storage;
 | 
								for_each_cgroup_storage_type(stype) {
 | 
				
			||||||
			bpf_cgroup_storage_unlink(old_storage);
 | 
									old_storage[stype] = pl->storage[stype];
 | 
				
			||||||
 | 
									bpf_cgroup_storage_unlink(old_storage[stype]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			pl_was_allocated = false;
 | 
								pl_was_allocated = false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		pl->prog = prog;
 | 
							pl->prog = prog;
 | 
				
			||||||
		pl->storage = storage;
 | 
							for_each_cgroup_storage_type(stype)
 | 
				
			||||||
 | 
								pl->storage[stype] = storage[stype];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cgrp->bpf.flags[type] = flags;
 | 
						cgrp->bpf.flags[type] = flags;
 | 
				
			||||||
| 
						 | 
					@ -304,21 +325,27 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
 | 
				
			||||||
		goto cleanup;
 | 
							goto cleanup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static_branch_inc(&cgroup_bpf_enabled_key);
 | 
						static_branch_inc(&cgroup_bpf_enabled_key);
 | 
				
			||||||
	if (old_storage)
 | 
						for_each_cgroup_storage_type(stype) {
 | 
				
			||||||
		bpf_cgroup_storage_free(old_storage);
 | 
							if (!old_storage[stype])
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							bpf_cgroup_storage_free(old_storage[stype]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (old_prog) {
 | 
						if (old_prog) {
 | 
				
			||||||
		bpf_prog_put(old_prog);
 | 
							bpf_prog_put(old_prog);
 | 
				
			||||||
		static_branch_dec(&cgroup_bpf_enabled_key);
 | 
							static_branch_dec(&cgroup_bpf_enabled_key);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bpf_cgroup_storage_link(storage, cgrp, type);
 | 
						for_each_cgroup_storage_type(stype)
 | 
				
			||||||
 | 
							bpf_cgroup_storage_link(storage[stype], cgrp, type);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cleanup:
 | 
					cleanup:
 | 
				
			||||||
	/* and cleanup the prog list */
 | 
						/* and cleanup the prog list */
 | 
				
			||||||
	pl->prog = old_prog;
 | 
						pl->prog = old_prog;
 | 
				
			||||||
	bpf_cgroup_storage_free(pl->storage);
 | 
						for_each_cgroup_storage_type(stype) {
 | 
				
			||||||
	pl->storage = old_storage;
 | 
							bpf_cgroup_storage_free(pl->storage[stype]);
 | 
				
			||||||
	bpf_cgroup_storage_link(old_storage, cgrp, type);
 | 
							pl->storage[stype] = old_storage[stype];
 | 
				
			||||||
 | 
							bpf_cgroup_storage_link(old_storage[stype], cgrp, type);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (pl_was_allocated) {
 | 
						if (pl_was_allocated) {
 | 
				
			||||||
		list_del(&pl->node);
 | 
							list_del(&pl->node);
 | 
				
			||||||
		kfree(pl);
 | 
							kfree(pl);
 | 
				
			||||||
| 
						 | 
					@ -339,6 +366,7 @@ int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
 | 
				
			||||||
			enum bpf_attach_type type, u32 unused_flags)
 | 
								enum bpf_attach_type type, u32 unused_flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct list_head *progs = &cgrp->bpf.progs[type];
 | 
						struct list_head *progs = &cgrp->bpf.progs[type];
 | 
				
			||||||
 | 
						enum bpf_cgroup_storage_type stype;
 | 
				
			||||||
	u32 flags = cgrp->bpf.flags[type];
 | 
						u32 flags = cgrp->bpf.flags[type];
 | 
				
			||||||
	struct bpf_prog *old_prog = NULL;
 | 
						struct bpf_prog *old_prog = NULL;
 | 
				
			||||||
	struct bpf_prog_list *pl;
 | 
						struct bpf_prog_list *pl;
 | 
				
			||||||
| 
						 | 
					@ -385,8 +413,10 @@ int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* now can actually delete it from this cgroup list */
 | 
						/* now can actually delete it from this cgroup list */
 | 
				
			||||||
	list_del(&pl->node);
 | 
						list_del(&pl->node);
 | 
				
			||||||
	bpf_cgroup_storage_unlink(pl->storage);
 | 
						for_each_cgroup_storage_type(stype) {
 | 
				
			||||||
	bpf_cgroup_storage_free(pl->storage);
 | 
							bpf_cgroup_storage_unlink(pl->storage[stype]);
 | 
				
			||||||
 | 
							bpf_cgroup_storage_free(pl->storage[stype]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	kfree(pl);
 | 
						kfree(pl);
 | 
				
			||||||
	if (list_empty(progs))
 | 
						if (list_empty(progs))
 | 
				
			||||||
		/* last program was detached, reset flags to zero */
 | 
							/* last program was detached, reset flags to zero */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,16 +194,18 @@ const struct bpf_func_proto bpf_get_current_cgroup_id_proto = {
 | 
				
			||||||
	.ret_type	= RET_INTEGER,
 | 
						.ret_type	= RET_INTEGER,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DECLARE_PER_CPU(void*, bpf_cgroup_storage);
 | 
					#ifdef CONFIG_CGROUP_BPF
 | 
				
			||||||
 | 
					DECLARE_PER_CPU(void*, bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags)
 | 
					BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* map and flags arguments are not used now,
 | 
						/* flags argument is not used now,
 | 
				
			||||||
	 * but provide an ability to extend the API
 | 
						 * but provides an ability to extend the API.
 | 
				
			||||||
	 * for other types of local storages.
 | 
						 * verifier checks that its value is correct.
 | 
				
			||||||
	 * verifier checks that their values are correct.
 | 
					 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	return (unsigned long) this_cpu_read(bpf_cgroup_storage);
 | 
						enum bpf_cgroup_storage_type stype = cgroup_storage_type(map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (unsigned long) this_cpu_read(bpf_cgroup_storage[stype]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const struct bpf_func_proto bpf_get_local_storage_proto = {
 | 
					const struct bpf_func_proto bpf_get_local_storage_proto = {
 | 
				
			||||||
| 
						 | 
					@ -214,3 +216,4 @@ const struct bpf_func_proto bpf_get_local_storage_proto = {
 | 
				
			||||||
	.arg2_type	= ARG_ANYTHING,
 | 
						.arg2_type	= ARG_ANYTHING,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,7 @@
 | 
				
			||||||
#include <linux/rbtree.h>
 | 
					#include <linux/rbtree.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFINE_PER_CPU(void*, bpf_cgroup_storage);
 | 
					DEFINE_PER_CPU(void*, bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_CGROUP_BPF
 | 
					#ifdef CONFIG_CGROUP_BPF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -251,6 +251,7 @@ const struct bpf_map_ops cgroup_storage_map_ops = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *_map)
 | 
					int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *_map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						enum bpf_cgroup_storage_type stype = cgroup_storage_type(_map);
 | 
				
			||||||
	struct bpf_cgroup_storage_map *map = map_to_storage(_map);
 | 
						struct bpf_cgroup_storage_map *map = map_to_storage(_map);
 | 
				
			||||||
	int ret = -EBUSY;
 | 
						int ret = -EBUSY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -258,11 +259,12 @@ int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *_map)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (map->prog && map->prog != prog)
 | 
						if (map->prog && map->prog != prog)
 | 
				
			||||||
		goto unlock;
 | 
							goto unlock;
 | 
				
			||||||
	if (prog->aux->cgroup_storage && prog->aux->cgroup_storage != _map)
 | 
						if (prog->aux->cgroup_storage[stype] &&
 | 
				
			||||||
 | 
						    prog->aux->cgroup_storage[stype] != _map)
 | 
				
			||||||
		goto unlock;
 | 
							goto unlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	map->prog = prog;
 | 
						map->prog = prog;
 | 
				
			||||||
	prog->aux->cgroup_storage = _map;
 | 
						prog->aux->cgroup_storage[stype] = _map;
 | 
				
			||||||
	ret = 0;
 | 
						ret = 0;
 | 
				
			||||||
unlock:
 | 
					unlock:
 | 
				
			||||||
	spin_unlock_bh(&map->lock);
 | 
						spin_unlock_bh(&map->lock);
 | 
				
			||||||
| 
						 | 
					@ -272,24 +274,26 @@ int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *_map)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void bpf_cgroup_storage_release(struct bpf_prog *prog, struct bpf_map *_map)
 | 
					void bpf_cgroup_storage_release(struct bpf_prog *prog, struct bpf_map *_map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						enum bpf_cgroup_storage_type stype = cgroup_storage_type(_map);
 | 
				
			||||||
	struct bpf_cgroup_storage_map *map = map_to_storage(_map);
 | 
						struct bpf_cgroup_storage_map *map = map_to_storage(_map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_bh(&map->lock);
 | 
						spin_lock_bh(&map->lock);
 | 
				
			||||||
	if (map->prog == prog) {
 | 
						if (map->prog == prog) {
 | 
				
			||||||
		WARN_ON(prog->aux->cgroup_storage != _map);
 | 
							WARN_ON(prog->aux->cgroup_storage[stype] != _map);
 | 
				
			||||||
		map->prog = NULL;
 | 
							map->prog = NULL;
 | 
				
			||||||
		prog->aux->cgroup_storage = NULL;
 | 
							prog->aux->cgroup_storage[stype] = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	spin_unlock_bh(&map->lock);
 | 
						spin_unlock_bh(&map->lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog)
 | 
					struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog,
 | 
				
			||||||
 | 
										enum bpf_cgroup_storage_type stype)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct bpf_cgroup_storage *storage;
 | 
						struct bpf_cgroup_storage *storage;
 | 
				
			||||||
	struct bpf_map *map;
 | 
						struct bpf_map *map;
 | 
				
			||||||
	u32 pages;
 | 
						u32 pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	map = prog->aux->cgroup_storage;
 | 
						map = prog->aux->cgroup_storage[stype];
 | 
				
			||||||
	if (!map)
 | 
						if (!map)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -988,10 +988,15 @@ static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
 | 
				
			||||||
/* drop refcnt on maps used by eBPF program and free auxilary data */
 | 
					/* drop refcnt on maps used by eBPF program and free auxilary data */
 | 
				
			||||||
static void free_used_maps(struct bpf_prog_aux *aux)
 | 
					static void free_used_maps(struct bpf_prog_aux *aux)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						enum bpf_cgroup_storage_type stype;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (aux->cgroup_storage)
 | 
						for_each_cgroup_storage_type(stype) {
 | 
				
			||||||
		bpf_cgroup_storage_release(aux->prog, aux->cgroup_storage);
 | 
							if (!aux->cgroup_storage[stype])
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							bpf_cgroup_storage_release(aux->prog,
 | 
				
			||||||
 | 
										   aux->cgroup_storage[stype]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < aux->used_map_cnt; i++)
 | 
						for (i = 0; i < aux->used_map_cnt; i++)
 | 
				
			||||||
		bpf_map_put(aux->used_maps[i]);
 | 
							bpf_map_put(aux->used_maps[i]);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5171,11 +5171,15 @@ static int replace_map_fd_with_map_ptr(struct bpf_verifier_env *env)
 | 
				
			||||||
/* drop refcnt of maps used by the rejected program */
 | 
					/* drop refcnt of maps used by the rejected program */
 | 
				
			||||||
static void release_maps(struct bpf_verifier_env *env)
 | 
					static void release_maps(struct bpf_verifier_env *env)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						enum bpf_cgroup_storage_type stype;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (env->prog->aux->cgroup_storage)
 | 
						for_each_cgroup_storage_type(stype) {
 | 
				
			||||||
 | 
							if (!env->prog->aux->cgroup_storage[stype])
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
		bpf_cgroup_storage_release(env->prog,
 | 
							bpf_cgroup_storage_release(env->prog,
 | 
				
			||||||
					   env->prog->aux->cgroup_storage);
 | 
								env->prog->aux->cgroup_storage[stype]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < env->used_map_cnt; i++)
 | 
						for (i = 0; i < env->used_map_cnt; i++)
 | 
				
			||||||
		bpf_map_put(env->used_maps[i]);
 | 
							bpf_map_put(env->used_maps[i]);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,7 @@
 | 
				
			||||||
#include <linux/sched/signal.h>
 | 
					#include <linux/sched/signal.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __always_inline u32 bpf_test_run_one(struct bpf_prog *prog, void *ctx,
 | 
					static __always_inline u32 bpf_test_run_one(struct bpf_prog *prog, void *ctx,
 | 
				
			||||||
					    struct bpf_cgroup_storage *storage)
 | 
							struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 ret;
 | 
						u32 ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,13 +28,20 @@ static __always_inline u32 bpf_test_run_one(struct bpf_prog *prog, void *ctx,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static u32 bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, u32 *time)
 | 
					static u32 bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, u32 *time)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct bpf_cgroup_storage *storage = NULL;
 | 
						struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE] = { 0 };
 | 
				
			||||||
 | 
						enum bpf_cgroup_storage_type stype;
 | 
				
			||||||
	u64 time_start, time_spent = 0;
 | 
						u64 time_start, time_spent = 0;
 | 
				
			||||||
	u32 ret = 0, i;
 | 
						u32 ret = 0, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	storage = bpf_cgroup_storage_alloc(prog);
 | 
						for_each_cgroup_storage_type(stype) {
 | 
				
			||||||
	if (IS_ERR(storage))
 | 
							storage[stype] = bpf_cgroup_storage_alloc(prog, stype);
 | 
				
			||||||
		return PTR_ERR(storage);
 | 
							if (IS_ERR(storage[stype])) {
 | 
				
			||||||
 | 
								storage[stype] = NULL;
 | 
				
			||||||
 | 
								for_each_cgroup_storage_type(stype)
 | 
				
			||||||
 | 
									bpf_cgroup_storage_free(storage[stype]);
 | 
				
			||||||
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!repeat)
 | 
						if (!repeat)
 | 
				
			||||||
		repeat = 1;
 | 
							repeat = 1;
 | 
				
			||||||
| 
						 | 
					@ -53,7 +60,8 @@ static u32 bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, u32 *time)
 | 
				
			||||||
	do_div(time_spent, repeat);
 | 
						do_div(time_spent, repeat);
 | 
				
			||||||
	*time = time_spent > U32_MAX ? U32_MAX : (u32)time_spent;
 | 
						*time = time_spent > U32_MAX ? U32_MAX : (u32)time_spent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bpf_cgroup_storage_free(storage);
 | 
						for_each_cgroup_storage_type(stype)
 | 
				
			||||||
 | 
							bpf_cgroup_storage_free(storage[stype]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue