The commit is pushed to "branch-rh7-3.10.0-1160.11.1.vz7.172.x-ovz" and will 
appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1160.11.1.vz7.172.14
------>
commit d70d9e2ba4f7b8515a7fcd7cf2ad39e09a7c334c
Author: Vasily Averin <[email protected]>
Date:   Mon Feb 22 21:50:17 2021 +0300

    memcg leak due to missing css_put on last kmem uncharge
    
    When mem_cgroup is removes mem_cgroup_css_offline() calls
    memcg_deactivate_kmem() which disables kmem accounting.
    If memcg still have some charged kmem final css_put is not called,
    and delayed till last kmem will be uncharged.
    
    Usually kmem is uncharged by using memcg_uncharge_kmem() which have
    according checks and if required calls final css_put().
    
    Though patch added to vz7.162.14 kernel
    "mm/memcg: Use per-cpu stock charges for ->kmem and ->cache counters"
    enabled kmem charge/uncharge in refill_stock()/drain_stock()
    without using of memcg_uncharge_kmem(), as result nobody called
    final css_put() after last kmem uncharge.
    
    This patch adds css_get/put for safe access to memcg in drain_stock(),
    and calls an additional css_put() after last kmem uncharge.
    
    Fixes: "mm/memcg: Use per-cpu stock charges for ->kmem and ->cache counters"
    https://bugs.openvz.org/browse/OVZ-7250
    Signed-off-by: Vasily Averin <[email protected]>
---
 mm/memcontrol.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index e0a4309..24e3bd7 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -439,6 +439,8 @@ enum {
        KMEM_ACCOUNTED_DEAD, /* dead memcg with pending kmem charges */
 };
 
+static void memcg_kmem_release_css(struct mem_cgroup *memcg);
+
 static struct mem_cgroup_per_node *
 mem_cgroup_nodeinfo(struct mem_cgroup *memcg, int nid)
 {
@@ -2928,11 +2930,15 @@ static void drain_stock(struct memcg_stock_pcp *stock)
 {
        struct mem_cgroup *old = stock->cached;
        unsigned long nr_pages = stock->nr_pages + stock->cache_nr_pages + 
stock->kmem_nr_pages;
+       u64 kmem = 1;
+
+       if (!old)
+               return;
 
        if (stock->cache_nr_pages)
                page_counter_uncharge(&old->cache, stock->cache_nr_pages);
        if (stock->kmem_nr_pages)
-               page_counter_uncharge(&old->kmem, stock->kmem_nr_pages);
+               kmem = page_counter_uncharge(&old->kmem, stock->kmem_nr_pages);
 
        if (nr_pages) {
                page_counter_uncharge(&old->memory, nr_pages);
@@ -2942,6 +2948,9 @@ static void drain_stock(struct memcg_stock_pcp *stock)
                stock->kmem_nr_pages = 0;
                stock->cache_nr_pages = 0;
        }
+       css_put(&old->css);
+       if (kmem == 0)
+               memcg_kmem_release_css(old);
        stock->cached = NULL;
 }
 
@@ -2978,6 +2987,7 @@ static void refill_stock(struct mem_cgroup *memcg, 
unsigned int nr_pages,
 
        if (stock->cached != memcg) { /* reset if necessary */
                drain_stock(stock);
+               css_get(&memcg->css);
                stock->cached = memcg;
        }
 
@@ -3608,10 +3618,12 @@ void memcg_uncharge_kmem(struct mem_cgroup *memcg,
        if (do_swap_account)
                page_counter_uncharge(&memcg->memsw, nr_pages);
 
-       /* Not down to 0 */
-       if (kmem)
-               return;
+       if (kmem == 0)
+               memcg_kmem_release_css(memcg);
+}
 
+static void memcg_kmem_release_css(struct mem_cgroup *memcg)
+{
        /*
         * Releases a reference taken in memcg_deactivate_kmem in case
         * this last uncharge is racing with the offlining code or it is
_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to