memcg: fix double free and make refcnt sane

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>
This commit is contained in:
KAMEZAWA Hiroyuki 2009-01-07 18:08:32 -08:00 committed by Linus Torvalds
parent 03f3c43364
commit a7ba0eef3a

View File

@ -2092,14 +2092,10 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
* Removal of cgroup itself succeeds regardless of refs from swap. * 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; int node;
if (atomic_read(&mem->refcnt) > 0)
return;
for_each_node_state(node, N_POSSIBLE) for_each_node_state(node, N_POSSIBLE)
free_mem_cgroup_per_zone_info(mem, node); 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) static void mem_cgroup_put(struct mem_cgroup *mem)
{ {
if (atomic_dec_and_test(&mem->refcnt)) { if (atomic_dec_and_test(&mem->refcnt))
if (!mem->obsolete) __mem_cgroup_free(mem);
return;
mem_cgroup_free(mem);
}
} }
@ -2170,12 +2163,10 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
if (parent) if (parent)
mem->swappiness = get_swappiness(parent); mem->swappiness = get_swappiness(parent);
atomic_set(&mem->refcnt, 1);
return &mem->css; return &mem->css;
free_out: free_out:
for_each_node_state(node, N_POSSIBLE) __mem_cgroup_free(mem);
free_mem_cgroup_per_zone_info(mem, node);
mem_cgroup_free(mem);
return ERR_PTR(-ENOMEM); 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, static void mem_cgroup_destroy(struct cgroup_subsys *ss,
struct cgroup *cont) 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, static int mem_cgroup_populate(struct cgroup_subsys *ss,