Commit 1020c1f2 authored by Andrey Ignatov's avatar Andrey Ignatov Committed by Alexei Starovoitov
Browse files

bpf: Simplify __cgroup_bpf_attach



__cgroup_bpf_attach has a lot of identical code to handle two scenarios:
BPF_F_ALLOW_MULTI is set and unset.

Simplify it by splitting the two main steps:

* First, the decision is made whether a new bpf_prog_list entry should
  be allocated or existing entry should be reused for the new program.
  This decision is saved in replace_pl pointer;

* Next, replace_pl pointer is used to handle both possible states of
  BPF_F_ALLOW_MULTI flag (set / unset) instead of doing similar work for
  them separately.

This splitting, in turn, allows to make further simplifications:

* The check for attaching same program twice in BPF_F_ALLOW_MULTI mode
  can be done before allocating cgroup storage, so that if user tries to
  attach same program twice no alloc/free happens as it was before;

* pl_was_allocated becomes redundant so it's removed.

Signed-off-by: default avatarAndrey Ignatov <rdna@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarMartin KaFai Lau <kafai@fb.com>
Acked-by: default avatarAndrii Nakryiko <andriin@fb.com>
Link: https://lore.kernel.org/bpf/c6193db6fe630797110b0d3ff06c125d093b834c.1576741281.git.rdna@fb.com
parent c92bbaa0
Loading
Loading
Loading
Loading
+23 −39
Original line number Diff line number Diff line
@@ -295,9 +295,8 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
	struct bpf_prog *old_prog = NULL;
	struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE],
		*old_storage[MAX_BPF_CGROUP_STORAGE_TYPE] = {NULL};
	struct bpf_prog_list *pl, *replace_pl = NULL;
	enum bpf_cgroup_storage_type stype;
	struct bpf_prog_list *pl;
	bool pl_was_allocated;
	int err;

	if ((flags & BPF_F_ALLOW_OVERRIDE) && (flags & BPF_F_ALLOW_MULTI))
@@ -317,61 +316,46 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
	if (prog_list_length(progs) >= BPF_CGROUP_MAX_PROGS)
		return -E2BIG;

	for_each_cgroup_storage_type(stype) {
		storage[stype] = bpf_cgroup_storage_alloc(prog, stype);
		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) {
		list_for_each_entry(pl, progs, node) {
			if (pl->prog == prog) {
			if (pl->prog == prog)
				/* disallow attaching the same prog twice */
				for_each_cgroup_storage_type(stype)
					bpf_cgroup_storage_free(storage[stype]);
				return -EINVAL;
		}
	} else if (!list_empty(progs)) {
		replace_pl = list_first_entry(progs, typeof(*pl), node);
	}

		pl = kmalloc(sizeof(*pl), GFP_KERNEL);
		if (!pl) {
	for_each_cgroup_storage_type(stype) {
		storage[stype] = bpf_cgroup_storage_alloc(prog, stype);
		if (IS_ERR(storage[stype])) {
			storage[stype] = NULL;
			for_each_cgroup_storage_type(stype)
				bpf_cgroup_storage_free(storage[stype]);
			return -ENOMEM;
		}
	}

		pl_was_allocated = true;
		pl->prog = prog;
		for_each_cgroup_storage_type(stype)
			pl->storage[stype] = storage[stype];
		list_add_tail(&pl->node, progs);
	if (replace_pl) {
		pl = replace_pl;
		old_prog = pl->prog;
		for_each_cgroup_storage_type(stype) {
			old_storage[stype] = pl->storage[stype];
			bpf_cgroup_storage_unlink(old_storage[stype]);
		}
	} else {
		if (list_empty(progs)) {
		pl = kmalloc(sizeof(*pl), GFP_KERNEL);
		if (!pl) {
			for_each_cgroup_storage_type(stype)
				bpf_cgroup_storage_free(storage[stype]);
			return -ENOMEM;
		}
			pl_was_allocated = true;
		list_add_tail(&pl->node, progs);
		} else {
			pl = list_first_entry(progs, typeof(*pl), node);
			old_prog = pl->prog;
			for_each_cgroup_storage_type(stype) {
				old_storage[stype] = pl->storage[stype];
				bpf_cgroup_storage_unlink(old_storage[stype]);
			}
			pl_was_allocated = false;
	}

	pl->prog = prog;
	for_each_cgroup_storage_type(stype)
		pl->storage[stype] = storage[stype];
	}

	cgrp->bpf.flags[type] = flags;

@@ -401,7 +385,7 @@ cleanup:
		pl->storage[stype] = old_storage[stype];
		bpf_cgroup_storage_link(old_storage[stype], cgrp, type);
	}
	if (pl_was_allocated) {
	if (!replace_pl) {
		list_del(&pl->node);
		kfree(pl);
	}