]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - kernel/cgroup.c
Merge tag 'devicetree-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-linux.git] / kernel / cgroup.c
index dffa54041d4a3544b0b6112de1a6363bbcd54935..bb263d0caab323810f2c30fc3799be467859a7ac 100644 (file)
@@ -277,6 +277,10 @@ static struct cgroup_subsys_state *cgroup_e_css(struct cgroup *cgrp,
        if (!(cgrp->root->subsys_mask & (1 << ss->id)))
                return NULL;
 
+       /*
+        * This function is used while updating css associations and thus
+        * can't test the csses directly.  Use ->child_subsys_mask.
+        */
        while (cgroup_parent(cgrp) &&
               !(cgroup_parent(cgrp)->child_subsys_mask & (1 << ss->id)))
                cgrp = cgroup_parent(cgrp);
@@ -284,6 +288,39 @@ static struct cgroup_subsys_state *cgroup_e_css(struct cgroup *cgrp,
        return cgroup_css(cgrp, ss);
 }
 
+/**
+ * cgroup_get_e_css - get a cgroup's effective css for the specified subsystem
+ * @cgrp: the cgroup of interest
+ * @ss: the subsystem of interest
+ *
+ * Find and get the effective css of @cgrp for @ss.  The effective css is
+ * defined as the matching css of the nearest ancestor including self which
+ * has @ss enabled.  If @ss is not mounted on the hierarchy @cgrp is on,
+ * the root css is returned, so this function always returns a valid css.
+ * The returned css must be put using css_put().
+ */
+struct cgroup_subsys_state *cgroup_get_e_css(struct cgroup *cgrp,
+                                            struct cgroup_subsys *ss)
+{
+       struct cgroup_subsys_state *css;
+
+       rcu_read_lock();
+
+       do {
+               css = cgroup_css(cgrp, ss);
+
+               if (css && css_tryget_online(css))
+                       goto out_unlock;
+               cgrp = cgroup_parent(cgrp);
+       } while (cgrp);
+
+       css = init_css_set.subsys[ss->id];
+       css_get(css);
+out_unlock:
+       rcu_read_unlock();
+       return css;
+}
+
 /* convenient tests for these bits */
 static inline bool cgroup_is_dead(const struct cgroup *cgrp)
 {
@@ -2836,6 +2873,24 @@ static ssize_t cgroup_subtree_control_write(struct kernfs_open_file *of,
                }
        }
 
+       /*
+        * The effective csses of all the descendants (excluding @cgrp) may
+        * have changed.  Subsystems can optionally subscribe to this event
+        * by implementing ->css_e_css_changed() which is invoked if any of
+        * the effective csses seen from the css's cgroup may have changed.
+        */
+       for_each_subsys(ss, ssid) {
+               struct cgroup_subsys_state *this_css = cgroup_css(cgrp, ss);
+               struct cgroup_subsys_state *css;
+
+               if (!ss->css_e_css_changed || !this_css)
+                       continue;
+
+               css_for_each_descendant_pre(css, this_css)
+                       if (css != this_css)
+                               ss->css_e_css_changed(css);
+       }
+
        kernfs_activate(cgrp->kn);
        ret = 0;
 out_unlock:
@@ -4380,6 +4435,8 @@ static void css_release_work_fn(struct work_struct *work)
        if (ss) {
                /* css release path */
                cgroup_idr_remove(&ss->css_idr, css->id);
+               if (ss->css_released)
+                       ss->css_released(css);
        } else {
                /* cgroup release path */
                cgroup_idr_remove(&cgrp->root->cgroup_idr, cgrp->id);