Add a new selftest to verify whether the `ksm_merging_pages` counter in `mm_struct` is inherited by a child process after fork. This helps ensure correctness of KSM accounting across process creation. Signed-off-by: Donet Tom --- .../selftests/mm/ksm_functional_tests.c | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/mm/ksm_functional_tests.c b/tools/testing/selftests/mm/ksm_functional_tests.c index 712f43c87736..d971394c9567 100644 --- a/tools/testing/selftests/mm/ksm_functional_tests.c +++ b/tools/testing/selftests/mm/ksm_functional_tests.c @@ -602,6 +602,45 @@ static void test_prot_none(void) munmap(map, size); } +static void test_fork_ksm_merging_page(void) +{ + const unsigned int size = 2 * MiB; + char *map; + pid_t child_pid; + int status; + + ksft_print_msg("[RUN] %s\n", __func__); + + map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_MADVISE); + if (map == MAP_FAILED) + return; + + child_pid = fork(); + if (!child_pid) { + int mpages; + + init_global_file_handles(); + mpages = ksm_get_self_merging_pages(); + if (mpages > 0) + ksft_test_result_fail("ksm_merging_page in child: %d\n", mpages); + + exit(0); + } else if (child_pid < 0) { + ksft_test_result_fail("fork() failed\n"); + return; + } + + if (waitpid(child_pid, &status, 0) < 0) { + ksft_test_result_fail("waitpid() failed\n"); + return; + } + + ksft_test_result_pass("ksm_merging_pages is not inherited after fork\n"); + + ksm_stop(); + munmap(map, size); +} + static void init_global_file_handles(void) { mem_fd = open("/proc/self/mem", O_RDWR); @@ -620,7 +659,7 @@ static void init_global_file_handles(void) int main(int argc, char **argv) { - unsigned int tests = 8; + unsigned int tests = 9; int err; if (argc > 1 && !strcmp(argv[1], FORK_EXEC_CHILD_PRG_NAME)) { @@ -652,6 +691,7 @@ int main(int argc, char **argv) test_prctl_fork(); test_prctl_fork_exec(); test_prctl_unmerge(); + test_fork_ksm_merging_page(); err = ksft_get_fail_cnt(); if (err) -- 2.51.0