[Devel] [PATCH RHEL7 COMMIT] mm/memcg: fix overcharging in cgroup try_charge() for !cache_charge

Konstantin Khorenko khorenko at virtuozzo.com
Tue Feb 27 13:28:49 MSK 2018


The commit is pushed to "branch-rh7-3.10.0-693.17.1.vz7.43.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-693.17.1.vz7.43.9
------>
commit e285be97ce1f2c75aaf2ec98eaee53fbcbaa560c
Author: Andrey Ryabinin <aryabinin at virtuozzo.com>
Date:   Tue Feb 27 13:28:49 2018 +0300

    mm/memcg: fix overcharging in cgroup try_charge() for !cache_charge
    
    Normally, try_charge() tries to charge 32 pages, and if succesfull,
    puts the rest (32-nr_pages) into stock. So the next try_charge() looks
    into the stock only and avoid calling expensive page_counter_try_charge(),
    (at least untill stock has some pages).
    
    This stopped to work after commit:
    
         15fd42f8580f ("mm/memcg: limit page cache in memcg hack")
    
    If cache_charge=false in try_charge() we always call refill_stock() which
    undoes stock charge and fallback to slowpath which charges 32 pages and puts
    rest into the stock. So we have constantly growing stock and page_counter.
    Eventually we hit the limit and call drain_all_stock_async() which uncharges
    all accumulated stock pages from page_counter and page_counter goes
    back to sane value. But before that happens mem_cgroup_enough_memory() may
    read over-charges ->memsw counter and return ENOMEM to user-space.
    
    https://jira.sw.ru/browse/PSBM-81750
    Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>
---
 mm/memcontrol.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 50cbcdc38f60..b4d61d72ccbf 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2769,13 +2769,12 @@ static int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask, bool kmem_charge
 			goto charge;
 		}
 
-		if (cache_charge && !page_counter_try_charge(
-				&memcg->cache, nr_pages, &counter))
-			goto done;
-
-		refill_stock(memcg, nr_pages);
-		if (kmem_charge)
-			page_counter_uncharge(&memcg->kmem, nr_pages);
+		if (cache_charge && page_counter_try_charge(
+				&memcg->cache, nr_pages, &counter)) {
+			refill_stock(memcg, nr_pages);
+			goto charge;
+		}
+		goto done;
 	}
 
 charge:


More information about the Devel mailing list