Commit fd06ce2c authored by Mike Yuan's avatar Mike Yuan Committed by Andrew Morton

selftests: test_zswap: add test for hierarchical zswap.writeback

Ensure that zswap.writeback check goes up the cgroup tree, i.e.  is
hierarchical.  Create a subcgroup which has zswap.writeback set to 1, and
the upper hierarchy's restrictions shall apply.

Link: https://lkml.kernel.org/r/20240823162506.12117-2-me@yhndnzj.comSigned-off-by: default avatarMike Yuan <me@yhndnzj.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Michal Koutný <mkoutny@suse.com>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Yosry Ahmed <yosryahmed@google.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 20a5532f
...@@ -263,15 +263,13 @@ static int test_zswapin(const char *root) ...@@ -263,15 +263,13 @@ static int test_zswapin(const char *root)
static int attempt_writeback(const char *cgroup, void *arg) static int attempt_writeback(const char *cgroup, void *arg)
{ {
long pagesize = sysconf(_SC_PAGESIZE); long pagesize = sysconf(_SC_PAGESIZE);
char *test_group = arg;
size_t memsize = MB(4); size_t memsize = MB(4);
char buf[pagesize]; char buf[pagesize];
long zswap_usage; long zswap_usage;
bool wb_enabled; bool wb_enabled = *(bool *) arg;
int ret = -1; int ret = -1;
char *mem; char *mem;
wb_enabled = cg_read_long(test_group, "memory.zswap.writeback");
mem = (char *)malloc(memsize); mem = (char *)malloc(memsize);
if (!mem) if (!mem)
return ret; return ret;
...@@ -288,12 +286,12 @@ static int attempt_writeback(const char *cgroup, void *arg) ...@@ -288,12 +286,12 @@ static int attempt_writeback(const char *cgroup, void *arg)
memcpy(&mem[i], buf, pagesize); memcpy(&mem[i], buf, pagesize);
/* Try and reclaim allocated memory */ /* Try and reclaim allocated memory */
if (cg_write_numeric(test_group, "memory.reclaim", memsize)) { if (cg_write_numeric(cgroup, "memory.reclaim", memsize)) {
ksft_print_msg("Failed to reclaim all of the requested memory\n"); ksft_print_msg("Failed to reclaim all of the requested memory\n");
goto out; goto out;
} }
zswap_usage = cg_read_long(test_group, "memory.zswap.current"); zswap_usage = cg_read_long(cgroup, "memory.zswap.current");
/* zswpin */ /* zswpin */
for (int i = 0; i < memsize; i += pagesize) { for (int i = 0; i < memsize; i += pagesize) {
...@@ -303,7 +301,7 @@ static int attempt_writeback(const char *cgroup, void *arg) ...@@ -303,7 +301,7 @@ static int attempt_writeback(const char *cgroup, void *arg)
} }
} }
if (cg_write_numeric(test_group, "memory.zswap.max", zswap_usage/2)) if (cg_write_numeric(cgroup, "memory.zswap.max", zswap_usage/2))
goto out; goto out;
/* /*
...@@ -312,7 +310,7 @@ static int attempt_writeback(const char *cgroup, void *arg) ...@@ -312,7 +310,7 @@ static int attempt_writeback(const char *cgroup, void *arg)
* If writeback is disabled, memory reclaim will fail as zswap is limited and * If writeback is disabled, memory reclaim will fail as zswap is limited and
* it can't writeback to swap. * it can't writeback to swap.
*/ */
ret = cg_write_numeric(test_group, "memory.reclaim", memsize); ret = cg_write_numeric(cgroup, "memory.reclaim", memsize);
if (!wb_enabled) if (!wb_enabled)
ret = (ret == -EAGAIN) ? 0 : -1; ret = (ret == -EAGAIN) ? 0 : -1;
...@@ -321,12 +319,41 @@ static int attempt_writeback(const char *cgroup, void *arg) ...@@ -321,12 +319,41 @@ static int attempt_writeback(const char *cgroup, void *arg)
return ret; return ret;
} }
static int test_zswap_writeback_one(const char *cgroup, bool wb)
{
long zswpwb_before, zswpwb_after;
zswpwb_before = get_cg_wb_count(cgroup);
if (zswpwb_before != 0) {
ksft_print_msg("zswpwb_before = %ld instead of 0\n", zswpwb_before);
return -1;
}
if (cg_run(cgroup, attempt_writeback, (void *) &wb))
return -1;
/* Verify that zswap writeback occurred only if writeback was enabled */
zswpwb_after = get_cg_wb_count(cgroup);
if (zswpwb_after < 0)
return -1;
if (wb != !!zswpwb_after) {
ksft_print_msg("zswpwb_after is %ld while wb is %s",
zswpwb_after, wb ? "enabled" : "disabled");
return -1;
}
return 0;
}
/* Test to verify the zswap writeback path */ /* Test to verify the zswap writeback path */
static int test_zswap_writeback(const char *root, bool wb) static int test_zswap_writeback(const char *root, bool wb)
{ {
long zswpwb_before, zswpwb_after;
int ret = KSFT_FAIL; int ret = KSFT_FAIL;
char *test_group; char *test_group, *test_group_child = NULL;
if (cg_read_strcmp(root, "memory.zswap.writeback", "1"))
return KSFT_SKIP;
test_group = cg_name(root, "zswap_writeback_test"); test_group = cg_name(root, "zswap_writeback_test");
if (!test_group) if (!test_group)
...@@ -336,29 +363,35 @@ static int test_zswap_writeback(const char *root, bool wb) ...@@ -336,29 +363,35 @@ static int test_zswap_writeback(const char *root, bool wb)
if (cg_write(test_group, "memory.zswap.writeback", wb ? "1" : "0")) if (cg_write(test_group, "memory.zswap.writeback", wb ? "1" : "0"))
goto out; goto out;
zswpwb_before = get_cg_wb_count(test_group); if (test_zswap_writeback_one(test_group, wb))
if (zswpwb_before != 0) {
ksft_print_msg("zswpwb_before = %ld instead of 0\n", zswpwb_before);
goto out; goto out;
}
if (cg_run(test_group, attempt_writeback, (void *) test_group)) /* Reset memory.zswap.max to max (modified by attempt_writeback), and
* set up child cgroup, whose memory.zswap.writeback is hardcoded to 1.
* Thus, the parent's setting shall be what's in effect. */
if (cg_write(test_group, "memory.zswap.max", "max"))
goto out;
if (cg_write(test_group, "cgroup.subtree_control", "+memory"))
goto out; goto out;
/* Verify that zswap writeback occurred only if writeback was enabled */ test_group_child = cg_name(test_group, "zswap_writeback_test_child");
zswpwb_after = get_cg_wb_count(test_group); if (!test_group_child)
if (zswpwb_after < 0) goto out;
if (cg_create(test_group_child))
goto out;
if (cg_write(test_group_child, "memory.zswap.writeback", "1"))
goto out; goto out;
if (wb != !!zswpwb_after) { if (test_zswap_writeback_one(test_group_child, wb))
ksft_print_msg("zswpwb_after is %ld while wb is %s",
zswpwb_after, wb ? "enabled" : "disabled");
goto out; goto out;
}
ret = KSFT_PASS; ret = KSFT_PASS;
out: out:
if (test_group_child) {
cg_destroy(test_group_child);
free(test_group_child);
}
cg_destroy(test_group); cg_destroy(test_group);
free(test_group); free(test_group);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment