[LTP] [PATCH] [PATCH V2] memcg/memcontrol04: Fix race in pagecache allocation measurement

Pavithra pavrampu@linux.ibm.com
Mon May 25 17:33:52 CEST 2026


The test was failing with memory.current values much lower than expected:
   TFAIL: (A/B/C memory.current=6684672) ~= 34603008
   TFAIL: (A/B/D memory.current=5373952) ~= 17825792

Root cause:
Child processes allocating pagecache were exiting immediately after
allocation (via tst_reap_children()), causing the pagecache to be
freed before the test could measure memory.current values.

Fix:
Modified alloc_pagecache_in_child() to keep children alive during test:
- Added TEST_DONE checkpoint for child lifecycle coordination
- Parent waits for CHILD_IDLE checkpoint before proceeding
- Child signals CHILD_IDLE after allocation and fsync
- Child waits for TEST_DONE to keep memory allocated during test
- Modified cleanup_sub_groups() to wake waiting children before cleanup
- Changed alloc_anon_in_child() to use SAFE_WAITPID() for specific child
- Added num_children_spawned tracking for accurate cleanup

Signed-off-by: Sachin Sant <sachinp@linux.ibm.com>
Signed-off-by: Pavithra <pavrampu@linux.ibm.com>
---
v2:
  - Added num_children_spawned counter to track spawned children
  - Fixed cleanup_sub_groups() to wake correct number of children

Link to v2: https://lore.kernel.org/ltp/20260427171734.621893-1-pavrampu@linux.ibm.com/

v1:
  - Initial fix for child process lifecycle coordination
  - Added TEST_DONE and CHILD_IDLE checkpoint synchronization

Link to v1: https://lore.kernel.org/ltp/20260330050105.258630-1-pavrampu@linux.ibm.com/  
  
---
 .../kernel/controllers/memcg/memcontrol04.c   | 21 ++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/testcases/kernel/controllers/memcg/memcontrol04.c b/testcases/kernel/controllers/memcg/memcontrol04.c
index 715cc5bcd..15d8f891c 100644
--- a/testcases/kernel/controllers/memcg/memcontrol04.c
+++ b/testcases/kernel/controllers/memcg/memcontrol04.c
@@ -45,9 +45,11 @@
 static struct tst_cg_group *trunk_cg[3];
 static struct tst_cg_group *leaf_cg[4];
 static int fd = -1;
+static unsigned int num_children_spawned;
 
 enum checkpoints {
-	CHILD_IDLE
+	CHILD_IDLE,
+	TEST_DONE,
 };
 
 enum trunk_cg {
@@ -67,6 +69,12 @@ static void cleanup_sub_groups(void)
 {
 	size_t i;
 
+	if (num_children_spawned > 0) {
+		TST_CHECKPOINT_WAKE2(TEST_DONE, num_children_spawned);
+		tst_reap_children();
+		num_children_spawned = 0;
+	}
+
 	for (i = ARRAY_SIZE(leaf_cg); i > 0; i--) {
 		if (!leaf_cg[i - 1])
 			continue;
@@ -88,7 +96,7 @@ static void alloc_anon_in_child(const struct tst_cg_group *const cg,
 	const pid_t pid = SAFE_FORK();
 
 	if (pid) {
-		tst_reap_children();
+		SAFE_WAITPID(pid, NULL, 0);
 		return;
 	}
 
@@ -107,7 +115,8 @@ static void alloc_pagecache_in_child(const struct tst_cg_group *const cg,
 	const pid_t pid = SAFE_FORK();
 
 	if (pid) {
-		tst_reap_children();
+		num_children_spawned++;
+		TST_CHECKPOINT_WAIT(CHILD_IDLE);
 		return;
 	}
 
@@ -117,6 +126,11 @@ static void alloc_pagecache_in_child(const struct tst_cg_group *const cg,
 		getpid(), tst_cg_group_name(cg), size);
 	alloc_pagecache(fd, size);
 
+	SAFE_FSYNC(fd);
+
+	TST_CHECKPOINT_WAKE(CHILD_IDLE);
+	TST_CHECKPOINT_WAIT(TEST_DONE);
+
 	exit(0);
 }
 
@@ -125,6 +139,7 @@ static void test_memcg_low(void)
 	long c[4];
 	unsigned int i;
 
+	num_children_spawned = 0;
 	fd = SAFE_OPEN(TMPDIR"/tmpfile", O_RDWR | O_CREAT, 0600);
 	trunk_cg[A] = tst_cg_group_mk(tst_cg, "trunk_A");
 
-- 
2.54.0



More information about the ltp mailing list