From e003ff9dd29449c2bb417ec4cc0c317941ba3d59 Mon Sep 17 00:00:00 2001 From: Daisuke Nishimura Date: Wed, 10 Mar 2010 15:22:16 -0800 Subject: [PATCH] --- yaml --- r: 187215 b: refs/heads/master c: 8033b97c9b5ef063e3f4bf2efe1cd0a22093aaff h: refs/heads/master i: 187213: cb7df0104ae84a1d0e64e1b7c5fb4b16fc9e122b 187211: 8c534201988adcba62724b5e9e03dfd23a586e23 187207: ab0468a6cea7f88a1dada933562d017cde40b968 187199: d69791ec55eaafc4bf6b1cddb7a4cf3aab3d369e v: v3 --- [refs] | 2 +- trunk/mm/memcontrol.c | 53 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/[refs] b/[refs] index b27cf98be38e..6b389e044b3c 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 854ffa8d104e44111fec96764c0e0cb29223d54c +refs/heads/master: 8033b97c9b5ef063e3f4bf2efe1cd0a22093aaff diff --git a/trunk/mm/memcontrol.c b/trunk/mm/memcontrol.c index f5fb9917787c..589084f00b70 100644 --- a/trunk/mm/memcontrol.c +++ b/trunk/mm/memcontrol.c @@ -254,7 +254,11 @@ static struct move_charge_struct { struct mem_cgroup *to; unsigned long precharge; unsigned long moved_charge; -} mc; + struct task_struct *moving_task; /* a task moving charges */ + wait_queue_head_t waitq; /* a waitq for other context */ +} mc = { + .waitq = __WAIT_QUEUE_HEAD_INITIALIZER(mc.waitq), +}; /* * Maximum loops in mem_cgroup_hierarchical_reclaim(), used for soft @@ -1508,6 +1512,48 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, if (mem_cgroup_check_under_limit(mem_over_limit)) continue; + /* try to avoid oom while someone is moving charge */ + if (mc.moving_task && current != mc.moving_task) { + struct mem_cgroup *from, *to; + bool do_continue = false; + /* + * There is a small race that "from" or "to" can be + * freed by rmdir, so we use css_tryget(). + */ + rcu_read_lock(); + from = mc.from; + to = mc.to; + if (from && css_tryget(&from->css)) { + if (mem_over_limit->use_hierarchy) + do_continue = css_is_ancestor( + &from->css, + &mem_over_limit->css); + else + do_continue = (from == mem_over_limit); + css_put(&from->css); + } + if (!do_continue && to && css_tryget(&to->css)) { + if (mem_over_limit->use_hierarchy) + do_continue = css_is_ancestor( + &to->css, + &mem_over_limit->css); + else + do_continue = (to == mem_over_limit); + css_put(&to->css); + } + rcu_read_unlock(); + if (do_continue) { + DEFINE_WAIT(wait); + prepare_to_wait(&mc.waitq, &wait, + TASK_INTERRUPTIBLE); + /* moving charge context might have finished. */ + if (mc.moving_task) + schedule(); + finish_wait(&mc.waitq, &wait); + continue; + } + } + if (!nr_retries--) { if (oom) { mem_cgroup_out_of_memory(mem_over_limit, gfp_mask); @@ -3381,7 +3427,6 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont) INIT_WORK(&stock->work, drain_local_stock); } hotcpu_notifier(memcg_stock_cpu_callback, 0); - } else { parent = mem_cgroup_from_cont(cont->parent); mem->use_hierarchy = parent->use_hierarchy; @@ -3641,6 +3686,8 @@ static void mem_cgroup_clear_mc(void) } mc.from = NULL; mc.to = NULL; + mc.moving_task = NULL; + wake_up_all(&mc.waitq); } static int mem_cgroup_can_attach(struct cgroup_subsys *ss, @@ -3666,10 +3713,12 @@ static int mem_cgroup_can_attach(struct cgroup_subsys *ss, VM_BUG_ON(mc.to); VM_BUG_ON(mc.precharge); VM_BUG_ON(mc.moved_charge); + VM_BUG_ON(mc.moving_task); mc.from = from; mc.to = mem; mc.precharge = 0; mc.moved_charge = 0; + mc.moving_task = current; ret = mem_cgroup_precharge_mc(mm); if (ret)