bpf: Simplify __cgroup_bpf_attach
authorAndrey Ignatov <rdna@fb.com>
Thu, 19 Dec 2019 07:44:33 +0000 (23:44 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 20 Dec 2019 05:22:25 +0000 (21:22 -0800)
__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: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Link: https://lore.kernel.org/bpf/c6193db6fe630797110b0d3ff06c125d093b834c.1576741281.git.rdna@fb.com
kernel/bpf/cgroup.c

index 9f90d3c92bdaca011f5645aa326fab4b09166d70..e8cbdd1be687be89702e2ea8e77e1e0ced2034be 100644 (file)
@@ -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,6 +316,16 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
        if (prog_list_length(progs) >= BPF_CGROUP_MAX_PROGS)
                return -E2BIG;
 
+       if (flags & BPF_F_ALLOW_MULTI) {
+               list_for_each_entry(pl, progs, node) {
+                       if (pl->prog == prog)
+                               /* disallow attaching the same prog twice */
+                               return -EINVAL;
+               }
+       } else if (!list_empty(progs)) {
+               replace_pl = list_first_entry(progs, typeof(*pl), node);
+       }
+
        for_each_cgroup_storage_type(stype) {
                storage[stype] = bpf_cgroup_storage_alloc(prog, stype);
                if (IS_ERR(storage[stype])) {
@@ -327,52 +336,27 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
                }
        }
 
-       if (flags & BPF_F_ALLOW_MULTI) {
-               list_for_each_entry(pl, progs, node) {
-                       if (pl->prog == prog) {
-                               /* disallow attaching the same prog twice */
-                               for_each_cgroup_storage_type(stype)
-                                       bpf_cgroup_storage_free(storage[stype]);
-                               return -EINVAL;
-                       }
+       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 {
                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;
-               pl->prog = prog;
-               for_each_cgroup_storage_type(stype)
-                       pl->storage[stype] = storage[stype];
                list_add_tail(&pl->node, progs);
-       } 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];
        }
 
+       pl->prog = prog;
+       for_each_cgroup_storage_type(stype)
+               pl->storage[stype] = storage[stype];
+
        cgrp->bpf.flags[type] = flags;
 
        err = update_effective_progs(cgrp, type);
@@ -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);
        }