* [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes
@ 2026-04-24 4:00 Li Wang
2026-04-24 4:00 ` [PATCH v7 1/8] selftests/cgroup: skip test_zswap if zswap is globally disabled Li Wang
` (9 more replies)
0 siblings, 10 replies; 13+ messages in thread
From: Li Wang @ 2026-04-24 4:00 UTC (permalink / raw)
To: akpm, tj, longman, roman.gushchin, hannes, yosry, jiayuan.chen,
nphamcs, chengming.zhou, mkoutny, shuah
Cc: linux-mm, cgroups, linux-kselftest, linux-kernel
This patchset aims to fix various spurious failures and improve the overall
robustness of the cgroup zswap selftests.
The primary motivation is to make the tests compatible with architectures
that use non-4K page sizes (such as 64K on ppc64le and arm64). Currently,
the tests rely heavily on hardcoded 4K page sizes and fixed memory limits.
On 64K page size systems, these hardcoded values lead to sub-page granularity
accesses, incorrect page count calculations, and insufficient memory pressure
to trigger zswap writeback, ultimately causing the tests to fail.
Additionally, this series addresses OOM kills occurring in test_swapin_nozswap
by dynamically scaling memory limits, and prevents spurious test failures
when zswap is built into the kernel but globally disabled.
Changes in v7:
Replace my work email by li.wang@linux.dev address.
Add Acked-by: Nhat Pham <nphamcs@gmail.com> to series.
Rebase to the latest branch (only one tiny conflict resolved).
Changes in v6:
Patch 4/8: Use page_size instead of BUF_SIZE
Declear page_size as int but not size_t
Patch 5/8: Use page_size replace the sysconf(_SC_PAGE_SIZE).
Patch 7/8: Adjust the code comments.
Patch 8/8: Declear long type for elapsed and count variables.
Changes in v5:
Patch 1/8: Defined PATH_ZSWAP and PATH_ZSWAP_ENABLED macros.
Patch 4/8: Merge Waiman's work into this patch (use page_size).
Patch 5/8: Change pagesize by the global page_size.
Patch 6/8: Swap data patterns: use getrandom() for wb_group and simple
memset for zw_group to fix the reversed allocation logic.
Patch 7/8: Setting zswap.max to zswap_usage/4 to increase writeback pressure.
Patch 8/8: New added. Just add loops for read zswpwb more times.
Test all passed on:
x86_64(4k), aarch64(4K, 64K), ppc64le(64K).
Li Wang (8):
selftests/cgroup: skip test_zswap if zswap is globally disabled
selftests/cgroup: avoid OOM in test_swapin_nozswap
selftests/cgroup: use runtime page size for zswpin check
selftests/cgroup: rename PAGE_SIZE to BUF_SIZE in cgroup_util
selftests/cgroup: replace hardcoded page size values in test_zswap
selftest/cgroup: fix zswap test_no_invasive_cgroup_shrink on large
pagesize system
selftest/cgroup: fix zswap attempt_writeback() on 64K pagesize system
selftests/cgroup: test_zswap: wait for asynchronous writeback
.../selftests/cgroup/lib/cgroup_util.c | 18 +-
.../cgroup/lib/include/cgroup_util.h | 4 +-
tools/testing/selftests/cgroup/test_core.c | 2 +-
tools/testing/selftests/cgroup/test_freezer.c | 2 +-
.../selftests/cgroup/test_memcontrol.c | 19 +-
tools/testing/selftests/cgroup/test_zswap.c | 181 ++++++++++++------
6 files changed, 152 insertions(+), 74 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v7 1/8] selftests/cgroup: skip test_zswap if zswap is globally disabled
2026-04-24 4:00 [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Li Wang
@ 2026-04-24 4:00 ` Li Wang
2026-04-24 4:00 ` [PATCH v7 2/8] selftests/cgroup: avoid OOM in test_swapin_nozswap Li Wang
` (8 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Li Wang @ 2026-04-24 4:00 UTC (permalink / raw)
To: akpm, tj, longman, roman.gushchin, hannes, yosry, jiayuan.chen,
nphamcs, chengming.zhou, mkoutny, shuah
Cc: linux-mm, cgroups, linux-kselftest, linux-kernel, Michal Hocko,
Muchun Song, Shakeel Butt, Yosry Ahmed
test_zswap currently only checks whether zswap is present by testing
/sys/module/zswap. This misses the runtime global state exposed in
/sys/module/zswap/parameters/enabled.
When zswap is built/loaded but globally disabled, the zswap cgroup
selftests run in an invalid environment and may fail spuriously.
Check the runtime enabled state before running the tests:
- skip if zswap is not configured,
- fail if the enabled knob cannot be read,
- skip if zswap is globally disabled.
Also print a hint in the skip message on how to enable zswap.
Signed-off-by: Li Wang <li.wang@linux.dev>
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: Tejun Heo <tj@kernel.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Yosry Ahmed <yosryahmed@google.com>
Acked-by: Yosry Ahmed <yosry@kernel.org>
Acked-by: Nhat Pham <nphamcs@gmail.com>
---
tools/testing/selftests/cgroup/test_zswap.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/cgroup/test_zswap.c b/tools/testing/selftests/cgroup/test_zswap.c
index a7bdcdd09d6..a94238a2e04 100644
--- a/tools/testing/selftests/cgroup/test_zswap.c
+++ b/tools/testing/selftests/cgroup/test_zswap.c
@@ -15,6 +15,9 @@
#include "kselftest.h"
#include "cgroup_util.h"
+#define PATH_ZSWAP "/sys/module/zswap"
+#define PATH_ZSWAP_ENABLED "/sys/module/zswap/parameters/enabled"
+
static int read_int(const char *path, size_t *value)
{
FILE *file;
@@ -725,9 +728,18 @@ struct zswap_test {
};
#undef T
-static bool zswap_configured(void)
+static void check_zswap_enabled(void)
{
- return access("/sys/module/zswap", F_OK) == 0;
+ char value[2];
+
+ if (access(PATH_ZSWAP, F_OK))
+ ksft_exit_skip("zswap isn't configured\n");
+
+ if (read_text(PATH_ZSWAP_ENABLED, value, sizeof(value)) <= 0)
+ ksft_exit_fail_msg("Failed to read " PATH_ZSWAP_ENABLED "\n");
+
+ if (value[0] == 'N')
+ ksft_exit_skip("zswap is disabled (hint: echo 1 > " PATH_ZSWAP_ENABLED ")\n");
}
int main(int argc, char **argv)
@@ -740,8 +752,7 @@ int main(int argc, char **argv)
if (cg_find_unified_root(root, sizeof(root), NULL))
ksft_exit_skip("cgroup v2 isn't mounted\n");
- if (!zswap_configured())
- ksft_exit_skip("zswap isn't configured\n");
+ check_zswap_enabled();
/*
* Check that memory controller is available:
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v7 2/8] selftests/cgroup: avoid OOM in test_swapin_nozswap
2026-04-24 4:00 [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Li Wang
2026-04-24 4:00 ` [PATCH v7 1/8] selftests/cgroup: skip test_zswap if zswap is globally disabled Li Wang
@ 2026-04-24 4:00 ` Li Wang
2026-04-24 4:00 ` [PATCH v7 3/8] selftests/cgroup: use runtime page size for zswpin check Li Wang
` (7 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Li Wang @ 2026-04-24 4:00 UTC (permalink / raw)
To: akpm, tj, longman, roman.gushchin, hannes, yosry, jiayuan.chen,
nphamcs, chengming.zhou, mkoutny, shuah
Cc: linux-mm, cgroups, linux-kselftest, linux-kernel, Michal Hocko,
Muchun Song, Shakeel Butt
test_swapin_nozswap can hit OOM before reaching its assertions on some
setups. The test currently sets memory.max=8M and then allocates/reads
32M with memory.zswap.max=0, which may over-constrain reclaim and kill
the workload process.
Replace hardcoded sizes with PAGE_SIZE-based values:
- control_allocation_size = PAGE_SIZE * 512
- memory.max = control_allocation_size * 3 / 4
- minimum expected swap = control_allocation_size / 4
This keeps the test pressure model intact (allocate/read beyond memory.max to
force swap-in/out) while making it more robust across different environments.
The test intent is unchanged: confirm that swapping occurs while zswap remains
unused when memory.zswap.max=0.
=== Error Logs ===
# ./test_zswap
TAP version 13
1..7
ok 1 test_zswap_usage
not ok 2 test_swapin_nozswap
...
# dmesg
[271641.879153] test_zswap invoked oom-killer: gfp_mask=0xcc0(GFP_KERNEL), order=0, oom_score_adj=0
[271641.879168] CPU: 1 UID: 0 PID: 177372 Comm: test_zswap Kdump: loaded Not tainted 6.12.0-211.el10.ppc64le #1 VOLUNTARY
[271641.879171] Hardware name: IBM,9009-41A POWER9 (architected) 0x4e0202 0xf000005 of:IBM,FW940.02 (UL940_041) hv:phyp pSeries
[271641.879173] Call Trace:
[271641.879174] [c00000037540f730] [c00000000127ec44] dump_stack_lvl+0x88/0xc4 (unreliable)
[271641.879184] [c00000037540f760] [c0000000005cc594] dump_header+0x5c/0x1e4
[271641.879188] [c00000037540f7e0] [c0000000005cb464] oom_kill_process+0x324/0x3b0
[271641.879192] [c00000037540f860] [c0000000005cbe48] out_of_memory+0x118/0x420
[271641.879196] [c00000037540f8f0] [c00000000070d8ec] mem_cgroup_out_of_memory+0x18c/0x1b0
[271641.879200] [c00000037540f990] [c000000000713888] try_charge_memcg+0x598/0x890
[271641.879204] [c00000037540fa70] [c000000000713dbc] charge_memcg+0x5c/0x110
[271641.879207] [c00000037540faa0] [c0000000007159f8] __mem_cgroup_charge+0x48/0x120
[271641.879211] [c00000037540fae0] [c000000000641914] alloc_anon_folio+0x2b4/0x5a0
[271641.879215] [c00000037540fb60] [c000000000641d58] do_anonymous_page+0x158/0x6b0
[271641.879218] [c00000037540fbd0] [c000000000642f8c] __handle_mm_fault+0x4bc/0x910
[271641.879221] [c00000037540fcf0] [c000000000643500] handle_mm_fault+0x120/0x3c0
[271641.879224] [c00000037540fd40] [c00000000014bba0] ___do_page_fault+0x1c0/0x980
[271641.879228] [c00000037540fdf0] [c00000000014c44c] hash__do_page_fault+0x2c/0xc0
[271641.879232] [c00000037540fe20] [c0000000001565d8] do_hash_fault+0x128/0x1d0
[271641.879236] [c00000037540fe50] [c000000000008be0] data_access_common_virt+0x210/0x220
[271641.879548] Tasks state (memory values in pages):
...
[271641.879550] [ pid ] uid tgid total_vm rss rss_anon rss_file rss_shmem pgtables_bytes swapents oom_score_adj name
[271641.879555] [ 177372] 0 177372 571 0 0 0 0 51200 96 0 test_zswap
[271641.879562] oom-kill:constraint=CONSTRAINT_MEMCG,nodemask=(null),cpuset=/,mems_allowed=0,oom_memcg=/no_zswap_test,task_memcg=/no_zswap_test,task=test_zswap,pid=177372,uid=0
[271641.879578] Memory cgroup out of memory: Killed process 177372 (test_zswap) total-vm:36544kB, anon-rss:0kB, file-rss:0kB, shmem-rss:0kB, UID:0 pgtables:50kB oom_score_adj:0
Signed-off-by: Li Wang <li.wang@linux.dev>
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: Tejun Heo <tj@kernel.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: Yosry Ahmed <yosry@kernel.org>
Acked-by: Nhat Pham <nphamcs@gmail.com>
---
tools/testing/selftests/cgroup/test_zswap.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/cgroup/test_zswap.c b/tools/testing/selftests/cgroup/test_zswap.c
index a94238a2e04..47709cbdcdf 100644
--- a/tools/testing/selftests/cgroup/test_zswap.c
+++ b/tools/testing/selftests/cgroup/test_zswap.c
@@ -165,21 +165,25 @@ static int test_zswap_usage(const char *root)
static int test_swapin_nozswap(const char *root)
{
int ret = KSFT_FAIL;
- char *test_group;
- long swap_peak, zswpout;
+ char *test_group, mem_max_buf[32];
+ long swap_peak, zswpout, min_swap;
+ size_t allocation_size = sysconf(_SC_PAGESIZE) * 512;
+
+ min_swap = allocation_size / 4;
+ snprintf(mem_max_buf, sizeof(mem_max_buf), "%zu", allocation_size * 3/4);
test_group = cg_name(root, "no_zswap_test");
if (!test_group)
goto out;
if (cg_create(test_group))
goto out;
- if (cg_write(test_group, "memory.max", "8M"))
+ if (cg_write(test_group, "memory.max", mem_max_buf))
goto out;
if (cg_write(test_group, "memory.zswap.max", "0"))
goto out;
/* Allocate and read more than memory.max to trigger swapin */
- if (cg_run(test_group, allocate_and_read_bytes, (void *)MB(32)))
+ if (cg_run(test_group, allocate_and_read_bytes, (void *)allocation_size))
goto out;
/* Verify that pages are swapped out, but no zswap happened */
@@ -189,8 +193,9 @@ static int test_swapin_nozswap(const char *root)
goto out;
}
- if (swap_peak < MB(24)) {
- ksft_print_msg("at least 24MB of memory should be swapped out\n");
+ if (swap_peak < min_swap) {
+ ksft_print_msg("at least %ldKB of memory should be swapped out\n",
+ min_swap / 1024);
goto out;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v7 3/8] selftests/cgroup: use runtime page size for zswpin check
2026-04-24 4:00 [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Li Wang
2026-04-24 4:00 ` [PATCH v7 1/8] selftests/cgroup: skip test_zswap if zswap is globally disabled Li Wang
2026-04-24 4:00 ` [PATCH v7 2/8] selftests/cgroup: avoid OOM in test_swapin_nozswap Li Wang
@ 2026-04-24 4:00 ` Li Wang
2026-04-24 4:00 ` [PATCH v7 4/8] selftests/cgroup: rename PAGE_SIZE to BUF_SIZE in cgroup_util Li Wang
` (6 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Li Wang @ 2026-04-24 4:00 UTC (permalink / raw)
To: akpm, tj, longman, roman.gushchin, hannes, yosry, jiayuan.chen,
nphamcs, chengming.zhou, mkoutny, shuah
Cc: linux-mm, cgroups, linux-kselftest, linux-kernel, Michal Hocko,
Muchun Song, Shakeel Butt
test_zswapin compares memory.stat:zswpin (counted in pages) against a
byte threshold converted with PAGE_SIZE. In cgroup selftests, PAGE_SIZE
is hardcoded to 4096, which makes the conversion wrong on systems with
non-4K base pages (e.g. 64K).
As a result, the test requires too many pages to pass and fails
spuriously even when zswap is working.
Use sysconf(_SC_PAGESIZE) for the zswpin threshold conversion so the
check matches the actual system page size.
Signed-off-by: Li Wang <li.wang@linux.dev>
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: Tejun Heo <tj@kernel.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Reviewed-by: Yosry Ahmed <yosry@kernel.org>
Acked-by: Nhat Pham <nphamcs@gmail.com>
---
tools/testing/selftests/cgroup/test_zswap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/cgroup/test_zswap.c b/tools/testing/selftests/cgroup/test_zswap.c
index 47709cbdcdf..37aa83c2f1b 100644
--- a/tools/testing/selftests/cgroup/test_zswap.c
+++ b/tools/testing/selftests/cgroup/test_zswap.c
@@ -245,7 +245,7 @@ static int test_zswapin(const char *root)
goto out;
}
- if (zswpin < MB(24) / PAGE_SIZE) {
+ if (zswpin < MB(24) / sysconf(_SC_PAGESIZE)) {
ksft_print_msg("at least 24MB should be brought back from zswap\n");
goto out;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v7 4/8] selftests/cgroup: rename PAGE_SIZE to BUF_SIZE in cgroup_util
2026-04-24 4:00 [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Li Wang
` (2 preceding siblings ...)
2026-04-24 4:00 ` [PATCH v7 3/8] selftests/cgroup: use runtime page size for zswpin check Li Wang
@ 2026-04-24 4:00 ` Li Wang
2026-04-24 4:00 ` [PATCH v7 5/8] selftests/cgroup: replace hardcoded page size values in test_zswap Li Wang
` (5 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Li Wang @ 2026-04-24 4:00 UTC (permalink / raw)
To: akpm, tj, longman, roman.gushchin, hannes, yosry, jiayuan.chen,
nphamcs, chengming.zhou, mkoutny, shuah
Cc: linux-mm, cgroups, linux-kselftest, linux-kernel, Michal Hocko,
Muchun Song, Shakeel Butt, Yosry Ahmed
The cgroup utility code defines a local PAGE_SIZE macro hardcoded to
4096, which is used primarily as a generic buffer size for reading cgroup
and proc files. This naming is misleading because the value has nothing
to do with the actual page size of the system. On architectures with larger
pages (e.g., 64K on arm64 or ppc64), the name suggests a relationship that
does not exist. Additionally, the name can shadow or conflict with PAGE_SIZE
definitions from system headers, leading to confusion or subtle bugs.
To resolve this, rename the macro to BUF_SIZE to accurately reflect its
purpose as a general I/O buffer size.
Furthermore, test_memcontrol currently relies on this hardcoded 4K value
to stride through memory and trigger page faults. Update this logic to
use the actual system page size dynamically. This micro-optimizes the
memory faulting process by ensuring it iterates correctly and efficiently
based on the underlying architecture's true page size. (This part from Waiman)
Signed-off-by: Li Wang <li.wang@linux.dev>
Signed-off-by: Waiman Long <longman@redhat.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: Tejun Heo <tj@kernel.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Yosry Ahmed <yosryahmed@google.com>
Acked-by: Nhat Pham <nphamcs@gmail.com>
---
.../selftests/cgroup/lib/cgroup_util.c | 18 +++++++++---------
.../cgroup/lib/include/cgroup_util.h | 4 ++--
tools/testing/selftests/cgroup/test_core.c | 2 +-
tools/testing/selftests/cgroup/test_freezer.c | 2 +-
.../selftests/cgroup/test_memcontrol.c | 19 ++++++++++++-------
5 files changed, 25 insertions(+), 20 deletions(-)
diff --git a/tools/testing/selftests/cgroup/lib/cgroup_util.c b/tools/testing/selftests/cgroup/lib/cgroup_util.c
index 6a7295347e9..9be8ac25657 100644
--- a/tools/testing/selftests/cgroup/lib/cgroup_util.c
+++ b/tools/testing/selftests/cgroup/lib/cgroup_util.c
@@ -140,7 +140,7 @@ int cg_read_strcmp_wait(const char *cgroup, const char *control,
int cg_read_strstr(const char *cgroup, const char *control, const char *needle)
{
- char buf[PAGE_SIZE];
+ char buf[BUF_SIZE];
if (cg_read(cgroup, control, buf, sizeof(buf)))
return -1;
@@ -170,7 +170,7 @@ long cg_read_long_fd(int fd)
long cg_read_key_long(const char *cgroup, const char *control, const char *key)
{
- char buf[PAGE_SIZE];
+ char buf[BUF_SIZE];
char *ptr;
if (cg_read(cgroup, control, buf, sizeof(buf)))
@@ -206,7 +206,7 @@ long cg_read_key_long_poll(const char *cgroup, const char *control,
long cg_read_lc(const char *cgroup, const char *control)
{
- char buf[PAGE_SIZE];
+ char buf[BUF_SIZE];
const char delim[] = "\n";
char *line;
long cnt = 0;
@@ -258,7 +258,7 @@ int cg_write_numeric(const char *cgroup, const char *control, long value)
static int cg_find_root(char *root, size_t len, const char *controller,
bool *nsdelegate)
{
- char buf[10 * PAGE_SIZE];
+ char buf[10 * BUF_SIZE];
char *fs, *mount, *type, *options;
const char delim[] = "\n\t ";
@@ -313,7 +313,7 @@ int cg_create(const char *cgroup)
int cg_wait_for_proc_count(const char *cgroup, int count)
{
- char buf[10 * PAGE_SIZE] = {0};
+ char buf[10 * BUF_SIZE] = {0};
int attempts;
char *ptr;
@@ -338,7 +338,7 @@ int cg_wait_for_proc_count(const char *cgroup, int count)
int cg_killall(const char *cgroup)
{
- char buf[PAGE_SIZE];
+ char buf[BUF_SIZE];
char *ptr = buf;
/* If cgroup.kill exists use it. */
@@ -548,7 +548,7 @@ int cg_run_nowait(const char *cgroup,
int proc_mount_contains(const char *option)
{
- char buf[4 * PAGE_SIZE];
+ char buf[4 * BUF_SIZE];
ssize_t read;
read = read_text("/proc/mounts", buf, sizeof(buf));
@@ -560,7 +560,7 @@ int proc_mount_contains(const char *option)
int cgroup_feature(const char *feature)
{
- char buf[PAGE_SIZE];
+ char buf[BUF_SIZE];
ssize_t read;
read = read_text("/sys/kernel/cgroup/features", buf, sizeof(buf));
@@ -587,7 +587,7 @@ ssize_t proc_read_text(int pid, bool thread, const char *item, char *buf, size_t
int proc_read_strstr(int pid, bool thread, const char *item, const char *needle)
{
- char buf[PAGE_SIZE];
+ char buf[BUF_SIZE];
if (proc_read_text(pid, thread, item, buf, sizeof(buf)) < 0)
return -1;
diff --git a/tools/testing/selftests/cgroup/lib/include/cgroup_util.h b/tools/testing/selftests/cgroup/lib/include/cgroup_util.h
index 567b1082974..febc1723d09 100644
--- a/tools/testing/selftests/cgroup/lib/include/cgroup_util.h
+++ b/tools/testing/selftests/cgroup/lib/include/cgroup_util.h
@@ -2,8 +2,8 @@
#include <stdbool.h>
#include <stdlib.h>
-#ifndef PAGE_SIZE
-#define PAGE_SIZE 4096
+#ifndef BUF_SIZE
+#define BUF_SIZE 4096
#endif
#define MB(x) (x << 20)
diff --git a/tools/testing/selftests/cgroup/test_core.c b/tools/testing/selftests/cgroup/test_core.c
index 7b83c7e7c9d..88ca832d4fc 100644
--- a/tools/testing/selftests/cgroup/test_core.c
+++ b/tools/testing/selftests/cgroup/test_core.c
@@ -87,7 +87,7 @@ static int test_cgcore_destroy(const char *root)
int ret = KSFT_FAIL;
char *cg_test = NULL;
int child_pid;
- char buf[PAGE_SIZE];
+ char buf[BUF_SIZE];
cg_test = cg_name(root, "cg_test");
diff --git a/tools/testing/selftests/cgroup/test_freezer.c b/tools/testing/selftests/cgroup/test_freezer.c
index 97fae92c838..160a9e6ad27 100644
--- a/tools/testing/selftests/cgroup/test_freezer.c
+++ b/tools/testing/selftests/cgroup/test_freezer.c
@@ -642,7 +642,7 @@ static int test_cgfreezer_ptrace(const char *root)
*/
static int proc_check_stopped(int pid)
{
- char buf[PAGE_SIZE];
+ char buf[BUF_SIZE];
int len;
len = proc_read_text(pid, 0, "stat", buf, sizeof(buf));
diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c
index b43da9bc20c..44338dbaee8 100644
--- a/tools/testing/selftests/cgroup/test_memcontrol.c
+++ b/tools/testing/selftests/cgroup/test_memcontrol.c
@@ -26,6 +26,7 @@
static bool has_localevents;
static bool has_recursiveprot;
+static int page_size;
int get_temp_fd(void)
{
@@ -34,7 +35,7 @@ int get_temp_fd(void)
int alloc_pagecache(int fd, size_t size)
{
- char buf[PAGE_SIZE];
+ char buf[BUF_SIZE];
struct stat st;
int i;
@@ -61,7 +62,7 @@ int alloc_anon(const char *cgroup, void *arg)
char *buf, *ptr;
buf = malloc(size);
- for (ptr = buf; ptr < buf + size; ptr += PAGE_SIZE)
+ for (ptr = buf; ptr < buf + size; ptr += page_size)
*ptr = 0;
free(buf);
@@ -70,7 +71,7 @@ int alloc_anon(const char *cgroup, void *arg)
int is_swap_enabled(void)
{
- char buf[PAGE_SIZE];
+ char buf[BUF_SIZE];
const char delim[] = "\n";
int cnt = 0;
char *line;
@@ -113,7 +114,7 @@ static int test_memcg_subtree_control(const char *root)
{
char *parent, *child, *parent2 = NULL, *child2 = NULL;
int ret = KSFT_FAIL;
- char buf[PAGE_SIZE];
+ char buf[BUF_SIZE];
/* Create two nested cgroups with the memory controller enabled */
parent = cg_name(root, "memcg_test_0");
@@ -184,7 +185,7 @@ static int alloc_anon_50M_check(const char *cgroup, void *arg)
return -1;
}
- for (ptr = buf; ptr < buf + size; ptr += PAGE_SIZE)
+ for (ptr = buf; ptr < buf + size; ptr += page_size)
*ptr = 0;
current = cg_read_long(cgroup, "memory.current");
@@ -414,7 +415,7 @@ static int alloc_anon_noexit(const char *cgroup, void *arg)
return -1;
}
- for (ptr = buf; ptr < buf + size; ptr += PAGE_SIZE)
+ for (ptr = buf; ptr < buf + size; ptr += page_size)
*ptr = 0;
while (getppid() == ppid)
@@ -1000,7 +1001,7 @@ static int alloc_anon_50M_check_swap(const char *cgroup, void *arg)
return -1;
}
- for (ptr = buf; ptr < buf + size; ptr += PAGE_SIZE)
+ for (ptr = buf; ptr < buf + size; ptr += page_size)
*ptr = 0;
mem_current = cg_read_long(cgroup, "memory.current");
@@ -1791,6 +1792,10 @@ int main(int argc, char **argv)
char root[PATH_MAX];
int i, proc_status;
+ page_size = sysconf(_SC_PAGE_SIZE);
+ if (page_size <= 0)
+ page_size = BUF_SIZE;
+
ksft_print_header();
ksft_set_plan(ARRAY_SIZE(tests));
if (cg_find_unified_root(root, sizeof(root), NULL))
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v7 5/8] selftests/cgroup: replace hardcoded page size values in test_zswap
2026-04-24 4:00 [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Li Wang
` (3 preceding siblings ...)
2026-04-24 4:00 ` [PATCH v7 4/8] selftests/cgroup: rename PAGE_SIZE to BUF_SIZE in cgroup_util Li Wang
@ 2026-04-24 4:00 ` Li Wang
2026-04-24 5:20 ` Jiayuan Chen
2026-04-24 4:00 ` [PATCH v7 6/8] selftest/cgroup: fix zswap test_no_invasive_cgroup_shrink on large pagesize system Li Wang
` (4 subsequent siblings)
9 siblings, 1 reply; 13+ messages in thread
From: Li Wang @ 2026-04-24 4:00 UTC (permalink / raw)
To: akpm, tj, longman, roman.gushchin, hannes, yosry, jiayuan.chen,
nphamcs, chengming.zhou, mkoutny, shuah
Cc: linux-mm, cgroups, linux-kselftest, linux-kernel, Michal Hocko,
Muchun Song, Shakeel Butt
test_zswap uses hardcoded values of 4095 and 4096 throughout as page
stride and page size, which are only correct on systems with a 4K page
size. On architectures with larger pages (e.g., 64K on arm64 or ppc64),
these constants cause memory to be touched at sub-page granularity,
leading to inefficient access patterns and incorrect page count
calculations, which can cause test failures.
Replace all hardcoded 4095 and 4096 values with a global pagesize
variable initialized from sysconf(_SC_PAGESIZE) at startup, and remove
the redundant local sysconf() calls scattered across individual
functions. No functional change on 4K page size systems.
Signed-off-by: Li Wang <li.wang@linux.dev>
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: Tejun Heo <tj@kernel.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: Yosry Ahmed <yosry@kernel.org>
---
tools/testing/selftests/cgroup/test_zswap.c | 45 ++++++++++++---------
1 file changed, 25 insertions(+), 20 deletions(-)
diff --git a/tools/testing/selftests/cgroup/test_zswap.c b/tools/testing/selftests/cgroup/test_zswap.c
index 37aa83c2f1b..23ff11390a3 100644
--- a/tools/testing/selftests/cgroup/test_zswap.c
+++ b/tools/testing/selftests/cgroup/test_zswap.c
@@ -15,6 +15,8 @@
#include "kselftest.h"
#include "cgroup_util.h"
+static int page_size;
+
#define PATH_ZSWAP "/sys/module/zswap"
#define PATH_ZSWAP_ENABLED "/sys/module/zswap/parameters/enabled"
@@ -73,11 +75,11 @@ static int allocate_and_read_bytes(const char *cgroup, void *arg)
if (!mem)
return -1;
- for (int i = 0; i < size; i += 4095)
+ for (int i = 0; i < size; i += page_size)
mem[i] = 'a';
/* Go through the allocated memory to (z)swap in and out pages */
- for (int i = 0; i < size; i += 4095) {
+ for (int i = 0; i < size; i += page_size) {
if (mem[i] != 'a')
ret = -1;
}
@@ -93,7 +95,7 @@ static int allocate_bytes(const char *cgroup, void *arg)
if (!mem)
return -1;
- for (int i = 0; i < size; i += 4095)
+ for (int i = 0; i < size; i += page_size)
mem[i] = 'a';
free(mem);
return 0;
@@ -167,7 +169,7 @@ static int test_swapin_nozswap(const char *root)
int ret = KSFT_FAIL;
char *test_group, mem_max_buf[32];
long swap_peak, zswpout, min_swap;
- size_t allocation_size = sysconf(_SC_PAGESIZE) * 512;
+ size_t allocation_size = page_size * 512;
min_swap = allocation_size / 4;
snprintf(mem_max_buf, sizeof(mem_max_buf), "%zu", allocation_size * 3/4);
@@ -245,7 +247,7 @@ static int test_zswapin(const char *root)
goto out;
}
- if (zswpin < MB(24) / sysconf(_SC_PAGESIZE)) {
+ if (zswpin < MB(24) / page_size) {
ksft_print_msg("at least 24MB should be brought back from zswap\n");
goto out;
}
@@ -272,9 +274,8 @@ static int test_zswapin(const char *root)
*/
static int attempt_writeback(const char *cgroup, void *arg)
{
- long pagesize = sysconf(_SC_PAGESIZE);
size_t memsize = MB(4);
- char buf[pagesize];
+ char buf[page_size];
long zswap_usage;
bool wb_enabled = *(bool *) arg;
int ret = -1;
@@ -289,11 +290,11 @@ static int attempt_writeback(const char *cgroup, void *arg)
* half empty, this will result in data that is still compressible
* and ends up in zswap, with material zswap usage.
*/
- for (int i = 0; i < pagesize; i++)
- buf[i] = i < pagesize/2 ? (char) i : 0;
+ for (int i = 0; i < page_size; i++)
+ buf[i] = i < page_size/2 ? (char) i : 0;
- for (int i = 0; i < memsize; i += pagesize)
- memcpy(&mem[i], buf, pagesize);
+ for (int i = 0; i < memsize; i += page_size)
+ memcpy(&mem[i], buf, page_size);
/* Try and reclaim allocated memory */
if (cg_write_numeric(cgroup, "memory.reclaim", memsize)) {
@@ -304,8 +305,8 @@ static int attempt_writeback(const char *cgroup, void *arg)
zswap_usage = cg_read_long(cgroup, "memory.zswap.current");
/* zswpin */
- for (int i = 0; i < memsize; i += pagesize) {
- if (memcmp(&mem[i], buf, pagesize)) {
+ for (int i = 0; i < memsize; i += page_size) {
+ if (memcmp(&mem[i], buf, page_size)) {
ksft_print_msg("invalid memory\n");
goto out;
}
@@ -441,7 +442,7 @@ static int test_no_invasive_cgroup_shrink(const char *root)
if (cg_enter_current(control_group))
goto out;
control_allocation = malloc(control_allocation_size);
- for (int i = 0; i < control_allocation_size; i += 4095)
+ for (int i = 0; i < control_allocation_size; i += page_size)
control_allocation[i] = 'a';
if (cg_read_key_long(control_group, "memory.stat", "zswapped") < 1)
goto out;
@@ -481,7 +482,7 @@ static int no_kmem_bypass_child(const char *cgroup, void *arg)
values->child_allocated = true;
return -1;
}
- for (long i = 0; i < values->target_alloc_bytes; i += 4095)
+ for (long i = 0; i < values->target_alloc_bytes; i += page_size)
((char *)allocation)[i] = 'a';
values->child_allocated = true;
pause();
@@ -529,7 +530,7 @@ static int test_no_kmem_bypass(const char *root)
min_free_kb_low = sys_info.totalram / 500000;
values->target_alloc_bytes = (sys_info.totalram - min_free_kb_high * 1000) +
sys_info.totalram * 5 / 100;
- stored_pages_threshold = sys_info.totalram / 5 / 4096;
+ stored_pages_threshold = sys_info.totalram / 5 / page_size;
trigger_allocation_size = sys_info.totalram / 20;
/* Set up test memcg */
@@ -556,7 +557,7 @@ static int test_no_kmem_bypass(const char *root)
if (!trigger_allocation)
break;
- for (int i = 0; i < trigger_allocation_size; i += 4095)
+ for (int i = 0; i < trigger_allocation_size; i += page_size)
trigger_allocation[i] = 'b';
usleep(100000);
free(trigger_allocation);
@@ -567,8 +568,8 @@ static int test_no_kmem_bypass(const char *root)
/* If memory was pushed to zswap, verify it belongs to memcg */
if (stored_pages > stored_pages_threshold) {
int zswapped = cg_read_key_long(test_group, "memory.stat", "zswapped ");
- int delta = stored_pages * 4096 - zswapped;
- int result_ok = delta < stored_pages * 4096 / 4;
+ int delta = stored_pages * page_size - zswapped;
+ int result_ok = delta < stored_pages * page_size / 4;
ret = result_ok ? KSFT_PASS : KSFT_FAIL;
break;
@@ -622,7 +623,7 @@ static int allocate_random_and_wait(const char *cgroup, void *arg)
close(fd);
/* Touch all pages to ensure they're faulted in */
- for (size_t i = 0; i < size; i += PAGE_SIZE)
+ for (size_t i = 0; i < size; i += page_size)
mem[i] = mem[i];
/* Use MADV_PAGEOUT to push pages into zswap */
@@ -752,6 +753,10 @@ int main(int argc, char **argv)
char root[PATH_MAX];
int i;
+ page_size = sysconf(_SC_PAGE_SIZE);
+ if (page_size <= 0)
+ page_size = BUF_SIZE;
+
ksft_print_header();
ksft_set_plan(ARRAY_SIZE(tests));
if (cg_find_unified_root(root, sizeof(root), NULL))
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v7 6/8] selftest/cgroup: fix zswap test_no_invasive_cgroup_shrink on large pagesize system
2026-04-24 4:00 [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Li Wang
` (4 preceding siblings ...)
2026-04-24 4:00 ` [PATCH v7 5/8] selftests/cgroup: replace hardcoded page size values in test_zswap Li Wang
@ 2026-04-24 4:00 ` Li Wang
2026-04-24 4:00 ` [PATCH v7 7/8] selftest/cgroup: fix zswap attempt_writeback() on 64K " Li Wang
` (3 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Li Wang @ 2026-04-24 4:00 UTC (permalink / raw)
To: akpm, tj, longman, roman.gushchin, hannes, yosry, jiayuan.chen,
nphamcs, chengming.zhou, mkoutny, shuah
Cc: linux-mm, cgroups, linux-kselftest, linux-kernel, Michal Hocko,
Muchun Song, Shakeel Butt, Yosry Ahmed
test_no_invasive_cgroup_shrink sets up two cgroups: wb_group, which is
expected to trigger zswap writeback, and a control group (renamed to
zw_group), which should only have pages sitting in zswap without any
writeback.
There are two problems with the current test:
1) The data patterns are reversed. wb_group uses allocate_bytes(), which
writes only a single byte per page — trivially compressible,
especially by zstd — so compressed pages fit within zswap.max and
writeback is never triggered. Meanwhile, the control group uses
getrandom() to produce hard-to-compress data, but it is the group
that does *not* need writeback.
2) The test uses fixed sizes (10K zswap.max, 10MB allocation) that are
too small on systems with large PAGE_SIZE (e.g. 64K), failing to
build enough memory pressure to trigger writeback reliably.
Fix both issues by:
- Swapping the data patterns: fill wb_group pages with partially
random data (getrandom for page_size/4 bytes) to resist compression
and trigger writeback, and fill zw_group pages with simple repeated
data to stay compressed in zswap.
- Making all size parameters PAGE_SIZE-aware: set allocation size to
PAGE_SIZE * 1024, memory.zswap.max to PAGE_SIZE, and memory.max to
allocation_size / 2 for both cgroups.
- Allocating memory inline instead of via cg_run() so the pages
remain resident throughout the test.
=== Error Log ===
# getconf PAGESIZE
65536
# ./test_zswap
TAP version 13
...
ok 5 test_zswap_writeback_disabled
ok 6 # SKIP test_no_kmem_bypass
not ok 7 test_no_invasive_cgroup_shrink
Signed-off-by: Li Wang <li.wang@linux.dev>
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: Tejun Heo <tj@kernel.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Yosry Ahmed <yosryahmed@google.com>
Acked-by: Nhat Pham <nphamcs@gmail.com>
---
tools/testing/selftests/cgroup/test_zswap.c | 70 ++++++++++++++-------
1 file changed, 49 insertions(+), 21 deletions(-)
diff --git a/tools/testing/selftests/cgroup/test_zswap.c b/tools/testing/selftests/cgroup/test_zswap.c
index 23ff11390a3..8f0478923bd 100644
--- a/tools/testing/selftests/cgroup/test_zswap.c
+++ b/tools/testing/selftests/cgroup/test_zswap.c
@@ -11,6 +11,7 @@
#include <string.h>
#include <sys/wait.h>
#include <sys/mman.h>
+#include <sys/random.h>
#include "kselftest.h"
#include "cgroup_util.h"
@@ -426,44 +427,71 @@ static int test_zswap_writeback_disabled(const char *root)
static int test_no_invasive_cgroup_shrink(const char *root)
{
int ret = KSFT_FAIL;
- size_t control_allocation_size = MB(10);
- char *control_allocation = NULL, *wb_group = NULL, *control_group = NULL;
+ unsigned int off;
+ size_t allocation_size = page_size * 1024;
+ unsigned int nr_pages = allocation_size / page_size;
+ char zswap_max_buf[32], mem_max_buf[32];
+ char *zw_allocation = NULL, *wb_allocation = NULL;
+ char *zw_group = NULL, *wb_group = NULL;
+
+ snprintf(zswap_max_buf, sizeof(zswap_max_buf), "%d", page_size);
+ snprintf(mem_max_buf, sizeof(mem_max_buf), "%zu", allocation_size / 2);
wb_group = setup_test_group_1M(root, "per_memcg_wb_test1");
if (!wb_group)
return KSFT_FAIL;
- if (cg_write(wb_group, "memory.zswap.max", "10K"))
+ if (cg_write(wb_group, "memory.zswap.max", zswap_max_buf))
+ goto out;
+ if (cg_write(wb_group, "memory.max", mem_max_buf))
+ goto out;
+
+ zw_group = setup_test_group_1M(root, "per_memcg_wb_test2");
+ if (!zw_group)
goto out;
- control_group = setup_test_group_1M(root, "per_memcg_wb_test2");
- if (!control_group)
+ if (cg_write(zw_group, "memory.max", mem_max_buf))
goto out;
- /* Push some test_group2 memory into zswap */
- if (cg_enter_current(control_group))
+ /* Push some zw_group memory into zswap (simple data, easy to compress) */
+ if (cg_enter_current(zw_group))
goto out;
- control_allocation = malloc(control_allocation_size);
- for (int i = 0; i < control_allocation_size; i += page_size)
- control_allocation[i] = 'a';
- if (cg_read_key_long(control_group, "memory.stat", "zswapped") < 1)
+ zw_allocation = malloc(allocation_size);
+ for (int i = 0; i < nr_pages; i++) {
+ off = (unsigned long)i * page_size;
+ memset(&zw_allocation[off], 0, page_size);
+ memset(&zw_allocation[off], 'a', page_size/4);
+ }
+ if (cg_read_key_long(zw_group, "memory.stat", "zswapped") < 1)
goto out;
- /* Allocate 10x memory.max to push wb_group memory into zswap and trigger wb */
- if (cg_run(wb_group, allocate_bytes, (void *)MB(10)))
+ /* Push wb_group memory into zswap with hard-to-compress data to trigger wb */
+ if (cg_enter_current(wb_group))
+ goto out;
+ wb_allocation = malloc(allocation_size);
+ if (!wb_allocation)
goto out;
+ for (int i = 0; i < nr_pages; i++) {
+ off = (unsigned long)i * page_size;
+ memset(&wb_allocation[off], 0, page_size);
+ getrandom(&wb_allocation[off], page_size/4, 0);
+ }
/* Verify that only zswapped memory from gwb_group has been written back */
- if (get_cg_wb_count(wb_group) > 0 && get_cg_wb_count(control_group) == 0)
+ if (get_cg_wb_count(wb_group) > 0 && get_cg_wb_count(zw_group) == 0)
ret = KSFT_PASS;
out:
cg_enter_current(root);
- if (control_group) {
- cg_destroy(control_group);
- free(control_group);
+ if (zw_group) {
+ cg_destroy(zw_group);
+ free(zw_group);
+ }
+ if (wb_group) {
+ cg_destroy(wb_group);
+ free(wb_group);
}
- cg_destroy(wb_group);
- free(wb_group);
- if (control_allocation)
- free(control_allocation);
+ if (zw_allocation)
+ free(zw_allocation);
+ if (wb_allocation)
+ free(wb_allocation);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v7 7/8] selftest/cgroup: fix zswap attempt_writeback() on 64K pagesize system
2026-04-24 4:00 [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Li Wang
` (5 preceding siblings ...)
2026-04-24 4:00 ` [PATCH v7 6/8] selftest/cgroup: fix zswap test_no_invasive_cgroup_shrink on large pagesize system Li Wang
@ 2026-04-24 4:00 ` Li Wang
2026-04-24 4:00 ` [PATCH v7 8/8] selftests/cgroup: test_zswap: wait for asynchronous writeback Li Wang
` (2 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Li Wang @ 2026-04-24 4:00 UTC (permalink / raw)
To: akpm, tj, longman, roman.gushchin, hannes, yosry, jiayuan.chen,
nphamcs, chengming.zhou, mkoutny, shuah
Cc: linux-mm, cgroups, linux-kselftest, linux-kernel, Michal Hocko,
Muchun Song, Shakeel Butt
In attempt_writeback(), a memsize of 4M only covers 64 pages on 64K
page size systems. When memory.reclaim is called, the kernel prefers
reclaiming clean file pages (binary, libc, linker, etc.) over swapping
anonymous pages. With only 64 pages of anonymous memory, the reclaim
target can be largely or entirely satisfied by dropping file pages,
resulting in very few or zero anonymous pages being pushed into zswap.
This causes zswap_usage to be extremely small or zero, making
zswap_usage/4 insufficient to create meaningful writeback pressure.
The test then fails because no writeback is triggered.
On 4K page size systems this is not an issue because 4M covers 1024
pages, and file pages are a small fraction of the reclaim target.
Fix this by:
- Always allocating 1024 pages regardless of page size. This ensures
enough anonymous pages to reliably populate zswap and trigger
writeback, while keeping the original 4M allocation on 4K systems.
- Setting zswap.max to zswap_usage/4 instead of zswap_usage/2 to
create stronger writeback pressure, ensuring reclaim reliably
triggers writeback even on large page size systems.
=== Error Log ===
# uname -rm
6.12.0-211.el10.ppc64le ppc64le
# getconf PAGESIZE
65536
# ./test_zswap
TAP version 13
1..7
ok 1 test_zswap_usage
ok 2 test_swapin_nozswap
ok 3 test_zswapin
not ok 4 test_zswap_writeback_enabled
...
Signed-off-by: Li Wang <li.wang@linux.dev>
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: Tejun Heo <tj@kernel.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: Yosry Ahmed <yosry@kernel.org>
Acked-by: Nhat Pham <nphamcs@gmail.com>
---
tools/testing/selftests/cgroup/test_zswap.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/cgroup/test_zswap.c b/tools/testing/selftests/cgroup/test_zswap.c
index 8f0478923bd..5fe0cffb557 100644
--- a/tools/testing/selftests/cgroup/test_zswap.c
+++ b/tools/testing/selftests/cgroup/test_zswap.c
@@ -268,14 +268,14 @@ static int test_zswapin(const char *root)
This will move it into zswap.
* 3. Save current zswap usage.
* 4. Move the memory allocated in step 1 back in from zswap.
- * 5. Set zswap.max to half the amount that was recorded in step 3.
+ * 5. Set zswap.max to 1/4 of the amount that was recorded in step 3.
* 6. Attempt to reclaim memory equal to the amount that was allocated,
this will either trigger writeback if it's enabled, or reclamation
will fail if writeback is disabled as there isn't enough zswap space.
*/
static int attempt_writeback(const char *cgroup, void *arg)
{
- size_t memsize = MB(4);
+ size_t memsize = page_size * 1024;
char buf[page_size];
long zswap_usage;
bool wb_enabled = *(bool *) arg;
@@ -313,12 +313,12 @@ static int attempt_writeback(const char *cgroup, void *arg)
}
}
- if (cg_write_numeric(cgroup, "memory.zswap.max", zswap_usage/2))
+ if (cg_write_numeric(cgroup, "memory.zswap.max", zswap_usage/4))
goto out;
/*
* If writeback is enabled, trying to reclaim memory now will trigger a
- * writeback as zswap.max is half of what was needed when reclaim ran the first time.
+ * writeback as zswap.max is 1/4 of what was needed when reclaim ran the first time.
* If writeback is disabled, memory reclaim will fail as zswap is limited and
* it can't writeback to swap.
*/
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v7 8/8] selftests/cgroup: test_zswap: wait for asynchronous writeback
2026-04-24 4:00 [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Li Wang
` (6 preceding siblings ...)
2026-04-24 4:00 ` [PATCH v7 7/8] selftest/cgroup: fix zswap attempt_writeback() on 64K " Li Wang
@ 2026-04-24 4:00 ` Li Wang
2026-04-24 10:06 ` [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Andrew Morton
2026-04-24 13:31 ` Andrew Morton
9 siblings, 0 replies; 13+ messages in thread
From: Li Wang @ 2026-04-24 4:00 UTC (permalink / raw)
To: akpm, tj, longman, roman.gushchin, hannes, yosry, jiayuan.chen,
nphamcs, chengming.zhou, mkoutny, shuah
Cc: linux-mm, cgroups, linux-kselftest, linux-kernel, Michal Hocko,
Muchun Song, Shakeel Butt, Yosry Ahmed
zswap writeback is asynchronous, but test_zswap.c checks writeback
counters immediately after reclaim/trigger paths. On some platforms
(e.g. ppc64le), this can race with background writeback and cause
spurious failures even when behavior is correct.
Add wait_for_writeback() to poll get_cg_wb_count() with a bounded
timeout, and use it in:
test_zswap_writeback_one() when writeback is expected
test_no_invasive_cgroup_shrink() for the wb_group check
This keeps the original before/after assertion style while making the
tests robust against writeback completion latency.
No test behavior change, selftest stability improvement only.
Signed-off-by: Li Wang <li.wang@linux.dev>
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: Tejun Heo <tj@kernel.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Yosry Ahmed <yosryahmed@google.com>
Acked-by: Nhat Pham <nphamcs@gmail.com>
---
tools/testing/selftests/cgroup/test_zswap.c | 28 +++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/cgroup/test_zswap.c b/tools/testing/selftests/cgroup/test_zswap.c
index 5fe0cffb557..49b36ee7916 100644
--- a/tools/testing/selftests/cgroup/test_zswap.c
+++ b/tools/testing/selftests/cgroup/test_zswap.c
@@ -120,6 +120,27 @@ static char *setup_test_group_1M(const char *root, const char *name)
return NULL;
}
+/*
+ * Writeback is asynchronous; poll until at least one writeback has
+ * been recorded for @cg, or until @timeout_ms has elapsed.
+ */
+static long wait_for_writeback(const char *cg, int timeout_ms)
+{
+ long elapsed, count;
+ for (elapsed = 0; elapsed < timeout_ms; elapsed += 100) {
+ count = get_cg_wb_count(cg);
+
+ if (count < 0)
+ return -1;
+ if (count > 0)
+ return count;
+
+ usleep(100000);
+ }
+
+ return 0;
+}
+
/*
* Sanity test to check that pages are written into zswap.
*/
@@ -345,7 +366,10 @@ static int test_zswap_writeback_one(const char *cgroup, bool wb)
return -1;
/* Verify that zswap writeback occurred only if writeback was enabled */
- zswpwb_after = get_cg_wb_count(cgroup);
+ if (wb)
+ zswpwb_after = wait_for_writeback(cgroup, 5000);
+ else
+ zswpwb_after = get_cg_wb_count(cgroup);
if (zswpwb_after < 0)
return -1;
@@ -476,7 +500,7 @@ static int test_no_invasive_cgroup_shrink(const char *root)
}
/* Verify that only zswapped memory from gwb_group has been written back */
- if (get_cg_wb_count(wb_group) > 0 && get_cg_wb_count(zw_group) == 0)
+ if (wait_for_writeback(wb_group, 5000) > 0 && get_cg_wb_count(zw_group) == 0)
ret = KSFT_PASS;
out:
cg_enter_current(root);
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v7 5/8] selftests/cgroup: replace hardcoded page size values in test_zswap
2026-04-24 4:00 ` [PATCH v7 5/8] selftests/cgroup: replace hardcoded page size values in test_zswap Li Wang
@ 2026-04-24 5:20 ` Jiayuan Chen
0 siblings, 0 replies; 13+ messages in thread
From: Jiayuan Chen @ 2026-04-24 5:20 UTC (permalink / raw)
To: Li Wang, akpm, tj, longman, roman.gushchin, hannes, yosry,
nphamcs, chengming.zhou, mkoutny, shuah
Cc: linux-mm, cgroups, linux-kselftest, linux-kernel, Michal Hocko,
Muchun Song, Shakeel Butt
On 4/24/26 12:00 PM, Li Wang wrote:
> test_zswap uses hardcoded values of 4095 and 4096 throughout as page
> stride and page size, which are only correct on systems with a 4K page
> size. On architectures with larger pages (e.g., 64K on arm64 or ppc64),
> these constants cause memory to be touched at sub-page granularity,
> leading to inefficient access patterns and incorrect page count
> calculations, which can cause test failures.
>
> Replace all hardcoded 4095 and 4096 values with a global pagesize
> variable initialized from sysconf(_SC_PAGESIZE) at startup, and remove
> the redundant local sysconf() calls scattered across individual
> functions. No functional change on 4K page size systems.
>
> Signed-off-by: Li Wang <li.wang@linux.dev>
> 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: Tejun Heo <tj@kernel.org>
> Cc: Roman Gushchin <roman.gushchin@linux.dev>
> Cc: Shakeel Butt <shakeel.butt@linux.dev>
> Acked-by: Yosry Ahmed <yosry@kernel.org>
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes
2026-04-24 4:00 [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Li Wang
` (7 preceding siblings ...)
2026-04-24 4:00 ` [PATCH v7 8/8] selftests/cgroup: test_zswap: wait for asynchronous writeback Li Wang
@ 2026-04-24 10:06 ` Andrew Morton
2026-04-24 11:14 ` Li Wang
2026-04-24 13:31 ` Andrew Morton
9 siblings, 1 reply; 13+ messages in thread
From: Andrew Morton @ 2026-04-24 10:06 UTC (permalink / raw)
To: Li Wang
Cc: tj, longman, roman.gushchin, hannes, yosry, jiayuan.chen, nphamcs,
chengming.zhou, mkoutny, shuah, linux-mm, cgroups,
linux-kselftest, linux-kernel
On Fri, 24 Apr 2026 12:00:51 +0800 Li Wang <li.wang@linux.dev> wrote:
> This patchset aims to fix various spurious failures and improve the overall
> robustness of the cgroup zswap selftests.
Great, thanks, I'll queue this in mm.git's mm-new branch. Next week
I'll move it into mm-unstable, where it will receive liunx-next
exposure.
> The primary motivation is to make the tests compatible with architectures
> that use non-4K page sizes (such as 64K on ppc64le and arm64). Currently,
> the tests rely heavily on hardcoded 4K page sizes and fixed memory limits.
Well that's an oops.
> On 64K page size systems, these hardcoded values lead to sub-page granularity
> accesses, incorrect page count calculations, and insufficient memory pressure
> to trigger zswap writeback, ultimately causing the tests to fail.
I assume you've been testing on arm64 or ppc?
> Additionally, this series addresses OOM kills occurring in test_swapin_nozswap
> by dynamically scaling memory limits, and prevents spurious test failures
> when zswap is built into the kernel but globally disabled.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes
2026-04-24 10:06 ` [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Andrew Morton
@ 2026-04-24 11:14 ` Li Wang
0 siblings, 0 replies; 13+ messages in thread
From: Li Wang @ 2026-04-24 11:14 UTC (permalink / raw)
To: Andrew Morton
Cc: tj, longman, roman.gushchin, hannes, yosry, jiayuan.chen, nphamcs,
chengming.zhou, mkoutny, shuah, linux-mm, cgroups,
linux-kselftest, linux-kernel
On Fri, Apr 24, 2026 at 03:06:05AM -0700, Andrew Morton wrote:
> On Fri, 24 Apr 2026 12:00:51 +0800 Li Wang <li.wang@linux.dev> wrote:
>
> > This patchset aims to fix various spurious failures and improve the overall
> > robustness of the cgroup zswap selftests.
>
> Great, thanks, I'll queue this in mm.git's mm-new branch. Next week
> I'll move it into mm-unstable, where it will receive liunx-next
> exposure.
>
> > The primary motivation is to make the tests compatible with architectures
> > that use non-4K page sizes (such as 64K on ppc64le and arm64). Currently,
> > the tests rely heavily on hardcoded 4K page sizes and fixed memory limits.
>
> Well that's an oops.
>
> > On 64K page size systems, these hardcoded values lead to sub-page granularity
> > accesses, incorrect page count calculations, and insufficient memory pressure
> > to trigger zswap writeback, ultimately causing the tests to fail.
>
> I assume you've been testing on arm64 or ppc?
Yes, before sending, I teseted the patchset on:
x86_64(4k), aarch64(4K, 64K), ppc64le(64K)
--
Regards,
Li Wang
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes
2026-04-24 4:00 [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Li Wang
` (8 preceding siblings ...)
2026-04-24 10:06 ` [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Andrew Morton
@ 2026-04-24 13:31 ` Andrew Morton
9 siblings, 0 replies; 13+ messages in thread
From: Andrew Morton @ 2026-04-24 13:31 UTC (permalink / raw)
To: Li Wang
Cc: tj, longman, roman.gushchin, hannes, yosry, jiayuan.chen, nphamcs,
chengming.zhou, mkoutny, shuah, linux-mm, cgroups,
linux-kselftest, linux-kernel
On Fri, 24 Apr 2026 12:00:51 +0800 Li Wang <li.wang@linux.dev> wrote:
> This patchset aims to fix various spurious failures and improve the overall
> robustness of the cgroup zswap selftests.
AI review:
https://sashiko.dev/#/patchset/20260424040059.12940-1-li.wang@linux.dev
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-04-24 13:31 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-24 4:00 [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Li Wang
2026-04-24 4:00 ` [PATCH v7 1/8] selftests/cgroup: skip test_zswap if zswap is globally disabled Li Wang
2026-04-24 4:00 ` [PATCH v7 2/8] selftests/cgroup: avoid OOM in test_swapin_nozswap Li Wang
2026-04-24 4:00 ` [PATCH v7 3/8] selftests/cgroup: use runtime page size for zswpin check Li Wang
2026-04-24 4:00 ` [PATCH v7 4/8] selftests/cgroup: rename PAGE_SIZE to BUF_SIZE in cgroup_util Li Wang
2026-04-24 4:00 ` [PATCH v7 5/8] selftests/cgroup: replace hardcoded page size values in test_zswap Li Wang
2026-04-24 5:20 ` Jiayuan Chen
2026-04-24 4:00 ` [PATCH v7 6/8] selftest/cgroup: fix zswap test_no_invasive_cgroup_shrink on large pagesize system Li Wang
2026-04-24 4:00 ` [PATCH v7 7/8] selftest/cgroup: fix zswap attempt_writeback() on 64K " Li Wang
2026-04-24 4:00 ` [PATCH v7 8/8] selftests/cgroup: test_zswap: wait for asynchronous writeback Li Wang
2026-04-24 10:06 ` [PATCH v7 0/8] selftests/cgroup: improve zswap tests robustness and support large page sizes Andrew Morton
2026-04-24 11:14 ` Li Wang
2026-04-24 13:31 ` Andrew Morton
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox