selftests: cgroup: add a selftest for memory.reclaim
authorYosry Ahmed <yosryahmed@google.com>
Fri, 29 Apr 2022 21:37:00 +0000 (14:37 -0700)
committerakpm <akpm@linux-foundation.org>
Fri, 29 Apr 2022 21:37:00 +0000 (14:37 -0700)
Add a new test for memory.reclaim that verifies that the interface
correctly reclaims memory as intended, from both anon and file pages.

Link: https://lkml.kernel.org/r/20220425190040.2475377-5-yosryahmed@google.com
Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
Acked-by: Roman Gushchin <roman.gushchin@linux.dev>
Acked-by: David Rientjes <rientjes@google.com>
Cc: Chen Wandun <chenwandun@huawei.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Michal Hocko <mhocko@suse.com>
Cc: "Michal Koutn" <mkoutny@suse.com>
Cc: Shakeel Butt <shakeelb@google.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Tejun Heo <tj@kernel.org>
Cc: Tim Chen <tim.c.chen@linux.intel.com>
Cc: Vaibhav Jain <vaibhav@linux.ibm.com>
Cc: Wei Xu <weixugc@google.com>
Cc: Yu Zhao <yuzhao@google.com>
Cc: Zefan Li <lizefan.x@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
tools/testing/selftests/cgroup/test_memcontrol.c

index a639bf4..ee7defb 100644 (file)
@@ -760,6 +760,111 @@ cleanup:
        return ret;
 }
 
+/*
+ * This test checks that memory.reclaim reclaims the given
+ * amount of memory (from both anon and file, if possible).
+ */
+static int test_memcg_reclaim(const char *root)
+{
+       int ret = KSFT_FAIL, fd, retries;
+       char *memcg;
+       long current, expected_usage, to_reclaim;
+       char buf[64];
+
+       memcg = cg_name(root, "memcg_test");
+       if (!memcg)
+               goto cleanup;
+
+       if (cg_create(memcg))
+               goto cleanup;
+
+       current = cg_read_long(memcg, "memory.current");
+       if (current != 0)
+               goto cleanup;
+
+       fd = get_temp_fd();
+       if (fd < 0)
+               goto cleanup;
+
+       cg_run_nowait(memcg, alloc_pagecache_50M_noexit, (void *)(long)fd);
+
+       /*
+        * If swap is enabled, try to reclaim from both anon and file, else try
+        * to reclaim from file only.
+        */
+       if (is_swap_enabled()) {
+               cg_run_nowait(memcg, alloc_anon_noexit, (void *) MB(50));
+               expected_usage = MB(100);
+       } else
+               expected_usage = MB(50);
+
+       /*
+        * Wait until current usage reaches the expected usage (or we run out of
+        * retries).
+        */
+       retries = 5;
+       while (!values_close(cg_read_long(memcg, "memory.current"),
+                           expected_usage, 10)) {
+               if (retries--) {
+                       sleep(1);
+                       continue;
+               } else {
+                       fprintf(stderr,
+                               "failed to allocate %ld for memcg reclaim test\n",
+                               expected_usage);
+                       goto cleanup;
+               }
+       }
+
+       /*
+        * Reclaim until current reaches 30M, this makes sure we hit both anon
+        * and file if swap is enabled.
+        */
+       retries = 5;
+       while (true) {
+               int err;
+
+               current = cg_read_long(memcg, "memory.current");
+               to_reclaim = current - MB(30);
+
+               /*
+                * We only keep looping if we get EAGAIN, which means we could
+                * not reclaim the full amount.
+                */
+               if (to_reclaim <= 0)
+                       goto cleanup;
+
+
+               snprintf(buf, sizeof(buf), "%ld", to_reclaim);
+               err = cg_write(memcg, "memory.reclaim", buf);
+               if (!err) {
+                       /*
+                        * If writing succeeds, then the written amount should have been
+                        * fully reclaimed (and maybe more).
+                        */
+                       current = cg_read_long(memcg, "memory.current");
+                       if (!values_close(current, MB(30), 3) && current > MB(30))
+                               goto cleanup;
+                       break;
+               }
+
+               /* The kernel could not reclaim the full amount, try again. */
+               if (err == -EAGAIN && retries--)
+                       continue;
+
+               /* We got an unexpected error or ran out of retries. */
+               goto cleanup;
+       }
+
+       ret = KSFT_PASS;
+cleanup:
+       cg_destroy(memcg);
+       free(memcg);
+       close(fd);
+
+       return ret;
+}
+
 static int alloc_anon_50M_check_swap(const char *cgroup, void *arg)
 {
        long mem_max = (long)arg;
@@ -1264,6 +1369,7 @@ struct memcg_test {
        T(test_memcg_high),
        T(test_memcg_high_sync),
        T(test_memcg_max),
+       T(test_memcg_reclaim),
        T(test_memcg_oom_events),
        T(test_memcg_swap_max),
        T(test_memcg_sock),