[RHEL7,COMMIT] mm/memcg: fix race with WARN_ON() check and kmem uncharging.

Submitted by Konstantin Khorenko on Aug. 14, 2019, 4:40 p.m.

Details

Message ID 201908141640.x7EGeTcg019942@finist-ce7.sw.ru
State New
Series "Series without cover letter"
Headers show

Commit Message

Konstantin Khorenko Aug. 14, 2019, 4:40 p.m.
The commit is pushed to "branch-rh7-3.10.0-957.27.2.vz7.107.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-957.27.2.vz7.107.3
------>
commit 41401c84f6224a60bb13d5041531b93541a8d563
Author: Andrey Ryabinin <aryabinin@virtuozzo.com>
Date:   Wed Aug 14 19:39:53 2019 +0300

    mm/memcg: fix race with WARN_ON() check and kmem uncharging.
    
    WARN_ON() in mem_cgroup_reparent_charges() may falsely trigger
    due to the following race (initial state "memory = kmem"):
    
    while((page_counter_read(memory)
             - page_counter_read(kmem) > 0) ....
                                                            memcg_unharge_kmem():
                                                              page_counter_uncharge(kmem);
    WARN_ON((page_counter_read(memory)
              - page_counter_read(kmem) > 0)...
                                                              page_counter_uncharge(memory);
    
    Fix this by reading counters only once.
    
    https://jira.sw.ru/browse/PSBM-97012
    Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
---
 mm/memcontrol.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 3385160f6168..435fdcf8c141 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -4347,6 +4347,7 @@  static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg)
 	/* Protection from leaked memcg->memory counter. */
 	unsigned long start_time = jiffies;
 	unsigned long timeout = start_time + HZ*1200;
+	unsigned long mem, kmem;
 
 	do {
 		/* This is for making all *used* pages to be on LRU. */
@@ -4378,16 +4379,16 @@  static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg)
 		 * right after the check. RES_USAGE should be safe as we always
 		 * charge before adding to the LRU.
 		 */
-	} while ((page_counter_read(&memcg->memory) -
-		 page_counter_read(&memcg->kmem) > 0) && time_before(jiffies, timeout));
+		mem = page_counter_read(&memcg->memory);
+		kmem = page_counter_read(&memcg->kmem);
+	} while ((mem - kmem > 0) && time_before(jiffies, timeout));
 
-	WARN_ONCE((page_counter_read(&memcg->memory) -
-			page_counter_read(&memcg->kmem) > 0),
+	WARN_ONCE((mem - kmem > 0),
 		  "memcg 0x%p leak suspected: "
 		  "memory=%lu, kmem=%lu start_time=%lx timeout=%lx jiffies=%lx",
 		  memcg,
-		  page_counter_read(&memcg->memory),
-		  page_counter_read(&memcg->kmem),
+		  mem,
+		  kmem,
 		  start_time, timeout, jiffies);
 }