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:
parent
03f3c43364
commit
a7ba0eef3a
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user