[Devel] [PATCH rh7] mm: memcontrol: carefully check for user charges while reparenting

Vladimir Davydov vdavydov at virtuozzo.com
Thu Jul 7 06:49:18 PDT 2016


kmem is uncharged before res, therefore when checking if there are still
user charges in a memory cgroup, we should read res before kmem,
otherwise a kmem uncharge can get in-between two reads, leading to
false-positive res <= kmem. Add smp_rmb() to guarantee this never
happens.

Note, since x86 doesn't reorder reads, this patch doesn't actually
introduce any functional changes - it just clarifies the code.

Fixes: 35c0d2a992aa ("mm: memcontrol: fix race between kmem uncharge and charge reparenting")
Signed-off-by: Vladimir Davydov <vdavydov at virtuozzo.com>
---
 mm/memcontrol.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 1f525f27e481..8151d4259c6b 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -4814,7 +4814,7 @@ static void mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
 static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg)
 {
 	int node, zid;
-	u64 usage;
+	u64 res, kmem;
 
 	do {
 		/* This is for making all *used* pages to be on LRU. */
@@ -4845,10 +4845,17 @@ static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg)
 		 * so the lru seemed empty but the page could have been added
 		 * right after the check. RES_USAGE should be safe as we always
 		 * charge before adding to the LRU.
+		 *
+		 * Note, we must read memcg->res strictly before memcg->kmem,
+		 * because otherwise a kmem charge might get uncharged in
+		 * between the two reads leading to res <= kmem, even though
+		 * there are still user pages charged to this cgroup out there.
+		 * (see also comment in memcg_charge_kmem())
 		 */
-		usage = res_counter_read_u64(&memcg->res, RES_USAGE) -
-			res_counter_read_u64(&memcg->kmem, RES_USAGE);
-	} while (usage > 0);
+		res = res_counter_read_u64(&memcg->res, RES_USAGE);
+		smp_rmb();
+		kmem = res_counter_read_u64(&memcg->kmem, RES_USAGE);
+	} while (res > kmem);
 }
 
 /*
-- 
2.1.4



More information about the Devel mailing list