| From 615d66c37c755c49ce022c9e5ac0875d27d2603d Mon Sep 17 00:00:00 2001 |
| From: Vladimir Davydov <vdavydov@virtuozzo.com> |
| Date: Thu, 11 Aug 2016 15:33:03 -0700 |
| Subject: mm: memcontrol: fix memcg id ref counter on swap charge move |
| |
| From: Vladimir Davydov <vdavydov@virtuozzo.com> |
| |
| commit 615d66c37c755c49ce022c9e5ac0875d27d2603d upstream. |
| |
| Since commit 73f576c04b94 ("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: 73f576c04b941 ("mm: memcontrol: fix cgroup creation failure after many small jobs") |
| Link: http://lkml.kernel.org/r/9ce297c64954a42dc90b543bc76106c4a94f07e8.1470219853.git.vdavydov@virtuozzo.com |
| Signed-off-by: Vladimir Davydov <vdavydov@virtuozzo.com> |
| Acked-by: Michal Hocko <mhocko@suse.com> |
| Acked-by: Johannes Weiner <hannes@cmpxchg.org> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Michal Hocko <mhocko@suse.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| mm/memcontrol.c | 24 ++++++++++++++++++------ |
| 1 file changed, 18 insertions(+), 6 deletions(-) |
| |
| --- a/mm/memcontrol.c |
| +++ b/mm/memcontrol.c |
| @@ -4136,9 +4136,9 @@ static struct cftype mem_cgroup_legacy_f |
| |
| 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) |
| @@ -4159,9 +4159,9 @@ static struct mem_cgroup *mem_cgroup_id_ |
| 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); |
| memcg->id.id = 0; |
| |
| @@ -4170,6 +4170,16 @@ static void mem_cgroup_id_put(struct mem |
| } |
| } |
| |
| +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 |
| * @id: the memcg id to look up |
| @@ -4854,6 +4864,8 @@ static void __mem_cgroup_clear_mc(void) |
| if (!mem_cgroup_is_root(mc.from)) |
| 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 |
| * should uncharge to->memory. |
| @@ -4861,9 +4873,9 @@ static void __mem_cgroup_clear_mc(void) |
| if (!mem_cgroup_is_root(mc.to)) |
| 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; |
| } |
| memcg_oom_recover(from); |