Commit 7bcc1bb1232de6efc0b85e0c7fe38e90b2436318
Committed by
Linus Torvalds
1 parent
baef99a08a
Exists in
master
and in
4 other branches
memcg: get/put parents at create/free
The lifetime of struct cgroup and struct mem_cgroup is different and mem_cgroup has its own reference count for handling references from swap_cgroup. This causes strange problem that the parent mem_cgroup dies while child mem_cgroup alive, and this problem causes a bug in case of use_hierarchy==1 because res_counter_uncharge climbs up the tree. This patch is for avoiding it by getting the parent at create, and putting it at freeing. Signed-off-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Reviewed-by; KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Balbir Singh <balbir@linux.vnet.ibm.com> Cc: Pavel Emelyanov <xemul@openvz.org> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Paul Menage <menage@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 22 additions and 1 deletions Side-by-side Diff
mm/memcontrol.c
... | ... | @@ -202,6 +202,7 @@ |
202 | 202 | |
203 | 203 | static void mem_cgroup_get(struct mem_cgroup *mem); |
204 | 204 | static void mem_cgroup_put(struct mem_cgroup *mem); |
205 | +static struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *mem); | |
205 | 206 | |
206 | 207 | static void mem_cgroup_charge_statistics(struct mem_cgroup *mem, |
207 | 208 | struct page_cgroup *pc, |
208 | 209 | |
209 | 210 | |
... | ... | @@ -2193,10 +2194,23 @@ |
2193 | 2194 | |
2194 | 2195 | static void mem_cgroup_put(struct mem_cgroup *mem) |
2195 | 2196 | { |
2196 | - if (atomic_dec_and_test(&mem->refcnt)) | |
2197 | + if (atomic_dec_and_test(&mem->refcnt)) { | |
2198 | + struct mem_cgroup *parent = parent_mem_cgroup(mem); | |
2197 | 2199 | __mem_cgroup_free(mem); |
2200 | + if (parent) | |
2201 | + mem_cgroup_put(parent); | |
2202 | + } | |
2198 | 2203 | } |
2199 | 2204 | |
2205 | +/* | |
2206 | + * Returns the parent mem_cgroup in memcgroup hierarchy with hierarchy enabled. | |
2207 | + */ | |
2208 | +static struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *mem) | |
2209 | +{ | |
2210 | + if (!mem->res.parent) | |
2211 | + return NULL; | |
2212 | + return mem_cgroup_from_res_counter(mem->res.parent, res); | |
2213 | +} | |
2200 | 2214 | |
2201 | 2215 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP |
2202 | 2216 | static void __init enable_swap_cgroup(void) |
... | ... | @@ -2235,6 +2249,13 @@ |
2235 | 2249 | if (parent && parent->use_hierarchy) { |
2236 | 2250 | res_counter_init(&mem->res, &parent->res); |
2237 | 2251 | res_counter_init(&mem->memsw, &parent->memsw); |
2252 | + /* | |
2253 | + * We increment refcnt of the parent to ensure that we can | |
2254 | + * safely access it on res_counter_charge/uncharge. | |
2255 | + * This refcnt will be decremented when freeing this | |
2256 | + * mem_cgroup(see mem_cgroup_put). | |
2257 | + */ | |
2258 | + mem_cgroup_get(parent); | |
2238 | 2259 | } else { |
2239 | 2260 | res_counter_init(&mem->res, NULL); |
2240 | 2261 | res_counter_init(&mem->memsw, NULL); |