diff options
author | Tejun Heo <tj@kernel.org> | 2014-05-16 13:22:48 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2014-05-16 13:22:48 -0400 |
commit | ea280e7b408ca0dad195ce9836feccdd1dc32131 (patch) | |
tree | 524a648df41fbd7dc270c225212d96d10b5a7815 /mm/memcontrol.c | |
parent | f61c42a7d9119a8b72b9607ba8e3a34111f81d8c (diff) |
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>
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 6144a8e7283f..b6f91d61b3af 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -4834,18 +4834,28 @@ static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg) | |||
4834 | } while (usage > 0); | 4834 | } while (usage > 0); |
4835 | } | 4835 | } |
4836 | 4836 | ||
4837 | /* | ||
4838 | * Test whether @memcg has children, dead or alive. Note that this | ||
4839 | * function doesn't care whether @memcg has use_hierarchy enabled and | ||
4840 | * returns %true if there are child csses according to the cgroup | ||
4841 | * hierarchy. Testing use_hierarchy is the caller's responsiblity. | ||
4842 | */ | ||
4837 | static inline bool memcg_has_children(struct mem_cgroup *memcg) | 4843 | static inline bool memcg_has_children(struct mem_cgroup *memcg) |
4838 | { | 4844 | { |
4839 | lockdep_assert_held(&memcg_create_mutex); | 4845 | bool ret; |
4846 | |||
4840 | /* | 4847 | /* |
4841 | * The lock does not prevent addition or deletion to the list | 4848 | * The lock does not prevent addition or deletion of children, but |
4842 | * of children, but it prevents a new child from being | 4849 | * it prevents a new child from being initialized based on this |
4843 | * initialized based on this parent in css_online(), so it's | 4850 | * parent in css_online(), so it's enough to decide whether |
4844 | * enough to decide whether hierarchically inherited | 4851 | * hierarchically inherited attributes can still be changed or not. |
4845 | * attributes can still be changed or not. | ||
4846 | */ | 4852 | */ |
4847 | return memcg->use_hierarchy && | 4853 | lockdep_assert_held(&memcg_create_mutex); |
4848 | !list_empty(&memcg->css.cgroup->children); | 4854 | |
4855 | rcu_read_lock(); | ||
4856 | ret = css_next_child(NULL, &memcg->css); | ||
4857 | rcu_read_unlock(); | ||
4858 | return ret; | ||
4849 | } | 4859 | } |
4850 | 4860 | ||
4851 | /* | 4861 | /* |
@@ -4919,7 +4929,7 @@ static int mem_cgroup_hierarchy_write(struct cgroup_subsys_state *css, | |||
4919 | */ | 4929 | */ |
4920 | if ((!parent_memcg || !parent_memcg->use_hierarchy) && | 4930 | if ((!parent_memcg || !parent_memcg->use_hierarchy) && |
4921 | (val == 1 || val == 0)) { | 4931 | (val == 1 || val == 0)) { |
4922 | if (list_empty(&memcg->css.cgroup->children)) | 4932 | if (!memcg_has_children(memcg)) |
4923 | memcg->use_hierarchy = val; | 4933 | memcg->use_hierarchy = val; |
4924 | else | 4934 | else |
4925 | retval = -EBUSY; | 4935 | retval = -EBUSY; |
@@ -5036,7 +5046,8 @@ static int __memcg_activate_kmem(struct mem_cgroup *memcg, | |||
5036 | * of course permitted. | 5046 | * of course permitted. |
5037 | */ | 5047 | */ |
5038 | mutex_lock(&memcg_create_mutex); | 5048 | mutex_lock(&memcg_create_mutex); |
5039 | if (cgroup_has_tasks(memcg->css.cgroup) || memcg_has_children(memcg)) | 5049 | if (cgroup_has_tasks(memcg->css.cgroup) || |
5050 | (memcg->use_hierarchy && memcg_has_children(memcg))) | ||
5040 | err = -EBUSY; | 5051 | err = -EBUSY; |
5041 | mutex_unlock(&memcg_create_mutex); | 5052 | mutex_unlock(&memcg_create_mutex); |
5042 | if (err) | 5053 | if (err) |