[PATCH -mmotm 7/8] memcg: avoid oom during recharge at task move

Daisuke Nishimura
2009-11-06T05:33:28Z

This recharge-at-task-move feature has extra charges(pre-charges) on "to"
mem_cgroup during recharging. This means unnecessary oom can happen.

This patch tries to avoid such oom.

Signed-off-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
---
mm/memcontrol.c | 27 +++++++++++++++++++++++++++
1 files changed, 27 insertions(+), 0 deletions(-)

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index f4b7116..7e96f3b 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -248,6 +248,7 @@ struct recharge_struct {
struct mem_cgroup *from;
struct mem_cgroup *to;
struct task_struct *target; /* the target task being moved */
+ struct task_struct *working; /* a task moving the target task */
unsigned long precharge;
};
static struct recharge_struct recharge;
@@ -1493,6 +1494,30 @@ 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 recharging */
+ if (recharge.working && current != recharge.working) {
+ struct mem_cgroup *dest;
+ bool do_continue = false;
+ /*
+ * There is a small race that "dest" can be freed by
+ * rmdir, so we use css_tryget().
+ */
+ rcu_read_lock();
+ dest = recharge.to;
+ if (dest && css_tryget(&dest->css)) {
+ if (dest->use_hierarchy)
+ do_continue = css_is_ancestor(
+ &dest->css,
+ &mem_over_limit->css);
+ else
+ do_continue = (dest == mem_over_limit);
+ css_put(&dest->css);
+ }
+ rcu_read_unlock();
+ if (do_continue)
+ continue;
+ }
+
if (!nr_retries--) {
if (oom) {
mutex_lock(&memcg_tasklist);
@@ -3573,6 +3598,7 @@ static void mem_cgroup_clear_recharge(void)
recharge.from = NULL;
recharge.to = NULL;
recharge.target = NULL;
+ recharge.working = NULL;
}

static int mem_cgroup_can_recharge(struct mem_cgroup *mem,
@@ -3587,6 +3613,7 @@ static int mem_cgroup_can_recharge(struct mem_cgroup *mem,
recharge.from = from;
recharge.to = mem;
recharge.target = p;
+ recharge.working = current;
recharge.precharge = 0;

ret = mem_cgroup_recharge_prepare();
--
1.5.6.1