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 -- 1.8.3.1 _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
