]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
cgroup/freezer: Reduce redundant traversal for cgroup_freeze
authorChen Ridong <chenridong@huawei.com>
Tue, 22 Oct 2024 11:49:45 +0000 (11:49 +0000)
committerTejun Heo <tj@kernel.org>
Wed, 23 Oct 2024 19:45:00 +0000 (09:45 -1000)
Whether a cgroup is frozen is determined solely by whether it is set to
to be frozen and whether its parent is frozen. Currently, when is cgroup
is frozen or unfrozen, it iterates through the entire subtree to freeze
or unfreeze its descentdants. However, this is unesessary for a cgroup
that does not change its effective frozen status. This path aims to skip
the subtree if its parent does not have a change in effective freeze.

For an example, subtree like, a-b-c-d-e-f-g, when a is frozen, the
entire tree is frozen. If we freeze b and c again, it is unesessary to
iterate d, e, f and g. So does that If we unfreeze b/c.

Reviewed-by: Michal Koutný <mkoutny@suse.com>
Signed-off-by: Chen Ridong <chenridong@huawei.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
include/linux/cgroup-defs.h
kernel/cgroup/freezer.c

index 0a80ef9191a6e629ed2b9e394918a09f3687a78e..1b20d2d8ef7ccec2d3bd5463ececf8c4c44cf646 100644 (file)
@@ -398,7 +398,7 @@ struct cgroup_freezer_state {
        bool freeze;
 
        /* Should the cgroup actually be frozen? */
-       int e_freeze;
+       bool e_freeze;
 
        /* Fields below are protected by css_set_lock */
 
index 617861a5479357056cb2a9d7de4f9a2ad9060232..188d5f2aeb5aa6f4282ef4f445f1ec5cdcf709de 100644 (file)
@@ -260,8 +260,10 @@ void cgroup_freezer_migrate_task(struct task_struct *task,
 void cgroup_freeze(struct cgroup *cgrp, bool freeze)
 {
        struct cgroup_subsys_state *css;
+       struct cgroup *parent;
        struct cgroup *dsct;
        bool applied = false;
+       bool old_e;
 
        lockdep_assert_held(&cgroup_mutex);
 
@@ -282,22 +284,18 @@ void cgroup_freeze(struct cgroup *cgrp, bool freeze)
                if (cgroup_is_dead(dsct))
                        continue;
 
-               if (freeze) {
-                       dsct->freezer.e_freeze++;
-                       /*
-                        * Already frozen because of ancestor's settings?
-                        */
-                       if (dsct->freezer.e_freeze > 1)
-                               continue;
-               } else {
-                       dsct->freezer.e_freeze--;
-                       /*
-                        * Still frozen because of ancestor's settings?
-                        */
-                       if (dsct->freezer.e_freeze > 0)
-                               continue;
-
-                       WARN_ON_ONCE(dsct->freezer.e_freeze < 0);
+               /*
+                * e_freeze is affected by parent's e_freeze and dst's freeze.
+                * If old e_freeze eq new e_freeze, no change, its children
+                * will not be affected. So do nothing and skip the subtree
+                */
+               old_e = dsct->freezer.e_freeze;
+               parent = cgroup_parent(dsct);
+               dsct->freezer.e_freeze = (dsct->freezer.freeze ||
+                                         parent->freezer.e_freeze);
+               if (dsct->freezer.e_freeze == old_e) {
+                       css = css_rightmost_descendant(css);
+                       continue;
                }
 
                /*