aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memcontrol.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r--mm/memcontrol.c82
1 files changed, 55 insertions, 27 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 9a99cfaf0a19..7a22b4129211 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -61,7 +61,14 @@ struct mem_cgroup *root_mem_cgroup __read_mostly;
61#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP 61#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
62/* Turned on only when memory cgroup is enabled && really_do_swap_account = 1 */ 62/* Turned on only when memory cgroup is enabled && really_do_swap_account = 1 */
63int do_swap_account __read_mostly; 63int do_swap_account __read_mostly;
64static int really_do_swap_account __initdata = 1; /* for remember boot option*/ 64
65/* for remember boot option*/
66#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED
67static int really_do_swap_account __initdata = 1;
68#else
69static int really_do_swap_account __initdata = 0;
70#endif
71
65#else 72#else
66#define do_swap_account (0) 73#define do_swap_account (0)
67#endif 74#endif
@@ -278,13 +285,14 @@ enum move_type {
278 285
279/* "mc" and its members are protected by cgroup_mutex */ 286/* "mc" and its members are protected by cgroup_mutex */
280static struct move_charge_struct { 287static struct move_charge_struct {
281 spinlock_t lock; /* for from, to, moving_task */ 288 spinlock_t lock; /* for from, to */
282 struct mem_cgroup *from; 289 struct mem_cgroup *from;
283 struct mem_cgroup *to; 290 struct mem_cgroup *to;
284 unsigned long precharge; 291 unsigned long precharge;
285 unsigned long moved_charge; 292 unsigned long moved_charge;
286 unsigned long moved_swap; 293 unsigned long moved_swap;
287 struct task_struct *moving_task; /* a task moving charges */ 294 struct task_struct *moving_task; /* a task moving charges */
295 struct mm_struct *mm;
288 wait_queue_head_t waitq; /* a waitq for other context */ 296 wait_queue_head_t waitq; /* a waitq for other context */
289} mc = { 297} mc = {
290 .lock = __SPIN_LOCK_UNLOCKED(mc.lock), 298 .lock = __SPIN_LOCK_UNLOCKED(mc.lock),
@@ -2152,7 +2160,7 @@ static void __mem_cgroup_move_account(struct page_cgroup *pc,
2152{ 2160{
2153 VM_BUG_ON(from == to); 2161 VM_BUG_ON(from == to);
2154 VM_BUG_ON(PageLRU(pc->page)); 2162 VM_BUG_ON(PageLRU(pc->page));
2155 VM_BUG_ON(!PageCgroupLocked(pc)); 2163 VM_BUG_ON(!page_is_cgroup_locked(pc));
2156 VM_BUG_ON(!PageCgroupUsed(pc)); 2164 VM_BUG_ON(!PageCgroupUsed(pc));
2157 VM_BUG_ON(pc->mem_cgroup != from); 2165 VM_BUG_ON(pc->mem_cgroup != from);
2158 2166
@@ -4208,15 +4216,17 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
4208 4216
4209 memset(mem, 0, size); 4217 memset(mem, 0, size);
4210 mem->stat = alloc_percpu(struct mem_cgroup_stat_cpu); 4218 mem->stat = alloc_percpu(struct mem_cgroup_stat_cpu);
4211 if (!mem->stat) { 4219 if (!mem->stat)
4212 if (size < PAGE_SIZE) 4220 goto out_free;
4213 kfree(mem);
4214 else
4215 vfree(mem);
4216 mem = NULL;
4217 }
4218 spin_lock_init(&mem->pcp_counter_lock); 4221 spin_lock_init(&mem->pcp_counter_lock);
4219 return mem; 4222 return mem;
4223
4224out_free:
4225 if (size < PAGE_SIZE)
4226 kfree(mem);
4227 else
4228 vfree(mem);
4229 return NULL;
4220} 4230}
4221 4231
4222/* 4232/*
@@ -4629,7 +4639,7 @@ static unsigned long mem_cgroup_count_precharge(struct mm_struct *mm)
4629 unsigned long precharge; 4639 unsigned long precharge;
4630 struct vm_area_struct *vma; 4640 struct vm_area_struct *vma;
4631 4641
4632 down_read(&mm->mmap_sem); 4642 /* We've already held the mmap_sem */
4633 for (vma = mm->mmap; vma; vma = vma->vm_next) { 4643 for (vma = mm->mmap; vma; vma = vma->vm_next) {
4634 struct mm_walk mem_cgroup_count_precharge_walk = { 4644 struct mm_walk mem_cgroup_count_precharge_walk = {
4635 .pmd_entry = mem_cgroup_count_precharge_pte_range, 4645 .pmd_entry = mem_cgroup_count_precharge_pte_range,
@@ -4641,7 +4651,6 @@ static unsigned long mem_cgroup_count_precharge(struct mm_struct *mm)
4641 walk_page_range(vma->vm_start, vma->vm_end, 4651 walk_page_range(vma->vm_start, vma->vm_end,
4642 &mem_cgroup_count_precharge_walk); 4652 &mem_cgroup_count_precharge_walk);
4643 } 4653 }
4644 up_read(&mm->mmap_sem);
4645 4654
4646 precharge = mc.precharge; 4655 precharge = mc.precharge;
4647 mc.precharge = 0; 4656 mc.precharge = 0;
@@ -4692,11 +4701,16 @@ static void mem_cgroup_clear_mc(void)
4692 4701
4693 mc.moved_swap = 0; 4702 mc.moved_swap = 0;
4694 } 4703 }
4704 if (mc.mm) {
4705 up_read(&mc.mm->mmap_sem);
4706 mmput(mc.mm);
4707 }
4695 spin_lock(&mc.lock); 4708 spin_lock(&mc.lock);
4696 mc.from = NULL; 4709 mc.from = NULL;
4697 mc.to = NULL; 4710 mc.to = NULL;
4698 mc.moving_task = NULL;
4699 spin_unlock(&mc.lock); 4711 spin_unlock(&mc.lock);
4712 mc.moving_task = NULL;
4713 mc.mm = NULL;
4700 mem_cgroup_end_move(from); 4714 mem_cgroup_end_move(from);
4701 memcg_oom_recover(from); 4715 memcg_oom_recover(from);
4702 memcg_oom_recover(to); 4716 memcg_oom_recover(to);
@@ -4722,12 +4736,21 @@ static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
4722 return 0; 4736 return 0;
4723 /* We move charges only when we move a owner of the mm */ 4737 /* We move charges only when we move a owner of the mm */
4724 if (mm->owner == p) { 4738 if (mm->owner == p) {
4739 /*
4740 * We do all the move charge works under one mmap_sem to
4741 * avoid deadlock with down_write(&mmap_sem)
4742 * -> try_charge() -> if (mc.moving_task) -> sleep.
4743 */
4744 down_read(&mm->mmap_sem);
4745
4725 VM_BUG_ON(mc.from); 4746 VM_BUG_ON(mc.from);
4726 VM_BUG_ON(mc.to); 4747 VM_BUG_ON(mc.to);
4727 VM_BUG_ON(mc.precharge); 4748 VM_BUG_ON(mc.precharge);
4728 VM_BUG_ON(mc.moved_charge); 4749 VM_BUG_ON(mc.moved_charge);
4729 VM_BUG_ON(mc.moved_swap); 4750 VM_BUG_ON(mc.moved_swap);
4730 VM_BUG_ON(mc.moving_task); 4751 VM_BUG_ON(mc.moving_task);
4752 VM_BUG_ON(mc.mm);
4753
4731 mem_cgroup_start_move(from); 4754 mem_cgroup_start_move(from);
4732 spin_lock(&mc.lock); 4755 spin_lock(&mc.lock);
4733 mc.from = from; 4756 mc.from = from;
@@ -4735,14 +4758,16 @@ static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
4735 mc.precharge = 0; 4758 mc.precharge = 0;
4736 mc.moved_charge = 0; 4759 mc.moved_charge = 0;
4737 mc.moved_swap = 0; 4760 mc.moved_swap = 0;
4738 mc.moving_task = current;
4739 spin_unlock(&mc.lock); 4761 spin_unlock(&mc.lock);
4762 mc.moving_task = current;
4763 mc.mm = mm;
4740 4764
4741 ret = mem_cgroup_precharge_mc(mm); 4765 ret = mem_cgroup_precharge_mc(mm);
4742 if (ret) 4766 if (ret)
4743 mem_cgroup_clear_mc(); 4767 mem_cgroup_clear_mc();
4744 } 4768 /* We call up_read() and mmput() in clear_mc(). */
4745 mmput(mm); 4769 } else
4770 mmput(mm);
4746 } 4771 }
4747 return ret; 4772 return ret;
4748} 4773}
@@ -4830,7 +4855,7 @@ static void mem_cgroup_move_charge(struct mm_struct *mm)
4830 struct vm_area_struct *vma; 4855 struct vm_area_struct *vma;
4831 4856
4832 lru_add_drain_all(); 4857 lru_add_drain_all();
4833 down_read(&mm->mmap_sem); 4858 /* We've already held the mmap_sem */
4834 for (vma = mm->mmap; vma; vma = vma->vm_next) { 4859 for (vma = mm->mmap; vma; vma = vma->vm_next) {
4835 int ret; 4860 int ret;
4836 struct mm_walk mem_cgroup_move_charge_walk = { 4861 struct mm_walk mem_cgroup_move_charge_walk = {
@@ -4849,7 +4874,6 @@ static void mem_cgroup_move_charge(struct mm_struct *mm)
4849 */ 4874 */
4850 break; 4875 break;
4851 } 4876 }
4852 up_read(&mm->mmap_sem);
4853} 4877}
4854 4878
4855static void mem_cgroup_move_task(struct cgroup_subsys *ss, 4879static void mem_cgroup_move_task(struct cgroup_subsys *ss,
@@ -4858,17 +4882,11 @@ static void mem_cgroup_move_task(struct cgroup_subsys *ss,
4858 struct task_struct *p, 4882 struct task_struct *p,
4859 bool threadgroup) 4883 bool threadgroup)
4860{ 4884{
4861 struct mm_struct *mm; 4885 if (!mc.mm)
4862
4863 if (!mc.to)
4864 /* no need to move charge */ 4886 /* no need to move charge */
4865 return; 4887 return;
4866 4888
4867 mm = get_task_mm(p); 4889 mem_cgroup_move_charge(mc.mm);
4868 if (mm) {
4869 mem_cgroup_move_charge(mm);
4870 mmput(mm);
4871 }
4872 mem_cgroup_clear_mc(); 4890 mem_cgroup_clear_mc();
4873} 4891}
4874#else /* !CONFIG_MMU */ 4892#else /* !CONFIG_MMU */
@@ -4909,10 +4927,20 @@ struct cgroup_subsys mem_cgroup_subsys = {
4909}; 4927};
4910 4928
4911#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP 4929#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
4930static int __init enable_swap_account(char *s)
4931{
4932 /* consider enabled if no parameter or 1 is given */
4933 if (!s || !strcmp(s, "1"))
4934 really_do_swap_account = 1;
4935 else if (!strcmp(s, "0"))
4936 really_do_swap_account = 0;
4937 return 1;
4938}
4939__setup("swapaccount", enable_swap_account);
4912 4940
4913static int __init disable_swap_account(char *s) 4941static int __init disable_swap_account(char *s)
4914{ 4942{
4915 really_do_swap_account = 0; 4943 enable_swap_account("0");
4916 return 1; 4944 return 1;
4917} 4945}
4918__setup("noswapaccount", disable_swap_account); 4946__setup("noswapaccount", disable_swap_account);