Commit 615d66c3 authored by Vladimir Davydov's avatar Vladimir Davydov Committed by Linus Torvalds

mm: memcontrol: fix memcg id ref counter on swap charge move

Since commit 73f576c0 ("mm: memcontrol: fix cgroup creation failure
after many small jobs") swap entries do not pin memcg->css.refcnt
directly.  Instead, they pin memcg->id.ref.  So we should adjust the
reference counters accordingly when moving swap charges between cgroups.

Fixes: 73f576c0 ("mm: memcontrol: fix cgroup creation failure after many small jobs")
Link: http://lkml.kernel.org/r/9ce297c64954a42dc90b543bc76106c4a94f07e8.1470219853.git.vdavydov@virtuozzo.comSigned-off-by: default avatarVladimir Davydov <vdavydov@virtuozzo.com>
Acked-by: default avatarMichal Hocko <mhocko@suse.com>
Acked-by: default avatarJohannes Weiner <hannes@cmpxchg.org>
Cc: <stable@vger.kernel.org>	[3.19+]
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 1f47b61f
...@@ -4077,9 +4077,9 @@ static struct cftype mem_cgroup_legacy_files[] = { ...@@ -4077,9 +4077,9 @@ static struct cftype mem_cgroup_legacy_files[] = {
static DEFINE_IDR(mem_cgroup_idr); static DEFINE_IDR(mem_cgroup_idr);
static void mem_cgroup_id_get(struct mem_cgroup *memcg) static void mem_cgroup_id_get_many(struct mem_cgroup *memcg, unsigned int n)
{ {
atomic_inc(&memcg->id.ref); atomic_add(n, &memcg->id.ref);
} }
static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg) static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg)
...@@ -4100,9 +4100,9 @@ static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg) ...@@ -4100,9 +4100,9 @@ static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg)
return memcg; return memcg;
} }
static void mem_cgroup_id_put(struct mem_cgroup *memcg) static void mem_cgroup_id_put_many(struct mem_cgroup *memcg, unsigned int n)
{ {
if (atomic_dec_and_test(&memcg->id.ref)) { if (atomic_sub_and_test(n, &memcg->id.ref)) {
idr_remove(&mem_cgroup_idr, memcg->id.id); idr_remove(&mem_cgroup_idr, memcg->id.id);
memcg->id.id = 0; memcg->id.id = 0;
...@@ -4111,6 +4111,16 @@ static void mem_cgroup_id_put(struct mem_cgroup *memcg) ...@@ -4111,6 +4111,16 @@ static void mem_cgroup_id_put(struct mem_cgroup *memcg)
} }
} }
static inline void mem_cgroup_id_get(struct mem_cgroup *memcg)
{
mem_cgroup_id_get_many(memcg, 1);
}
static inline void mem_cgroup_id_put(struct mem_cgroup *memcg)
{
mem_cgroup_id_put_many(memcg, 1);
}
/** /**
* mem_cgroup_from_id - look up a memcg from a memcg id * mem_cgroup_from_id - look up a memcg from a memcg id
* @id: the memcg id to look up * @id: the memcg id to look up
...@@ -4745,6 +4755,8 @@ static void __mem_cgroup_clear_mc(void) ...@@ -4745,6 +4755,8 @@ static void __mem_cgroup_clear_mc(void)
if (!mem_cgroup_is_root(mc.from)) if (!mem_cgroup_is_root(mc.from))
page_counter_uncharge(&mc.from->memsw, mc.moved_swap); page_counter_uncharge(&mc.from->memsw, mc.moved_swap);
mem_cgroup_id_put_many(mc.from, mc.moved_swap);
/* /*
* we charged both to->memory and to->memsw, so we * we charged both to->memory and to->memsw, so we
* should uncharge to->memory. * should uncharge to->memory.
...@@ -4752,9 +4764,9 @@ static void __mem_cgroup_clear_mc(void) ...@@ -4752,9 +4764,9 @@ static void __mem_cgroup_clear_mc(void)
if (!mem_cgroup_is_root(mc.to)) if (!mem_cgroup_is_root(mc.to))
page_counter_uncharge(&mc.to->memory, mc.moved_swap); page_counter_uncharge(&mc.to->memory, mc.moved_swap);
css_put_many(&mc.from->css, mc.moved_swap); mem_cgroup_id_get_many(mc.to, mc.moved_swap);
css_put_many(&mc.to->css, mc.moved_swap);
/* we've already done css_get(mc.to) */
mc.moved_swap = 0; mc.moved_swap = 0;
} }
memcg_oom_recover(from); memcg_oom_recover(from);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment