* [LTP] [PATCH] mmap22: Improve MAP_DROPPABLE test stability using mincore()
@ 2025-09-17 7:57 Li Wang via ltp
2025-09-23 11:07 ` Petr Vorel
0 siblings, 1 reply; 3+ messages in thread
From: Li Wang via ltp @ 2025-09-17 7:57 UTC (permalink / raw)
To: ltp
The current mmap22 test validates MAP_DROPPABLE by writing to the
allocated memory and checking for zero-filled pages under memory
pressure. However, this approach is unreliable because:
- Child process memory pressure (malloc + single writes) may not
reliably trigger cgroup memory reclaim.
- Checking memory content (alloc[i] == 0) is insufficient to
confirm kernel reclamation, as pages may remain resident but not
overwritten.
- Race conditions during child cleanup could leave residual cgroup
processes.
Error logs:
command: mmap22
tst_tmpdir.c:316: TINFO: Using /tmp/LTP_mmaxrtyKb as tmpdir (xfs filesystem)
tst_test.c:1953: TINFO: LTP version: 20250530
tst_kconfig.c:88: TINFO: Parsing kernel config '/lib/modules/6.12.0-130.1445_2041086229.el10.x86_64+rt/build/.config'
tst_test.c:1774: TINFO: Overall timeout per run is 0h 05m 54s
tst_test.c:1837: TINFO: Killed the leftover descendant processes
tst_test.c:1846: TINFO: If you are running on slow machine, try exporting LTP_TIMEOUT_MUL > 1
tst_test.c:1848: TBROK: Test killed! (timeout?)
tst_cgroup.c:1043: TBROK: unlinkat(5</sys/fs/cgroup/ltp>, 'test-92902', AT_REMOVEDIR): EBUSY (16)
...
This patch improves the test in the following ways:
* Use mincore() to precisely detect if MAP_DROPPABLE pages have
been reclaimed by the kernel.
* Replace the old child loop with a stronger memory pressure loop
(malloc + memset), ensuring cgroup limits are hit quickly.
* Use SAFE_KILL + SAFE_WAITPID for robust child cleanup.
* Extend runtime and add short sleeps to reduce busy looping and
stabilize test results.
* Record page size during setup for consistent use across functions.
As a result, the test becomes more stable, deterministic, and easier
to reproduce under different kernels and configurations.
Signed-off-by: Li Wang <liwang@redhat.com>
---
testcases/kernel/syscalls/mmap/mmap22.c | 78 ++++++++++++++++---------
1 file changed, 52 insertions(+), 26 deletions(-)
diff --git a/testcases/kernel/syscalls/mmap/mmap22.c b/testcases/kernel/syscalls/mmap/mmap22.c
index 1507fdfa7..b9db8e1b6 100644
--- a/testcases/kernel/syscalls/mmap/mmap22.c
+++ b/testcases/kernel/syscalls/mmap/mmap22.c
@@ -9,12 +9,19 @@
* Test mmap(2) with MAP_DROPPABLE flag.
*
* Test base on kernel selftests/mm/droppable.c
+ *
+ * Ensure that memory allocated with MAP_DROPPABLE can be reclaimed
+ * under memory pressure within a cgroup.
*/
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
#include "tst_test.h"
#include "lapi/mmap.h"
@@ -22,13 +29,24 @@
#define ALLOC_SIZE (128 * TST_MB)
static struct tst_cg_group *cg_child;
+static pid_t child;
+static int page_size;
+
+static void stress_child(void)
+{
+ for (;;) {
+ char *buf = malloc(page_size);
+ if (!buf)
+ exit(1);
+ memset(buf, 'B', page_size);
+ }
+}
static void test_mmap(void)
{
- size_t alloc_size = ALLOC_SIZE;
- size_t page_size = getpagesize();
char *alloc;
- pid_t child;
+ unsigned char *vec;
+ size_t npages = ALLOC_SIZE / page_size;
cg_child = tst_cg_group_mk(tst_cg, "child");
SAFE_CG_PRINTF(tst_cg, "memory.max", "%d", MEM_LIMIT);
@@ -38,38 +56,45 @@ static void test_mmap(void)
SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%d", MEM_LIMIT);
SAFE_CG_PRINTF(cg_child, "cgroup.procs", "%d", getpid());
- alloc = SAFE_MMAP(0, alloc_size, PROT_READ | PROT_WRITE,
+ alloc = SAFE_MMAP(0, ALLOC_SIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_DROPPABLE, -1, 0);
- memset(alloc, 'A', alloc_size);
- for (size_t i = 0; i < alloc_size; i += page_size) {
- if (alloc[i] != 'A')
- tst_res(TFAIL, "memset failed");
- }
+ memset(alloc, 'A', ALLOC_SIZE);
+
+ vec = SAFE_MALLOC(npages);
child = SAFE_FORK();
- if (!child) {
- for (;;)
- *(char *)malloc(page_size) = 'B';
- }
+ if (!child)
+ stress_child();
- while (1) {
- for (size_t i = 0; i < alloc_size; i += page_size) {
- if (!tst_remaining_runtime()) {
- tst_res(TFAIL, "MAP_DROPPABLE did not drop memory within the timeout period.");
- goto kill_child;
- }
- if (!alloc[i]) {
- tst_res(TPASS, "MAP_DROPPABLE test pass.");
- goto kill_child;
+ for (;;) {
+ if (!tst_remaining_runtime()) {
+ tst_res(TFAIL, "MAP_DROPPABLE did not drop pages within timeout");
+ goto cleanup;
+ }
+
+ if (mincore(alloc, ALLOC_SIZE, vec) == -1)
+ tst_brk(TBROK | TERRNO, "mincore failed");
+
+ for (size_t i = 0; i < npages; i++) {
+ if (!(vec[i] & 1)) {
+ tst_res(TPASS, "MAP_DROPPABLE page reclaimed by kernel");
+ goto cleanup;
}
}
+
+ usleep(100000);
}
-kill_child:
- SAFE_KILL(child, SIGKILL);
- SAFE_WAITPID(child, NULL, 0);
- SAFE_MUNMAP(alloc, alloc_size);
+cleanup:
+ if (child > 0) {
+ SAFE_KILL(child, SIGKILL);
+ SAFE_WAITPID(child, NULL, 0);
+ }
+ SAFE_MUNMAP(alloc, ALLOC_SIZE);
+ free(vec);
+ SAFE_CG_PRINTF(tst_cg_drain, "cgroup.procs", "%d", getpid());
+ cg_child = tst_cg_group_rm(cg_child);
}
static void setup(void)
@@ -84,6 +109,7 @@ static void setup(void)
tst_brk(TBROK | TERRNO, "mmap() MAP_DROPPABLE failed");
SAFE_MUNMAP(addr, 1);
+ page_size = getpagesize();
}
static void cleanup(void)
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [LTP] [PATCH] mmap22: Improve MAP_DROPPABLE test stability using mincore()
2025-09-17 7:57 [LTP] [PATCH] mmap22: Improve MAP_DROPPABLE test stability using mincore() Li Wang via ltp
@ 2025-09-23 11:07 ` Petr Vorel
2025-09-24 0:43 ` Li Wang via ltp
0 siblings, 1 reply; 3+ messages in thread
From: Petr Vorel @ 2025-09-23 11:07 UTC (permalink / raw)
To: Li Wang; +Cc: ltp
Hi Li,
> The current mmap22 test validates MAP_DROPPABLE by writing to the
> allocated memory and checking for zero-filled pages under memory
> pressure. However, this approach is unreliable because:
> - Child process memory pressure (malloc + single writes) may not
> reliably trigger cgroup memory reclaim.
> - Checking memory content (alloc[i] == 0) is insufficient to
> confirm kernel reclamation, as pages may remain resident but not
> overwritten.
> - Race conditions during child cleanup could leave residual cgroup
> processes.
Thanks for the investigation.
> Error logs:
> command: mmap22
> tst_tmpdir.c:316: TINFO: Using /tmp/LTP_mmaxrtyKb as tmpdir (xfs filesystem)
> tst_test.c:1953: TINFO: LTP version: 20250530
> tst_kconfig.c:88: TINFO: Parsing kernel config '/lib/modules/6.12.0-130.1445_2041086229.el10.x86_64+rt/build/.config'
> tst_test.c:1774: TINFO: Overall timeout per run is 0h 05m 54s
> tst_test.c:1837: TINFO: Killed the leftover descendant processes
> tst_test.c:1846: TINFO: If you are running on slow machine, try exporting LTP_TIMEOUT_MUL > 1
> tst_test.c:1848: TBROK: Test killed! (timeout?)
> tst_cgroup.c:1043: TBROK: unlinkat(5</sys/fs/cgroup/ltp>, 'test-92902', AT_REMOVEDIR): EBUSY (16)
> ...
> This patch improves the test in the following ways:
> * Use mincore() to precisely detect if MAP_DROPPABLE pages have
> been reclaimed by the kernel.
> * Replace the old child loop with a stronger memory pressure loop
> (malloc + memset), ensuring cgroup limits are hit quickly.
> * Use SAFE_KILL + SAFE_WAITPID for robust child cleanup.
nit: SAFE_KILL + SAFE_WAITPID were used before, the change you did is to check
with 'if (child > 0)' if it's meaningful to attempt to kill child.
> * Extend runtime and add short sleeps to reduce busy looping and
> stabilize test results.
> * Record page size during setup for consistent use across functions.
> As a result, the test becomes more stable, deterministic, and easier
> to reproduce under different kernels and configurations.
+1
...
> +static void stress_child(void)
> +{
> + for (;;) {
> + char *buf = malloc(page_size);
nit: Please insert a blank line here to keep checkpatch.pl quiet.
mmap22.c:39: WARNING: Missing a blank line after declarations
> + if (!buf)
> + exit(1);
> + memset(buf, 'B', page_size);
> + }
> +}
...
> + for (;;) {
> + if (!tst_remaining_runtime()) {
> + tst_res(TFAIL, "MAP_DROPPABLE did not drop pages within timeout");
> + goto cleanup;
> + }
> +
> + if (mincore(alloc, ALLOC_SIZE, vec) == -1)
> + tst_brk(TBROK | TERRNO, "mincore failed");
NOTE: we have SAFE_MINCORE() (can be fixed during merge).
The rest LGTM.
Reviewed-by: Petr Vorel <pvorel@suse.cz>
Kind regards,
Petr
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [LTP] [PATCH] mmap22: Improve MAP_DROPPABLE test stability using mincore()
2025-09-23 11:07 ` Petr Vorel
@ 2025-09-24 0:43 ` Li Wang via ltp
0 siblings, 0 replies; 3+ messages in thread
From: Li Wang via ltp @ 2025-09-24 0:43 UTC (permalink / raw)
To: Petr Vorel; +Cc: ltp
Merged as you suggested, thanks!
--
Regards,
Li Wang
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-09-24 0:43 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-17 7:57 [LTP] [PATCH] mmap22: Improve MAP_DROPPABLE test stability using mincore() Li Wang via ltp
2025-09-23 11:07 ` Petr Vorel
2025-09-24 0:43 ` Li Wang via ltp
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.