[PATCH v7] mmapstress06: Convert to new API
Wei Gao via ltp <[email protected]>
| Newsgroups | gmane.linux.ltp |
|---|---|
| Message-ID | <[email protected]> |
Convert the mmapstress06 test case from the legacy LTP API to the new tst_test API. Refactor and redesign the test to be active instead of passive: - Replaced the passive sleep-based synchronization with an active cgroup constrained memory stress test compatible with both cgroups v1 and v2. - Dirties all pages of a 256MB shared anonymous mapping inside the child cgroup, forcing the kernel to swap out memory when hitting the 128MB limit. - Rate limits page dirtying by introducing a page-size independent 1ms sleep every 2MB (i.e. usleep(1000) when i % 2MB == 0) to allow the kernel's asynchronous swap writeback to stably reclaim pages and prevent MemCG OOM-kills on all architectures (e.g. standard 4KB or 64KB page size) while optimizing execution speed. - Added CONFIG_SWAP=y and CONFIG_MEMCG=y kernel configuration checks. - Utilized declarative .min_mem_avail and .min_swap_avail for framework-level resource validation. Suggested-by: Li Wang <[email protected]> Signed-off-by: Wei Gao <wegao-IBi9RG/[email protected]> --- v6->v7: - Change rate-limit sleep interval from 64KB to 2MB to optimize execution time. runtest/mm | 2 +- .../kernel/mem/mmapstress/mmapstress06.c | 186 +++++++++--------- 2 files changed, 97 insertions(+), 91 deletions(-) diff --git a/runtest/mm b/runtest/mm index 41d624ad8..7d75b65c8 100644 --- a/runtest/mm +++ b/runtest/mm @@ -41,7 +41,7 @@ mmapstress02 mmapstress02 mmapstress03 mmapstress03 mmapstress04 mmapstress04 mmapstress05 mmapstress05 -mmapstress06 mmapstress06 20 +mmapstress06 mmapstress06 mmapstress07 TMPFILE=`mktemp $TMPDIR/example.XXXXXXXXXXXX`; mmapstress07 $TMPFILE mmapstress08 mmapstress08 mmapstress09 mmapstress09 -p 20 -t 0.2 diff --git a/testcases/kernel/mem/mmapstress/mmapstress06.c b/testcases/kernel/mem/mmapstress/mmapstress06.c index 37b7edc84..4e6023399 100644 --- a/testcases/kernel/mem/mmapstress/mmapstress06.c +++ b/testcases/kernel/mem/mmapstress/mmapstress06.c @@ -1,116 +1,122 @@ -/* IBM Corporation */ -/* 01/02/2003 Port to LTP avenkat-r/[email protected] */ -/* 06/30/2001 Port to Linux nsharoff-r/[email protected] */ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2003 - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Copyright (c) International Business Machines Corp., 2003 + * Copyright (c) 2026 Linux Test Project + */ + +/*\ + * Test :manpage:`mmap(2)` with swap behavior. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. + * Mmap a large anonymous shared region and force it to be swapped out + * by setting memory limits using Cgroups and dirtying all pages. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * This test requires root privileges because configuring cgroup memory + * limits requires administrative access. */ -/* - * mfile_swap: - * Mmap a large (> ANON_GRAN_PAGES_MAX) shared, anonymous region before - * swapping to use the second half of the kernel primitive mfile_swap. - * However, this test does _NOT_ cause swapping to occur. Instead it should be - * run with waves or at the same time as a test which does cause swapping (i.e. - * vsswapin or vfork_swap) - */ -#define _KMEMUSER +#define _GNU_SOURCE #include <sys/types.h> #include <sys/mman.h> +#include <sys/wait.h> #include <unistd.h> #include <stdio.h> #include <errno.h> +#include <stdlib.h> +#include "tst_test.h" -/***** LTP Port *****/ -#include "test.h" -#define FAILED 0 -#define PASSED 1 +static struct tst_cg_group *cg_child; +static int page_size; +static size_t map_size; +static size_t mem_limit; +static pid_t child_pid = -1; -int local_flag = PASSED; -char *TCID = "mmapstress06"; //mfile_swap -FILE *temp; -int TST_TOTAL = 1; +static void run_test(void) +{ + cg_child = tst_cg_group_mk(tst_cg, "child"); -int anyfail(); -void ok_exit(); -/***** ** ** *****/ + /* Set memory limit to force swapping of the mapping */ + SAFE_CG_PRINTF(cg_child, "memory.max", "%lu", (unsigned long)mem_limit); -#define ANON_GRAN_PAGES_MAX (32U) + if (TST_CG_VER_IS_V1(cg_child, "memory")) + SAFE_CG_PRINT(cg_child, "memory.swap.max", "-1"); + else + SAFE_CG_PRINT(cg_child, "memory.swap.max", "max"); -extern time_t time(time_t *); -extern char *ctime(const time_t *); -extern int atoi(const char *); + child_pid = SAFE_FORK(); + if (!child_pid) { + char *mmapaddr; + unsigned long cg_swap_before = 0, cg_swap_after = 0; -#define NMFPTEPG (1024) -#define ERROR(M) (void)fprintf(stderr, "%s: errno = %d; " M "\n", \ - argv[0], errno); + /* Move child to the constrained cgroup */ + SAFE_CG_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); -int main(int argc, char *argv[]) -{ - caddr_t mmapaddr; - size_t pagesize = sysconf(_SC_PAGE_SIZE); - time_t t; - int sleep_time = 0; - - if (!argc) { - (void)fprintf(stderr, "argc == 0\n"); - anyfail(); - } - if (argc != 2 || !(sleep_time = atoi(argv[1]))) { - (void)fprintf(stderr, "usage: %s sleep_time\n", argv[0]); - anyfail(); - } - (void)time(&t); -// (void)printf("%s: Started %s", argv[0], ctime(&t)); LTP Port - if (sbrk(pagesize - ((ulong) sbrk(0) & (pagesize - 1))) == (char *)-1) { - ERROR("couldn't round up brk"); - anyfail(); - } - if ((mmapaddr = sbrk(0)) == (char *)-1) { - ERROR("couldn't find top of brk"); - anyfail(); - } - /* mmapaddr is now on a page boundary after the brk segment */ - if (mmap - (mmapaddr, (ANON_GRAN_PAGES_MAX * NMFPTEPG + 1) * pagesize, - PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, - 0) == (caddr_t) - 1) { - ERROR("large mmap failed"); - printf("for this test to run, it needs a mmap space of\n"); - printf("%d pages\n", (ANON_GRAN_PAGES_MAX * NMFPTEPG + 1)); - return 1; + SAFE_CG_SCANF(cg_child, "memory.swap.current", "%lu", &cg_swap_before); + + mmapaddr = SAFE_MMAP(NULL, map_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED, -1, 0); + + tst_res(TINFO, "Dirtying %zu bytes in child", map_size); + + for (size_t i = 0; i < map_size; i += page_size) { + mmapaddr[i] = 'a'; + if ((i % (2 * 1024 * 1024)) == 0) + usleep(1000); + } + + SAFE_CG_SCANF(cg_child, "memory.swap.current", "%lu", &cg_swap_after); + + if (cg_swap_after > cg_swap_before) { + tst_res(TPASS, "Cgroup swap usage increased from %lu MB to %lu MB", + cg_swap_before / TST_MB, cg_swap_after / TST_MB); + } else { + tst_res(TFAIL, "Cgroup swap usage did not increase (before: %lu B, after: %lu B)", + cg_swap_before, cg_swap_after); + } + + SAFE_MUNMAP(mmapaddr, map_size); + exit(0); } - (void)sleep(sleep_time); - (void)time(&t); -// (void)printf("%s: Finished %s", argv[0], ctime(&t)); LTP Port - ok_exit(); - tst_exit(); + + SAFE_WAITPID(child_pid, NULL, 0); + child_pid = -1; + + cg_child = tst_cg_group_rm(cg_child); } -/***** LTP Port *****/ -void ok_exit(void) +static void setup(void) { - tst_resm(TPASS, "Test passed"); - tst_exit(); + if (!SAFE_CG_HAS(tst_cg, "memory.swap.max")) + tst_brk(TCONF, "Cgroup swap controller is not enabled/supported"); + + page_size = getpagesize(); + + mem_limit = 128 * TST_MB; + map_size = 256 * TST_MB; } -int anyfail(void) +static void cleanup(void) { - tst_brkm(TFAIL, NULL, "Test failed"); + if (child_pid > 0) { + SAFE_KILL(child_pid, SIGKILL); + SAFE_WAITPID(child_pid, NULL, 0); + } + + if (cg_child) + cg_child = tst_cg_group_rm(cg_child); } -/***** ** ** *****/ +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .forks_child = 1, + .needs_root = 1, + .needs_cgroup_ctrls = (const char *const []){ "memory", NULL }, + .min_mem_avail = 256, + .min_swap_avail = 128, + .needs_kconfigs = (const char *[]) { + "CONFIG_SWAP=y", + "CONFIG_MEMCG=y", + NULL + }, +}; -- 2.54.0 -- Mailing list info: https://lists.linux.it/listinfo/ltp