From: Vladimir Davydov <vdavy...@virtuozzo.com>

An offline memory cgroup might have anonymous memory or shmem left
charged to it and no swap.  Since only swap entries pin the id of an
offline cgroup, such a cgroup will have no id and so an attempt to
swapout its anon/shmem will not store memory cgroup info in the swap
cgroup map.  As a result, memcg->swap or memcg->memsw will never get
uncharged from it and any of its ascendants.

Fix this by always charging swapout to the first ancestor cgroup that
hasn't released its id yet.

[han...@cmpxchg.org: add comment to mem_cgroup_swapout]
[vdavy...@virtuozzo.com: use WARN_ON_ONCE() in mem_cgroup_id_get_online()]
  Link: http://lkml.kernel.org/r/20160803123445.GJ13263@esperanza
Fixes: 73f576c04b941 ("mm: memcontrol: fix cgroup creation failure after many 
small jobs")
Link: 
http://lkml.kernel.org/r/5336daa5c9a32e776067773d9da655d2dc126491.1470219853.git.vdavy...@virtuozzo.com
Signed-off-by: Vladimir Davydov <vdavy...@virtuozzo.com>
Acked-by: Johannes Weiner <han...@cmpxchg.org>
Acked-by: Michal Hocko <mho...@suse.com>
Cc: <sta...@vger.kernel.org>    [3.19+]
Signed-off-by: Andrew Morton <a...@linux-foundation.org>
Signed-off-by: Linus Torvalds <torva...@linux-foundation.org>

https://jira.vzint.dev/browse/PSBM-147036

(cherry picked from commit 1f47b61fb4077936465dcde872a4e5cc4fe708da)
Signed-off-by: Pavel Tikhomirov <ptikhomi...@virtuozzo.com>
---
 mm/memcontrol.c | 39 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 34 insertions(+), 5 deletions(-)

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 6356b6532163..a9a1fb354d33 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -6679,6 +6679,24 @@ static void mem_cgroup_id_get(struct mem_cgroup *memcg)
        atomic_inc(&memcg->id.ref);
 }
 
+static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg)
+{
+       while (!atomic_inc_not_zero(&memcg->id.ref)) {
+               /*
+                * The root cgroup cannot be destroyed, so it's refcount must
+                * always be >= 1.
+                */
+               if (WARN_ON_ONCE(memcg == root_mem_cgroup)) {
+                       VM_BUG_ON(1);
+                       break;
+               }
+               memcg = parent_mem_cgroup(memcg);
+               if (!memcg)
+                       memcg = root_mem_cgroup;
+       }
+       return memcg;
+}
+
 static void mem_cgroup_id_put(struct mem_cgroup *memcg)
 {
        if (atomic_dec_and_test(&memcg->id.ref)) {
@@ -7759,7 +7777,7 @@ static void __init enable_swap_cgroup(void)
  */
 void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
 {
-       struct mem_cgroup *memcg;
+       struct mem_cgroup *memcg, *swap_memcg;
        struct page_cgroup *pc;
        unsigned short oldid;
 
@@ -7778,17 +7796,28 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t 
entry)
        VM_BUG_ON_PAGE(!(pc->flags & PCG_MEMSW), page);
        memcg = pc->mem_cgroup;
 
-       mem_cgroup_id_get(memcg);
-       oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg));
+       /*
+        * In case the memcg owning these pages has been offlined and doesn't
+        * have an ID allocated to it anymore, charge the closest online
+        * ancestor for the swap instead and transfer the memory+swap charge.
+        */
+       swap_memcg = mem_cgroup_id_get_online(memcg);
+       oldid = swap_cgroup_record(entry, mem_cgroup_id(swap_memcg));
        VM_BUG_ON_PAGE(oldid, page);
-       mem_cgroup_swap_statistics(memcg, true);
-       this_cpu_inc(memcg->stat->events[MEM_CGROUP_EVENTS_PSWPOUT]);
+       mem_cgroup_swap_statistics(swap_memcg, true);
+       this_cpu_inc(swap_memcg->stat->events[MEM_CGROUP_EVENTS_PSWPOUT]);
 
        pc->flags = 0;
 
        if (!mem_cgroup_is_root(memcg))
                page_counter_uncharge(&memcg->memory, 1);
 
+       if (memcg != swap_memcg) {
+               if (!mem_cgroup_is_root(swap_memcg))
+                       page_counter_charge(&swap_memcg->memsw, 1);
+               page_counter_uncharge(&memcg->memsw, 1);
+       }
+
        /* XXX: caller holds IRQ-safe mapping->tree_lock */
        VM_BUG_ON(!irqs_disabled());
 
-- 
2.40.1

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to