diff options
author | KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> | 2009-01-07 21:08:32 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-08 11:31:10 -0500 |
commit | a7ba0eef3af51cd1b6fc4028e4705b3ea2ea9469 (patch) | |
tree | 70e43097041eed321be38d1af4ed65e41d1ebff9 /mm/memcontrol.c | |
parent | 03f3c433648a97ae7c86be789edba67690f6ea60 (diff) |
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>
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 21 |
1 files changed, 6 insertions, 15 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 0ed61e27d526..4f9a9c5a02e2 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -2092,14 +2092,10 @@ static struct mem_cgroup *mem_cgroup_alloc(void) | |||
2092 | * Removal of cgroup itself succeeds regardless of refs from swap. | 2092 | * Removal of cgroup itself succeeds regardless of refs from swap. |
2093 | */ | 2093 | */ |
2094 | 2094 | ||
2095 | static void mem_cgroup_free(struct mem_cgroup *mem) | 2095 | static void __mem_cgroup_free(struct mem_cgroup *mem) |
2096 | { | 2096 | { |
2097 | int node; | 2097 | int node; |
2098 | 2098 | ||
2099 | if (atomic_read(&mem->refcnt) > 0) | ||
2100 | return; | ||
2101 | |||
2102 | |||
2103 | for_each_node_state(node, N_POSSIBLE) | 2099 | for_each_node_state(node, N_POSSIBLE) |
2104 | free_mem_cgroup_per_zone_info(mem, node); | 2100 | free_mem_cgroup_per_zone_info(mem, node); |
2105 | 2101 | ||
@@ -2116,11 +2112,8 @@ static void mem_cgroup_get(struct mem_cgroup *mem) | |||
2116 | 2112 | ||
2117 | static void mem_cgroup_put(struct mem_cgroup *mem) | 2113 | static void mem_cgroup_put(struct mem_cgroup *mem) |
2118 | { | 2114 | { |
2119 | if (atomic_dec_and_test(&mem->refcnt)) { | 2115 | if (atomic_dec_and_test(&mem->refcnt)) |
2120 | if (!mem->obsolete) | 2116 | __mem_cgroup_free(mem); |
2121 | return; | ||
2122 | mem_cgroup_free(mem); | ||
2123 | } | ||
2124 | } | 2117 | } |
2125 | 2118 | ||
2126 | 2119 | ||
@@ -2170,12 +2163,10 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont) | |||
2170 | 2163 | ||
2171 | if (parent) | 2164 | if (parent) |
2172 | mem->swappiness = get_swappiness(parent); | 2165 | mem->swappiness = get_swappiness(parent); |
2173 | 2166 | atomic_set(&mem->refcnt, 1); | |
2174 | return &mem->css; | 2167 | return &mem->css; |
2175 | free_out: | 2168 | free_out: |
2176 | for_each_node_state(node, N_POSSIBLE) | 2169 | __mem_cgroup_free(mem); |
2177 | free_mem_cgroup_per_zone_info(mem, node); | ||
2178 | mem_cgroup_free(mem); | ||
2179 | return ERR_PTR(-ENOMEM); | 2170 | return ERR_PTR(-ENOMEM); |
2180 | } | 2171 | } |
2181 | 2172 | ||
@@ -2190,7 +2181,7 @@ static void mem_cgroup_pre_destroy(struct cgroup_subsys *ss, | |||
2190 | static void mem_cgroup_destroy(struct cgroup_subsys *ss, | 2181 | static void mem_cgroup_destroy(struct cgroup_subsys *ss, |
2191 | struct cgroup *cont) | 2182 | struct cgroup *cont) |
2192 | { | 2183 | { |
2193 | mem_cgroup_free(mem_cgroup_from_cont(cont)); | 2184 | mem_cgroup_put(mem_cgroup_from_cont(cont)); |
2194 | } | 2185 | } |
2195 | 2186 | ||
2196 | static int mem_cgroup_populate(struct cgroup_subsys *ss, | 2187 | static int mem_cgroup_populate(struct cgroup_subsys *ss, |