Merge tag 'for-5.13-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[linux-2.6-microblaze.git] / kernel / cgroup / rstat.c
index d51175c..3a3fd29 100644 (file)
@@ -25,13 +25,8 @@ static struct cgroup_rstat_cpu *cgroup_rstat_cpu(struct cgroup *cgrp, int cpu)
 void cgroup_rstat_updated(struct cgroup *cgrp, int cpu)
 {
        raw_spinlock_t *cpu_lock = per_cpu_ptr(&cgroup_rstat_cpu_lock, cpu);
-       struct cgroup *parent;
        unsigned long flags;
 
-       /* nothing to do for root */
-       if (!cgroup_parent(cgrp))
-               return;
-
        /*
         * Speculative already-on-list test. This may race leading to
         * temporary inaccuracies, which is fine.
@@ -46,10 +41,10 @@ void cgroup_rstat_updated(struct cgroup *cgrp, int cpu)
        raw_spin_lock_irqsave(cpu_lock, flags);
 
        /* put @cgrp and all ancestors on the corresponding updated lists */
-       for (parent = cgroup_parent(cgrp); parent;
-            cgrp = parent, parent = cgroup_parent(cgrp)) {
+       while (true) {
                struct cgroup_rstat_cpu *rstatc = cgroup_rstat_cpu(cgrp, cpu);
-               struct cgroup_rstat_cpu *prstatc = cgroup_rstat_cpu(parent, cpu);
+               struct cgroup *parent = cgroup_parent(cgrp);
+               struct cgroup_rstat_cpu *prstatc;
 
                /*
                 * Both additions and removals are bottom-up.  If a cgroup
@@ -58,8 +53,17 @@ void cgroup_rstat_updated(struct cgroup *cgrp, int cpu)
                if (rstatc->updated_next)
                        break;
 
+               /* Root has no parent to link it to, but mark it busy */
+               if (!parent) {
+                       rstatc->updated_next = cgrp;
+                       break;
+               }
+
+               prstatc = cgroup_rstat_cpu(parent, cpu);
                rstatc->updated_next = prstatc->updated_children;
                prstatc->updated_children = cgrp;
+
+               cgrp = parent;
        }
 
        raw_spin_unlock_irqrestore(cpu_lock, flags);
@@ -113,23 +117,26 @@ static struct cgroup *cgroup_rstat_cpu_pop_updated(struct cgroup *pos,
         */
        if (rstatc->updated_next) {
                struct cgroup *parent = cgroup_parent(pos);
-               struct cgroup_rstat_cpu *prstatc = cgroup_rstat_cpu(parent, cpu);
-               struct cgroup_rstat_cpu *nrstatc;
-               struct cgroup **nextp;
-
-               nextp = &prstatc->updated_children;
-               while (true) {
-                       nrstatc = cgroup_rstat_cpu(*nextp, cpu);
-                       if (*nextp == pos)
-                               break;
-
-                       WARN_ON_ONCE(*nextp == parent);
-                       nextp = &nrstatc->updated_next;
+
+               if (parent) {
+                       struct cgroup_rstat_cpu *prstatc;
+                       struct cgroup **nextp;
+
+                       prstatc = cgroup_rstat_cpu(parent, cpu);
+                       nextp = &prstatc->updated_children;
+                       while (true) {
+                               struct cgroup_rstat_cpu *nrstatc;
+
+                               nrstatc = cgroup_rstat_cpu(*nextp, cpu);
+                               if (*nextp == pos)
+                                       break;
+                               WARN_ON_ONCE(*nextp == parent);
+                               nextp = &nrstatc->updated_next;
+                       }
+                       *nextp = rstatc->updated_next;
                }
 
-               *nextp = rstatc->updated_next;
                rstatc->updated_next = NULL;
-
                return pos;
        }
 
@@ -285,8 +292,6 @@ void __init cgroup_rstat_boot(void)
 
        for_each_possible_cpu(cpu)
                raw_spin_lock_init(per_cpu_ptr(&cgroup_rstat_cpu_lock, cpu));
-
-       BUG_ON(cgroup_rstat_init(&cgrp_dfl_root.cgrp));
 }
 
 /*
@@ -311,11 +316,15 @@ static void cgroup_base_stat_sub(struct cgroup_base_stat *dst_bstat,
 
 static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu)
 {
-       struct cgroup *parent = cgroup_parent(cgrp);
        struct cgroup_rstat_cpu *rstatc = cgroup_rstat_cpu(cgrp, cpu);
+       struct cgroup *parent = cgroup_parent(cgrp);
        struct cgroup_base_stat cur, delta;
        unsigned seq;
 
+       /* Root-level stats are sourced from system-wide CPU stats */
+       if (!parent)
+               return;
+
        /* fetch the current per-cpu values */
        do {
                seq = __u64_stats_fetch_begin(&rstatc->bsync);
@@ -328,8 +337,8 @@ static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu)
        cgroup_base_stat_add(&cgrp->bstat, &delta);
        cgroup_base_stat_add(&rstatc->last_bstat, &delta);
 
-       /* propagate global delta to parent */
-       if (parent) {
+       /* propagate global delta to parent (unless that's root) */
+       if (cgroup_parent(parent)) {
                delta = cgrp->bstat;
                cgroup_base_stat_sub(&delta, &cgrp->last_bstat);
                cgroup_base_stat_add(&parent->bstat, &delta);