|
@@ -4762,6 +4762,33 @@ static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg)
|
|
|
} while (usage > 0);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * This mainly exists for tests during the setting of set of use_hierarchy.
|
|
|
+ * Since this is the very setting we are changing, the current hierarchy value
|
|
|
+ * is meaningless
|
|
|
+ */
|
|
|
+static inline bool __memcg_has_children(struct mem_cgroup *memcg)
|
|
|
+{
|
|
|
+ struct cgroup *pos;
|
|
|
+
|
|
|
+ /* bounce at first found */
|
|
|
+ cgroup_for_each_child(pos, memcg->css.cgroup)
|
|
|
+ return true;
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Must be called with cgroup_lock held, unless the cgroup is guaranteed to be
|
|
|
+ * already dead (in mem_cgroup_force_empty(), for instance). This is different
|
|
|
+ * from mem_cgroup_count_children(), in the sense that we don't really care how
|
|
|
+ * many children we have; we only need to know if we have any. It also counts
|
|
|
+ * any memcg without hierarchy as infertile.
|
|
|
+ */
|
|
|
+static inline bool memcg_has_children(struct mem_cgroup *memcg)
|
|
|
+{
|
|
|
+ return memcg->use_hierarchy && __memcg_has_children(memcg);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Reclaims as many pages from the given memcg as possible and moves
|
|
|
* the rest to the parent.
|
|
@@ -4847,7 +4874,7 @@ static int mem_cgroup_hierarchy_write(struct cgroup *cont, struct cftype *cft,
|
|
|
*/
|
|
|
if ((!parent_memcg || !parent_memcg->use_hierarchy) &&
|
|
|
(val == 1 || val == 0)) {
|
|
|
- if (list_empty(&cont->children))
|
|
|
+ if (!__memcg_has_children(memcg))
|
|
|
memcg->use_hierarchy = val;
|
|
|
else
|
|
|
retval = -EBUSY;
|
|
@@ -4964,8 +4991,7 @@ static int memcg_update_kmem_limit(struct cgroup *cont, u64 val)
|
|
|
cgroup_lock();
|
|
|
mutex_lock(&set_limit_mutex);
|
|
|
if (!memcg->kmem_account_flags && val != RESOURCE_MAX) {
|
|
|
- if (cgroup_task_count(cont) || (memcg->use_hierarchy &&
|
|
|
- !list_empty(&cont->children))) {
|
|
|
+ if (cgroup_task_count(cont) || memcg_has_children(memcg)) {
|
|
|
ret = -EBUSY;
|
|
|
goto out;
|
|
|
}
|
|
@@ -5373,8 +5399,7 @@ static int mem_cgroup_swappiness_write(struct cgroup *cgrp, struct cftype *cft,
|
|
|
cgroup_lock();
|
|
|
|
|
|
/* If under hierarchy, only empty-root can set this value */
|
|
|
- if ((parent->use_hierarchy) ||
|
|
|
- (memcg->use_hierarchy && !list_empty(&cgrp->children))) {
|
|
|
+ if ((parent->use_hierarchy) || memcg_has_children(memcg)) {
|
|
|
cgroup_unlock();
|
|
|
return -EINVAL;
|
|
|
}
|
|
@@ -5709,8 +5734,7 @@ static int mem_cgroup_oom_control_write(struct cgroup *cgrp,
|
|
|
|
|
|
cgroup_lock();
|
|
|
/* oom-kill-disable is a flag for subhierarchy. */
|
|
|
- if ((parent->use_hierarchy) ||
|
|
|
- (memcg->use_hierarchy && !list_empty(&cgrp->children))) {
|
|
|
+ if ((parent->use_hierarchy) || memcg_has_children(memcg)) {
|
|
|
cgroup_unlock();
|
|
|
return -EINVAL;
|
|
|
}
|