|
@@ -4834,18 +4834,28 @@ static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg)
|
|
} while (usage > 0);
|
|
} while (usage > 0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Test whether @memcg has children, dead or alive. Note that this
|
|
|
|
+ * function doesn't care whether @memcg has use_hierarchy enabled and
|
|
|
|
+ * returns %true if there are child csses according to the cgroup
|
|
|
|
+ * hierarchy. Testing use_hierarchy is the caller's responsiblity.
|
|
|
|
+ */
|
|
static inline bool memcg_has_children(struct mem_cgroup *memcg)
|
|
static inline bool memcg_has_children(struct mem_cgroup *memcg)
|
|
{
|
|
{
|
|
- lockdep_assert_held(&memcg_create_mutex);
|
|
|
|
|
|
+ bool ret;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
- * The lock does not prevent addition or deletion to the list
|
|
|
|
- * of children, but it prevents a new child from being
|
|
|
|
- * initialized based on this parent in css_online(), so it's
|
|
|
|
- * enough to decide whether hierarchically inherited
|
|
|
|
- * attributes can still be changed or not.
|
|
|
|
|
|
+ * The lock does not prevent addition or deletion of children, but
|
|
|
|
+ * it prevents a new child from being initialized based on this
|
|
|
|
+ * parent in css_online(), so it's enough to decide whether
|
|
|
|
+ * hierarchically inherited attributes can still be changed or not.
|
|
*/
|
|
*/
|
|
- return memcg->use_hierarchy &&
|
|
|
|
- !list_empty(&memcg->css.cgroup->children);
|
|
|
|
|
|
+ lockdep_assert_held(&memcg_create_mutex);
|
|
|
|
+
|
|
|
|
+ rcu_read_lock();
|
|
|
|
+ ret = css_next_child(NULL, &memcg->css);
|
|
|
|
+ rcu_read_unlock();
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -4919,7 +4929,7 @@ static int mem_cgroup_hierarchy_write(struct cgroup_subsys_state *css,
|
|
*/
|
|
*/
|
|
if ((!parent_memcg || !parent_memcg->use_hierarchy) &&
|
|
if ((!parent_memcg || !parent_memcg->use_hierarchy) &&
|
|
(val == 1 || val == 0)) {
|
|
(val == 1 || val == 0)) {
|
|
- if (list_empty(&memcg->css.cgroup->children))
|
|
|
|
|
|
+ if (!memcg_has_children(memcg))
|
|
memcg->use_hierarchy = val;
|
|
memcg->use_hierarchy = val;
|
|
else
|
|
else
|
|
retval = -EBUSY;
|
|
retval = -EBUSY;
|
|
@@ -5036,7 +5046,8 @@ static int __memcg_activate_kmem(struct mem_cgroup *memcg,
|
|
* of course permitted.
|
|
* of course permitted.
|
|
*/
|
|
*/
|
|
mutex_lock(&memcg_create_mutex);
|
|
mutex_lock(&memcg_create_mutex);
|
|
- if (cgroup_has_tasks(memcg->css.cgroup) || memcg_has_children(memcg))
|
|
|
|
|
|
+ if (cgroup_has_tasks(memcg->css.cgroup) ||
|
|
|
|
+ (memcg->use_hierarchy && memcg_has_children(memcg)))
|
|
err = -EBUSY;
|
|
err = -EBUSY;
|
|
mutex_unlock(&memcg_create_mutex);
|
|
mutex_unlock(&memcg_create_mutex);
|
|
if (err)
|
|
if (err)
|