[Devel] [PATCH rh7] mm/memcg: sleep if mem_cgroup_force_empty_list() stumped on busy page

Andrey Ryabinin aryabinin at virtuozzo.com
Tue Sep 5 18:53:06 MSK 2017


mem_cgroup_force_empty_list() executed in workqueue context. If work doesn't
go to sleep the workqueue engine thinks that this work is making progress,
so there is no need to start more workers to execute other works.

So, if we need other works to be executed to unlock those pages we might
have a deadlock. I think this easy might happen with fuse, something
like this:

fuse:                              cgroup_destroy work:
			              mem_cgroup_force_empty_list()
                                          //busy wait for fuse to unlock pages.
 queue_work()

 //this may have to wait
 //for mem_cgroup_force_empty_list
 //to finish
 flush_work()

 read pages and unlock them.

The solution to this problem is to put mem_cgroup_force_empty_list() in short
sleep() instead of cond_resched(). This will allow other works to make progress
if mem_cgroup_force_empty_list() is stuck.

https://jira.sw.ru/browse/PSBM-70021
Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>
---
 mm/memcontrol.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 940cca31ed5d..b09d5be27444 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -4034,7 +4034,7 @@ static void mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
 		if (mem_cgroup_move_parent(page, pc, memcg)) {
 			/* found lock contention or "pc" is obsolete. */
 			busy = page;
-			cond_resched();
+			schedule_timeout_uninterruptible(1);
 		} else
 			busy = NULL;
 	} while (!list_empty(list));
-- 
2.13.5



More information about the Devel mailing list