memcg: fix double free and make refcnt sane
authorKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Thu, 8 Jan 2009 02:08:32 +0000 (18:08 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 8 Jan 2009 16:31:10 +0000 (08:31 -0800)
1. Fix double-free BUG in error route of mem_cgroup_create().
    mem_cgroup_free() itself frees per-zone-info.
 2. Making refcnt of memcg simple.
    Add 1 refcnt at creation and call free when refcnt goes down to 0.

Reviewed-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Balbir Singh <balbir@in.ibm.com>
Cc: Paul Menage <menage@google.com>
Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
Cc: Li Zefan <lizf@cn.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
mm/memcontrol.c

index 0ed61e27d526ebc249754d4952da76db66e637d5..4f9a9c5a02e2751766dd87f928b5d449b5c41057 100644 (file)
@@ -2092,14 +2092,10 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
  * Removal of cgroup itself succeeds regardless of refs from swap.
  */
 
-static void mem_cgroup_free(struct mem_cgroup *mem)
+static void __mem_cgroup_free(struct mem_cgroup *mem)
 {
        int node;
 
-       if (atomic_read(&mem->refcnt) > 0)
-               return;
-
-
        for_each_node_state(node, N_POSSIBLE)
                free_mem_cgroup_per_zone_info(mem, node);
 
@@ -2116,11 +2112,8 @@ static void mem_cgroup_get(struct mem_cgroup *mem)
 
 static void mem_cgroup_put(struct mem_cgroup *mem)
 {
-       if (atomic_dec_and_test(&mem->refcnt)) {
-               if (!mem->obsolete)
-                       return;
-               mem_cgroup_free(mem);
-       }
+       if (atomic_dec_and_test(&mem->refcnt))
+               __mem_cgroup_free(mem);
 }
 
 
@@ -2170,12 +2163,10 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
 
        if (parent)
                mem->swappiness = get_swappiness(parent);
-
+       atomic_set(&mem->refcnt, 1);
        return &mem->css;
 free_out:
-       for_each_node_state(node, N_POSSIBLE)
-               free_mem_cgroup_per_zone_info(mem, node);
-       mem_cgroup_free(mem);
+       __mem_cgroup_free(mem);
        return ERR_PTR(-ENOMEM);
 }
 
@@ -2190,7 +2181,7 @@ static void mem_cgroup_pre_destroy(struct cgroup_subsys *ss,
 static void mem_cgroup_destroy(struct cgroup_subsys *ss,
                                struct cgroup *cont)
 {
-       mem_cgroup_free(mem_cgroup_from_cont(cont));
+       mem_cgroup_put(mem_cgroup_from_cont(cont));
 }
 
 static int mem_cgroup_populate(struct cgroup_subsys *ss,