aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memcontrol.c
diff options
context:
space:
mode:
authorGlauber Costa <glommer@parallels.com>2013-02-22 19:34:53 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-23 20:50:18 -0500
commitb5f99b537d047072bd50ff5c51000613eb537be8 (patch)
tree59d1cae2ef46ede8f966226782661fbe8da5825b /mm/memcontrol.c
parentd142e3e66731a0fb205a8158f5eec6f79a2ee478 (diff)
memcg: fast hierarchy-aware child test
Currently, we use cgroups' provided list of children to verify if it is safe to proceed with any value change that is dependent on the cgroup being empty. This is less than ideal, because it enforces a dependency over cgroup core that we would be better off without. The solution proposed here is to iterate over the child cgroups and if any is found that is already online, we bounce and return: we don't really care how many children we have, only if we have any. This is also made to be hierarchy aware. IOW, cgroups with hierarchy disabled, while they still exist, will be considered for the purpose of this interface as having no children. [akpm@linux-foundation.org: tweak comments] Signed-off-by: Glauber Costa <glommer@parallels.com> Acked-by: Michal Hocko <mhocko@suse.cz> Cc: Tejun Heo <tj@kernel.org> Cc: Hiroyuki Kamezawa <kamezawa.hiroyuki@gmail.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r--mm/memcontrol.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index a9318963d5d5..2bc3fbe93154 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -4763,6 +4763,33 @@ static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg)
4763} 4763}
4764 4764
4765/* 4765/*
4766 * This mainly exists for tests during the setting of set of use_hierarchy.
4767 * Since this is the very setting we are changing, the current hierarchy value
4768 * is meaningless
4769 */
4770static inline bool __memcg_has_children(struct mem_cgroup *memcg)
4771{
4772 struct cgroup *pos;
4773
4774 /* bounce at first found */
4775 cgroup_for_each_child(pos, memcg->css.cgroup)
4776 return true;
4777 return false;
4778}
4779
4780/*
4781 * Must be called with cgroup_lock held, unless the cgroup is guaranteed to be
4782 * already dead (in mem_cgroup_force_empty(), for instance). This is different
4783 * from mem_cgroup_count_children(), in the sense that we don't really care how
4784 * many children we have; we only need to know if we have any. It also counts
4785 * any memcg without hierarchy as infertile.
4786 */
4787static inline bool memcg_has_children(struct mem_cgroup *memcg)
4788{
4789 return memcg->use_hierarchy && __memcg_has_children(memcg);
4790}
4791
4792/*
4766 * Reclaims as many pages from the given memcg as possible and moves 4793 * Reclaims as many pages from the given memcg as possible and moves
4767 * the rest to the parent. 4794 * the rest to the parent.
4768 * 4795 *
@@ -4847,7 +4874,7 @@ static int mem_cgroup_hierarchy_write(struct cgroup *cont, struct cftype *cft,
4847 */ 4874 */
4848 if ((!parent_memcg || !parent_memcg->use_hierarchy) && 4875 if ((!parent_memcg || !parent_memcg->use_hierarchy) &&
4849 (val == 1 || val == 0)) { 4876 (val == 1 || val == 0)) {
4850 if (list_empty(&cont->children)) 4877 if (!__memcg_has_children(memcg))
4851 memcg->use_hierarchy = val; 4878 memcg->use_hierarchy = val;
4852 else 4879 else
4853 retval = -EBUSY; 4880 retval = -EBUSY;
@@ -4964,8 +4991,7 @@ static int memcg_update_kmem_limit(struct cgroup *cont, u64 val)
4964 cgroup_lock(); 4991 cgroup_lock();
4965 mutex_lock(&set_limit_mutex); 4992 mutex_lock(&set_limit_mutex);
4966 if (!memcg->kmem_account_flags && val != RESOURCE_MAX) { 4993 if (!memcg->kmem_account_flags && val != RESOURCE_MAX) {
4967 if (cgroup_task_count(cont) || (memcg->use_hierarchy && 4994 if (cgroup_task_count(cont) || memcg_has_children(memcg)) {
4968 !list_empty(&cont->children))) {
4969 ret = -EBUSY; 4995 ret = -EBUSY;
4970 goto out; 4996 goto out;
4971 } 4997 }
@@ -5373,8 +5399,7 @@ static int mem_cgroup_swappiness_write(struct cgroup *cgrp, struct cftype *cft,
5373 cgroup_lock(); 5399 cgroup_lock();
5374 5400
5375 /* If under hierarchy, only empty-root can set this value */ 5401 /* If under hierarchy, only empty-root can set this value */
5376 if ((parent->use_hierarchy) || 5402 if ((parent->use_hierarchy) || memcg_has_children(memcg)) {
5377 (memcg->use_hierarchy && !list_empty(&cgrp->children))) {
5378 cgroup_unlock(); 5403 cgroup_unlock();
5379 return -EINVAL; 5404 return -EINVAL;
5380 } 5405 }
@@ -5709,8 +5734,7 @@ static int mem_cgroup_oom_control_write(struct cgroup *cgrp,
5709 5734
5710 cgroup_lock(); 5735 cgroup_lock();
5711 /* oom-kill-disable is a flag for subhierarchy. */ 5736 /* oom-kill-disable is a flag for subhierarchy. */
5712 if ((parent->use_hierarchy) || 5737 if ((parent->use_hierarchy) || memcg_has_children(memcg)) {
5713 (memcg->use_hierarchy && !list_empty(&cgrp->children))) {
5714 cgroup_unlock(); 5738 cgroup_unlock();
5715 return -EINVAL; 5739 return -EINVAL;
5716 } 5740 }