aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memcontrol.c
diff options
context:
space:
mode:
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)