diff options
author | Michal Hocko <mhocko@suse.cz> | 2012-10-26 07:37:28 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2012-10-29 19:22:21 -0400 |
commit | c26251f9f06d27d1941229d237aca44a0e7b4e42 (patch) | |
tree | 6460f272a925acccb381aa4f939b6ce169e46f9c /mm/memcontrol.c | |
parent | a0d271cbfed1dd50278c6b06bead3d00ba0a88f9 (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.c | 72 |
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 | */ |
3745 | static int mem_cgroup_force_empty(struct mem_cgroup *memcg, bool free_all) | 3748 | static 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; | ||
3758 | move_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); |
3786 | out: | 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 | */ | ||
3790 | static 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 | ||
3790 | try_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 | ||
3821 | static int mem_cgroup_force_empty_write(struct cgroup *cont, unsigned int event) | 3821 | static 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: | |||
5003 | static int mem_cgroup_pre_destroy(struct cgroup *cont) | 5010 | static 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 | ||
5010 | static void mem_cgroup_destroy(struct cgroup *cont) | 5022 | static void mem_cgroup_destroy(struct cgroup *cont) |