]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - mm/memcontrol.c
memcg: add interface to move charge at task migration
[net-next-2.6.git] / mm / memcontrol.c
index d813823ab08f06916a3d905ecfabffe3d0ca217f..59ffaf511d77fce9c7f8f6fe7cc2e02cf456bc85 100644 (file)
@@ -225,12 +225,27 @@ struct mem_cgroup {
        /* set when res.limit == memsw.limit */
        bool            memsw_is_minimum;
 
+       /*
+        * Should we move charges of a task when a task is moved into this
+        * mem_cgroup ? And what type of charges should we move ?
+        */
+       unsigned long   move_charge_at_immigrate;
+
        /*
         * statistics. This must be placed at the end of memcg.
         */
        struct mem_cgroup_stat stat;
 };
 
+/* Stuffs for move charges at task migration. */
+/*
+ * Types of charges to be moved. "move_charge_at_immitgrate" is treated as a
+ * left-shifted bitmap of these types.
+ */
+enum move_type {
+       NR_MOVE_TYPE,
+};
+
 /*
  * Maximum loops in mem_cgroup_hierarchical_reclaim(), used for soft
  * limit reclaim to prevent infinite loops, if they ever occur.
@@ -2865,6 +2880,31 @@ static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
        return 0;
 }
 
+static u64 mem_cgroup_move_charge_read(struct cgroup *cgrp,
+                                       struct cftype *cft)
+{
+       return mem_cgroup_from_cont(cgrp)->move_charge_at_immigrate;
+}
+
+static int mem_cgroup_move_charge_write(struct cgroup *cgrp,
+                                       struct cftype *cft, u64 val)
+{
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cgrp);
+
+       if (val >= (1 << NR_MOVE_TYPE))
+               return -EINVAL;
+       /*
+        * We check this value several times in both in can_attach() and
+        * attach(), so we need cgroup lock to prevent this value from being
+        * inconsistent.
+        */
+       cgroup_lock();
+       mem->move_charge_at_immigrate = val;
+       cgroup_unlock();
+
+       return 0;
+}
+
 
 /* For read statistics */
 enum {
@@ -3098,6 +3138,11 @@ static struct cftype mem_cgroup_files[] = {
                .read_u64 = mem_cgroup_swappiness_read,
                .write_u64 = mem_cgroup_swappiness_write,
        },
+       {
+               .name = "move_charge_at_immigrate",
+               .read_u64 = mem_cgroup_move_charge_read,
+               .write_u64 = mem_cgroup_move_charge_write,
+       },
 };
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
@@ -3345,6 +3390,7 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
        if (parent)
                mem->swappiness = get_swappiness(parent);
        atomic_set(&mem->refcnt, 1);
+       mem->move_charge_at_immigrate = 0;
        return &mem->css;
 free_out:
        __mem_cgroup_free(mem);
@@ -3381,16 +3427,57 @@ static int mem_cgroup_populate(struct cgroup_subsys *ss,
        return ret;
 }
 
+/* Handlers for move charge at task migration. */
+static int mem_cgroup_can_move_charge(void)
+{
+       return 0;
+}
+
+static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
+                               struct cgroup *cgroup,
+                               struct task_struct *p,
+                               bool threadgroup)
+{
+       int ret = 0;
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cgroup);
+
+       if (mem->move_charge_at_immigrate) {
+               struct mm_struct *mm;
+               struct mem_cgroup *from = mem_cgroup_from_task(p);
+
+               VM_BUG_ON(from == mem);
+
+               mm = get_task_mm(p);
+               if (!mm)
+                       return 0;
+
+               /* We move charges only when we move a owner of the mm */
+               if (mm->owner == p)
+                       ret = mem_cgroup_can_move_charge();
+
+               mmput(mm);
+       }
+       return ret;
+}
+
+static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss,
+                               struct cgroup *cgroup,
+                               struct task_struct *p,
+                               bool threadgroup)
+{
+}
+
+static void mem_cgroup_move_charge(void)
+{
+}
+
 static void mem_cgroup_move_task(struct cgroup_subsys *ss,
                                struct cgroup *cont,
                                struct cgroup *old_cont,
                                struct task_struct *p,
                                bool threadgroup)
 {
-       /*
-        * FIXME: It's better to move charges of this process from old
-        * memcg to new memcg. But it's just on TODO-List now.
-        */
+       mem_cgroup_move_charge();
 }
 
 struct cgroup_subsys mem_cgroup_subsys = {
@@ -3400,6 +3487,8 @@ struct cgroup_subsys mem_cgroup_subsys = {
        .pre_destroy = mem_cgroup_pre_destroy,
        .destroy = mem_cgroup_destroy,
        .populate = mem_cgroup_populate,
+       .can_attach = mem_cgroup_can_attach,
+       .cancel_attach = mem_cgroup_cancel_attach,
        .attach = mem_cgroup_move_task,
        .early_init = 0,
        .use_id = 1,