[LTP] [PATCH v2] madvise09: Scale cgroup memory/swap limits dynamically with page size

Wei Gao wegao@suse.com
Thu Jul 23 11:46:21 CEST 2026


On systems with 64KB page size (such as ppc64le), the mapped footprint
of PAGES (128) is 128 * 64KB = 8MB. Since the cgroup MEM_LIMIT was
hardcoded to 8MB, there was zero headroom left for the parent's process
overhead, resulting in OOM when trying to fork the memory pressure
process.

This caused the test to enter an infinite "Both children killed,
retrying..." loop.

Fix this by scaling mem_limit and swap_limit dynamically based on the
system page size at runtime, and update the swap pre-check and doc
comments to match.

Signed-off-by: Wei Gao <wegao@suse.com>
---
Changes v1 -> v2:
- Update doc comment to reflect page-size based limit calculation.
- Guard tst_available_swap() check with swap_accounting_enabled to avoid unnecessary TCONF when swap accounting is off.

 testcases/kernel/syscalls/madvise/madvise09.c | 30 ++++++++++++-------
 1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/testcases/kernel/syscalls/madvise/madvise09.c b/testcases/kernel/syscalls/madvise/madvise09.c
index 5453f9411..620805370 100644
--- a/testcases/kernel/syscalls/madvise/madvise09.c
+++ b/testcases/kernel/syscalls/madvise/madvise09.c
@@ -17,11 +17,11 @@
  * o Write to some of the madvised pages again, these must not be freed
  *
  * o Set memory limits
- *   - memory.max = 8MB
- *   - memory.swap.max = 16MB
+ *   - memory.max = 16 * PAGES * page_size (8MB on 4KB page size)
+ *   - memory.swap.max = 2 * memory.max (16MB on 4KB page size)
  *
  *   The reason for doubling the memory.max is to have safe margin
- *   for forking the memory hungy child etc. And the reason to setting
+ *   for forking the memory hungry child etc. And the reason to setting
  *   memory.swap.max to twice of that is to give the system chance
  *   to try to free some memory before cgroup OOM kicks in and kills
  *   the memory hungry child.
@@ -54,8 +54,10 @@ static int swap_accounting_enabled;
 #define TOUCHED_PAGE1 0
 #define TOUCHED_PAGE2 10
 
-#define MEM_LIMIT (8 * 1024 * 1024)
-#define SWAP_LIMIT (2 * MEM_LIMIT)
+#define BASE_SWAP_LIMIT (16 * 1024 * 1024)
+
+static long long mem_limit;
+static long long swap_limit;
 
 static void memory_pressure_child(void)
 {
@@ -176,12 +178,12 @@ static void child(void)
 	ptr[TOUCHED_PAGE1 * page_size] = 'b';
 	ptr[TOUCHED_PAGE2 * page_size] = 'b';
 
-	SAFE_CG_PRINTF(tst_cg, "memory.max", "%d", MEM_LIMIT);
-	tst_res(TINFO, "Setting memory.max to %d bytes", MEM_LIMIT);
+	SAFE_CG_PRINTF(tst_cg, "memory.max", "%lld", mem_limit);
+	tst_res(TINFO, "Setting memory.max to %lld bytes", mem_limit);
 
 	if (swap_accounting_enabled) {
-		SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%d", SWAP_LIMIT);
-		tst_res(TINFO, "Setting memory.swap.max to %d bytes", SWAP_LIMIT);
+		SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%lld", swap_limit);
+		tst_res(TINFO, "Setting memory.swap.max to %lld bytes", swap_limit);
 	} else {
 		tst_res(TINFO, "memory.swap.max is unavailable, running without SWAP_LIMIT");
 	}
@@ -284,6 +286,14 @@ static void setup(void)
 		tst_res(TINFO, "Swap accounting is disabled");
 
 	page_size = getpagesize();
+
+	mem_limit = 16 * PAGES * page_size;
+	swap_limit = 2 * mem_limit;
+
+	if (swap_accounting_enabled && (tst_available_swap() < swap_limit / 1024)) {
+		tst_brk(TCONF, "System needs at least %lldMB free swap to run this test",
+			swap_limit / TST_MB);
+	}
 }
 
 static struct tst_test test = {
@@ -291,6 +301,6 @@ static struct tst_test test = {
 	.test_all = run,
 	.needs_root = 1,
 	.forks_child = 1,
-	.min_swap_avail = SWAP_LIMIT / TST_MB,
+	.min_swap_avail = BASE_SWAP_LIMIT / TST_MB,
 	.needs_cgroup_ctrls = (const char *const []){ "memory", NULL },
 };
-- 
2.54.0



More information about the ltp mailing list