]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
cgroup: distinguish local and children populated states
authorTejun Heo <tj@kernel.org>
Mon, 17 Jul 2017 01:43:33 +0000 (21:43 -0400)
committerTejun Heo <tj@kernel.org>
Mon, 17 Jul 2017 01:44:42 +0000 (21:44 -0400)
cgrp->populated_cnt counts both local (the cgroup's populated
css_sets) and subtree proper (populated children) so that it's only
zero when the whole subtree, including self, is empty.

This patch splits the counter into two so that local and children
populated states are tracked separately.  It allows finer-grained
tests on the state of the hierarchy which will be used to replace
css_set walking local populated test.

Signed-off-by: Tejun Heo <tj@kernel.org>
include/linux/cgroup-defs.h
include/linux/cgroup.h
kernel/cgroup/cgroup.c

index 09f4c7df1478e6c6b8fea1cfc4912ed66219bd34..ae7bc1e7008596a63976cb7c0a498fb8be50cd3d 100644 (file)
@@ -263,11 +263,16 @@ struct cgroup {
 
        /*
         * Each non-empty css_set associated with this cgroup contributes
-        * one to populated_cnt.  All children with non-zero popuplated_cnt
-        * of their own contribute one.  The count is zero iff there's no
-        * task in this cgroup or its subtree.
+        * one to nr_populated_csets.  The counter is zero iff this cgroup
+        * doesn't have any tasks.
+        *
+        * All children which have non-zero nr_populated_csets and/or
+        * nr_populated_children of their own contribute one to
+        * nr_populated_children.  The counter is zero iff this cgroup's
+        * subtree proper doesn't have any tasks.
         */
-       int populated_cnt;
+       int nr_populated_csets;
+       int nr_populated_children;
 
        struct kernfs_node *kn;         /* cgroup kernfs entry */
        struct cgroup_file procs_file;  /* handle for "cgroup.procs" */
index 710a005c6b7a652bb9c32b5457dbd64196f6f4a0..308b10797a5440360a427b77f499619a380fe92a 100644 (file)
@@ -537,7 +537,7 @@ static inline bool task_under_cgroup_hierarchy(struct task_struct *task,
 /* no synchronization, the result can only be used as a hint */
 static inline bool cgroup_is_populated(struct cgroup *cgrp)
 {
-       return cgrp->populated_cnt;
+       return cgrp->nr_populated_csets + cgrp->nr_populated_children;
 }
 
 /* returns ino associated with a cgroup */
index 4f02b5edd82ca145b28932974d0e63ce74bab4ec..5fe2644cd0f321aab38810c12388426ffb252a20 100644 (file)
@@ -587,39 +587,44 @@ static bool css_set_populated(struct css_set *cset)
 }
 
 /**
- * cgroup_update_populated - updated populated count of a cgroup
+ * cgroup_update_populated - update the populated count of a cgroup
  * @cgrp: the target cgroup
  * @populated: inc or dec populated count
  *
  * One of the css_sets associated with @cgrp is either getting its first
- * task or losing the last.  Update @cgrp->populated_cnt accordingly.  The
- * count is propagated towards root so that a given cgroup's populated_cnt
- * is zero iff the cgroup and all its descendants don't contain any tasks.
+ * task or losing the last.  Update @cgrp->nr_populated_* accordingly.  The
+ * count is propagated towards root so that a given cgroup's
+ * nr_populated_children is zero iff none of its descendants contain any
+ * tasks.
  *
- * @cgrp's interface file "cgroup.populated" is zero if
- * @cgrp->populated_cnt is zero and 1 otherwise.  When @cgrp->populated_cnt
- * changes from or to zero, userland is notified that the content of the
- * interface file has changed.  This can be used to detect when @cgrp and
- * its descendants become populated or empty.
+ * @cgrp's interface file "cgroup.populated" is zero if both
+ * @cgrp->nr_populated_csets and @cgrp->nr_populated_children are zero and
+ * 1 otherwise.  When the sum changes from or to zero, userland is notified
+ * that the content of the interface file has changed.  This can be used to
+ * detect when @cgrp and its descendants become populated or empty.
  */
 static void cgroup_update_populated(struct cgroup *cgrp, bool populated)
 {
+       struct cgroup *child = NULL;
+       int adj = populated ? 1 : -1;
+
        lockdep_assert_held(&css_set_lock);
 
        do {
-               bool trigger;
+               bool was_populated = cgroup_is_populated(cgrp);
 
-               if (populated)
-                       trigger = !cgrp->populated_cnt++;
+               if (!child)
+                       cgrp->nr_populated_csets += adj;
                else
-                       trigger = !--cgrp->populated_cnt;
+                       cgrp->nr_populated_children += adj;
 
-               if (!trigger)
+               if (was_populated == cgroup_is_populated(cgrp))
                        break;
 
                cgroup1_check_for_release(cgrp);
                cgroup_file_notify(&cgrp->events_file);
 
+               child = cgrp;
                cgrp = cgroup_parent(cgrp);
        } while (cgrp);
 }
@@ -630,7 +635,7 @@ static void cgroup_update_populated(struct cgroup *cgrp, bool populated)
  * @populated: whether @cset is populated or depopulated
  *
  * @cset is either getting the first task or losing the last.  Update the
- * ->populated_cnt of all associated cgroups accordingly.
+ * populated counters of all associated cgroups accordingly.
  */
 static void css_set_update_populated(struct css_set *cset, bool populated)
 {
@@ -653,7 +658,7 @@ static void css_set_update_populated(struct css_set *cset, bool populated)
  * css_set, @from_cset can be NULL.  If @task is being disassociated
  * instead of moved, @to_cset can be NULL.
  *
- * This function automatically handles populated_cnt updates and
+ * This function automatically handles populated counter updates and
  * css_task_iter adjustments but the caller is responsible for managing
  * @from_cset and @to_cset's reference counts.
  */