mem_cgroup_resize_cache_limit() tries to free only 32 (SWAP_CLUSTER_MAX)
pages on each iteration.  This makes it practically impossible to decrease
limit of memory cgroup.  Tasks could easily allocate back 32 pages, so we
can't reduce memory usage, and once retry_count reaches zero we return
-EBUSY.

Easy to reproduce the problem by running the following commands:

  mkdir /sys/fs/cgroup/memory/test
  echo $$ >> /sys/fs/cgroup/memory/test/tasks
  cat big_file > /dev/null &
  sleep 1 && echo $((100*1024*1024)) > 
/sys/fs/cgroup/memory/test/memory.cache.limit_in_bytes
  -bash: echo: write error: Device or resource busy

Instead of relying on retry_count, keep retrying the reclaim until the
desired limit is reached or fail if the reclaim doesn't make any progress
or a signal is pending.

https://jira.sw.ru/browse/PSBM-80732
Signed-off-by: Andrey Ryabinin <aryabi...@virtuozzo.com>
---
 mm/memcontrol.c | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 22471a7b995a..99cabf41bc9f 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -4456,15 +4456,9 @@ static int memcg_update_cache_limit(struct mem_cgroup 
*memcg,
        int retry_count;
        int ret;
 
-       /*
-        * For keeping hierarchical_reclaim simple, how long we should retry
-        * is depends on callers. We set our retry-count to be function
-        * of # of children which we should visit in this loop.
-        */
-       retry_count = MEM_CGROUP_RECLAIM_RETRIES *
-                     mem_cgroup_count_children(memcg);
+       retry_count = MEM_CGROUP_RECLAIM_RETRIES;
 
-       oldusage = page_counter_read(&memcg->cache);
+       curusage = oldusage = page_counter_read(&memcg->cache);
 
        do {
                if (signal_pending(current)) {
@@ -4482,8 +4476,8 @@ static int memcg_update_cache_limit(struct mem_cgroup 
*memcg,
                if (!ret)
                        break;
 
-               mem_cgroup_reclaim(memcg, GFP_KERNEL,
-                                  MEM_CGROUP_RECLAIM_NOSWAP);
+               try_to_free_mem_cgroup_pages(memcg, curusage - limit, 
GFP_KERNEL,
+                                       MEM_CGROUP_RECLAIM_NOSWAP);
                curusage = page_counter_read(&memcg->cache);
                /* Usage is reduced ? */
                if (curusage >= oldusage)
-- 
2.13.6

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to