aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memcontrol.c
diff options
context:
space:
mode:
authorMichal Hocko <mhocko@suse.cz>2012-10-26 07:37:28 -0400
committerTejun Heo <tj@kernel.org>2012-10-29 19:22:21 -0400
commitc26251f9f06d27d1941229d237aca44a0e7b4e42 (patch)
tree6460f272a925acccb381aa4f939b6ce169e46f9c /mm/memcontrol.c
parenta0d271cbfed1dd50278c6b06bead3d00ba0a88f9 (diff)
memcg: split mem_cgroup_force_empty into reclaiming and reparenting parts
mem_cgroup_force_empty did two separate things depending on free_all parameter from the very beginning. It either reclaimed as many pages as possible and moved the rest to the parent or just moved charges to the parent. The first variant is used as memory.force_empty callback while the later is used from the mem_cgroup_pre_destroy. The whole games around gotos are far from being nice and there is no reason to keep those two functions inside one. Let's split them and also move the responsibility for css reference counting to their callers to make to code easier. This patch doesn't have any functional changes. Signed-off-by: Michal Hocko <mhocko@suse.cz> Reviewed-by: Tejun Heo <tj@kernel.org> Reviewed-by: Glauber Costa <glommer@parallels.com> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r--mm/memcontrol.c72
1 files changed, 42 insertions, 30 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 795e525afaba..07d92b84f448 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -3739,27 +3739,21 @@ static bool mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
3739} 3739}
3740 3740
3741/* 3741/*
3742 * make mem_cgroup's charge to be 0 if there is no task. 3742 * make mem_cgroup's charge to be 0 if there is no task by moving
3743 * all the charges and pages to the parent.
3743 * This enables deleting this mem_cgroup. 3744 * This enables deleting this mem_cgroup.
3745 *
3746 * Caller is responsible for holding css reference on the memcg.
3744 */ 3747 */
3745static int mem_cgroup_force_empty(struct mem_cgroup *memcg, bool free_all) 3748static int mem_cgroup_reparent_charges(struct mem_cgroup *memcg)
3746{ 3749{
3747 int ret;
3748 int node, zid, shrink;
3749 int nr_retries = MEM_CGROUP_RECLAIM_RETRIES;
3750 struct cgroup *cgrp = memcg->css.cgroup; 3750 struct cgroup *cgrp = memcg->css.cgroup;
3751 int node, zid;
3752 int ret;
3751 3753
3752 css_get(&memcg->css);
3753
3754 shrink = 0;
3755 /* should free all ? */
3756 if (free_all)
3757 goto try_to_free;
3758move_account:
3759 do { 3754 do {
3760 ret = -EBUSY;
3761 if (cgroup_task_count(cgrp) || !list_empty(&cgrp->children)) 3755 if (cgroup_task_count(cgrp) || !list_empty(&cgrp->children))
3762 goto out; 3756 return -EBUSY;
3763 /* This is for making all *used* pages to be on LRU. */ 3757 /* This is for making all *used* pages to be on LRU. */
3764 lru_add_drain_all(); 3758 lru_add_drain_all();
3765 drain_all_stock_sync(memcg); 3759 drain_all_stock_sync(memcg);
@@ -3783,27 +3777,34 @@ move_account:
3783 cond_resched(); 3777 cond_resched();
3784 /* "ret" should also be checked to ensure all lists are empty. */ 3778 /* "ret" should also be checked to ensure all lists are empty. */
3785 } while (res_counter_read_u64(&memcg->res, RES_USAGE) > 0 || ret); 3779 } while (res_counter_read_u64(&memcg->res, RES_USAGE) > 0 || ret);
3786out: 3780
3787 css_put(&memcg->css);
3788 return ret; 3781 return ret;
3782}
3783
3784/*
3785 * Reclaims as many pages from the given memcg as possible and moves
3786 * the rest to the parent.
3787 *
3788 * Caller is responsible for holding css reference for memcg.
3789 */
3790static int mem_cgroup_force_empty(struct mem_cgroup *memcg)
3791{
3792 int nr_retries = MEM_CGROUP_RECLAIM_RETRIES;
3793 struct cgroup *cgrp = memcg->css.cgroup;
3789 3794
3790try_to_free:
3791 /* returns EBUSY if there is a task or if we come here twice. */ 3795 /* returns EBUSY if there is a task or if we come here twice. */
3792 if (cgroup_task_count(cgrp) || !list_empty(&cgrp->children) || shrink) { 3796 if (cgroup_task_count(cgrp) || !list_empty(&cgrp->children))
3793 ret = -EBUSY; 3797 return -EBUSY;
3794 goto out; 3798
3795 }
3796 /* we call try-to-free pages for make this cgroup empty */ 3799 /* we call try-to-free pages for make this cgroup empty */
3797 lru_add_drain_all(); 3800 lru_add_drain_all();
3798 /* try to free all pages in this cgroup */ 3801 /* try to free all pages in this cgroup */
3799 shrink = 1;
3800 while (nr_retries && res_counter_read_u64(&memcg->res, RES_USAGE) > 0) { 3802 while (nr_retries && res_counter_read_u64(&memcg->res, RES_USAGE) > 0) {
3801 int progress; 3803 int progress;
3802 3804
3803 if (signal_pending(current)) { 3805 if (signal_pending(current))
3804 ret = -EINTR; 3806 return -EINTR;
3805 goto out; 3807
3806 }
3807 progress = try_to_free_mem_cgroup_pages(memcg, GFP_KERNEL, 3808 progress = try_to_free_mem_cgroup_pages(memcg, GFP_KERNEL,
3808 false); 3809 false);
3809 if (!progress) { 3810 if (!progress) {
@@ -3814,13 +3815,19 @@ try_to_free:
3814 3815
3815 } 3816 }
3816 lru_add_drain(); 3817 lru_add_drain();
3817 /* try move_account...there may be some *locked* pages. */ 3818 return mem_cgroup_reparent_charges(memcg);
3818 goto move_account;
3819} 3819}
3820 3820
3821static int mem_cgroup_force_empty_write(struct cgroup *cont, unsigned int event) 3821static int mem_cgroup_force_empty_write(struct cgroup *cont, unsigned int event)
3822{ 3822{
3823 return mem_cgroup_force_empty(mem_cgroup_from_cont(cont), true); 3823 struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
3824 int ret;
3825
3826 css_get(&memcg->css);
3827 ret = mem_cgroup_force_empty(memcg);
3828 css_put(&memcg->css);
3829
3830 return ret;
3824} 3831}
3825 3832
3826 3833
@@ -5003,8 +5010,13 @@ free_out:
5003static int mem_cgroup_pre_destroy(struct cgroup *cont) 5010static int mem_cgroup_pre_destroy(struct cgroup *cont)
5004{ 5011{
5005 struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); 5012 struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
5013 int ret;
5006 5014
5007 return mem_cgroup_force_empty(memcg, false); 5015 css_get(&memcg->css);
5016 ret = mem_cgroup_reparent_charges(memcg);
5017 css_put(&memcg->css);
5018
5019 return ret;
5008} 5020}
5009 5021
5010static void mem_cgroup_destroy(struct cgroup *cont) 5022static void mem_cgroup_destroy(struct cgroup *cont)