[RHEL7,COMMIT] mm/memcg: Bypass charges to offlined cgroup

Submitted by Konstantin Khorenko on July 13, 2018, 12:34 p.m.

Details

Message ID 201807131234.w6DCYmSc018426@finist_ce7.work
State New
Series "mm/memcg: Bypass charges to offlined cgroup."
Headers show

Commit Message

Konstantin Khorenko July 13, 2018, 12:34 p.m.
The commit is pushed to "branch-rh7-3.10.0-862.6.3.vz7.62.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-862.6.3.vz7.62.3
------>
commit 90633e808c57ac222f9efeedf851500ec6133965
Author: Andrey Ryabinin <aryabinin@virtuozzo.com>
Date:   Fri Jul 13 15:34:48 2018 +0300

    mm/memcg: Bypass charges to offlined cgroup
    
    Charges to offlined cgroup can happen. E.g. swapped KSM page may charge to
    offlined cgroup. If such charge races with reparenting during the offlining
    process it may result in hang in mem_cgroup_reparent_charges().
    
    Let's say we have cgroup A and cgroup B. A is parent of B, B is offlined
    already, and A in the process of offlining.  During offline of A, we walk
    through all childs of A and reparent their charges. After that, we reparent the
    A itself.
    
    If charge to B cgroup will appear after the reparenting of B and before
    reparenting A, the reparanting of A will hang.  Charge to B also increases
    ->memory counter of its parent A, so mem_cgroup_reparent_charges(A) will never
    satisfy the condition
    'A->memory - A->kmem > 0'
    which is required to break the loop.
    
    https://jira.sw.ru/browse/PSBM-86092
    Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
---
 mm/memcontrol.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

Patch hide | download patch | download mbox

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 59cf47972f9e..8b979d88045c 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2909,6 +2909,28 @@  static int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask, bool kmem_charge
 	return -EINTR;
 
 done_restock:
+
+	/*
+	 * Cancel charge in case if cgroup was offlined while we were here,
+	 * otherwise we can get a pending user memory charge to an offline
+	 * cgroup, which might race with reparanting in mem_cgroup_css_offline()
+	 * and result in hang.
+	 *
+	 * Note, no need to issue an explicit barrier here, because a
+	 * successful charge implies full memory barrier.
+	 */
+	if (unlikely(memcg->is_offline)) {
+		page_counter_uncharge(&memcg->memory, batch);
+		if (do_swap_account)
+			page_counter_uncharge(&memcg->memsw, batch);
+		if (cache_charge)
+			page_counter_uncharge(&memcg->cache, nr_pages);
+		if (kmem_charge)
+			page_counter_uncharge(&memcg->kmem, nr_pages);
+
+		goto bypass;
+	}
+
 	if (batch > nr_pages)
 		refill_stock(memcg, batch - nr_pages);
 done: