memcg: update memcg_has_children() to use css_next_child()
Currently, memcg_has_children() and mem_cgroup_hierarchy_write() directly test cgroup->children for list emptiness. It's semantically correct in traditional hierarchies as it actually wants to test for any children dead or alive; however, cgroup->children is not a published field and scheduled to go away. This patch moves out .use_hierarchy test out of memcg_has_children() and updates it to use css_next_child() to test whether there exists any children. With .use_hierarchy test moved out, it can also be used by mem_cgroup_hierarchy_write(). A side note: As .use_hierarchy is going away, it doesn't really matter but I'm not sure about how it's used in __memcg_activate_kmem(). The condition tested by memcg_has_children() is mushy when seen from userland as its result is affected by dead csses which aren't visible from userland. I think the rule would be a lot clearer if we have a dedicated "freshly minted" flag which gets cleared when the first task is migrated into it or the first child is created and then gate activation with that. v2: Added comment noting that testing use_hierarchy is the responsibility of the callers of memcg_has_children() as suggested by Michal Hocko. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Michal Hocko <mhocko@suse.cz> Acked-by: Li Zefan <lizefan@huawei.com> Cc: Johannes Weiner <hannes@cmpxchg.org>
This commit is contained in:
parent
f61c42a7d9
commit
ea280e7b40
|
@ -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
|
* The lock does not prevent addition or deletion of children, but
|
||||||
* of children, but it prevents a new child from being
|
* it prevents a new child from being initialized based on this
|
||||||
* initialized based on this parent in css_online(), so it's
|
* parent in css_online(), so it's enough to decide whether
|
||||||
* enough to decide whether hierarchically inherited
|
* hierarchically inherited attributes can still be changed or not.
|
||||||
* attributes can still be changed or not.
|
|
||||||
*/
|
*/
|
||||||
return memcg->use_hierarchy &&
|
lockdep_assert_held(&memcg_create_mutex);
|
||||||
!list_empty(&memcg->css.cgroup->children);
|
|
||||||
|
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)
|
||||||
|
|
Loading…
Reference in New Issue