Commit 7abaacb8 authored by Jinjiang Tu's avatar Jinjiang Tu Committed by Andrew Morton

selftest/mm: ksm_functional_tests: refactor mmap_and_merge_range()

In order to extend test_prctl_fork() and test_prctl_fork_exec() to make
sure that deduplication really happens, mmap_and_merge_range() needs to be
refactored.

Firstly, mmap_and_merge_range() will be called with no need to call enable
KSM by madvise or prctl.  So, switch the 'bool use_prctl' parameter to
enum ksm_merge_mode.

Secondly, mmap_and_merge_range() will be called in child process in the
two testcases, it isn't appropriate to call ksft_test_result_{fail, skip},
because the global variables ksft_{fail, skip} aren't consistent with the
parent process.  Thus, convert calls of ksft_test_result_{fail, skip} to
ksft_print_msg(), return differrent error according to the two cases, and
rename mmap_and_merge_range() to __mmap_and_merge_range().  For existing
callers, introduce new mmap_and_merge_range() to handle different return
values of __mmap_and_merge_range().

Link: https://lkml.kernel.org/r/20240328111010.1502191-3-tujinjiang@huawei.comSigned-off-by: default avatarJinjiang Tu <tujinjiang@huawei.com>
Suggested-by: default avatarDavid Hildenbrand <david@redhat.com>
Reviewed-by: default avatarDavid Hildenbrand <david@redhat.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
Cc: Nanyong Sun <sunnanyong@huawei.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Stefan Roesch <shr@devkernel.io>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 3a9e567c
......@@ -28,6 +28,15 @@
#define MiB (1024 * KiB)
#define FORK_EXEC_CHILD_PRG_NAME "ksm_fork_exec_child"
#define MAP_MERGE_FAIL ((void *)-1)
#define MAP_MERGE_SKIP ((void *)-2)
enum ksm_merge_mode {
KSM_MERGE_PRCTL,
KSM_MERGE_MADVISE,
KSM_MERGE_NONE, /* PRCTL already set */
};
static int mem_fd;
static int ksm_fd;
static int ksm_full_scans_fd;
......@@ -146,33 +155,34 @@ static int ksm_unmerge(void)
return 0;
}
static char *mmap_and_merge_range(char val, unsigned long size, int prot,
bool use_prctl)
static char *__mmap_and_merge_range(char val, unsigned long size, int prot,
enum ksm_merge_mode mode)
{
char *map;
char *err_map = MAP_MERGE_FAIL;
int ret;
/* Stabilize accounting by disabling KSM completely. */
if (ksm_unmerge()) {
ksft_test_result_fail("Disabling (unmerging) KSM failed\n");
return MAP_FAILED;
ksft_print_msg("Disabling (unmerging) KSM failed\n");
return err_map;
}
if (get_my_merging_pages() > 0) {
ksft_test_result_fail("Still pages merged\n");
return MAP_FAILED;
ksft_print_msg("Still pages merged\n");
return err_map;
}
map = mmap(NULL, size, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANON, -1, 0);
if (map == MAP_FAILED) {
ksft_test_result_fail("mmap() failed\n");
return MAP_FAILED;
ksft_print_msg("mmap() failed\n");
return err_map;
}
/* Don't use THP. Ignore if THP are not around on a kernel. */
if (madvise(map, size, MADV_NOHUGEPAGE) && errno != EINVAL) {
ksft_test_result_fail("MADV_NOHUGEPAGE failed\n");
ksft_print_msg("MADV_NOHUGEPAGE failed\n");
goto unmap;
}
......@@ -180,27 +190,36 @@ static char *mmap_and_merge_range(char val, unsigned long size, int prot,
memset(map, val, size);
if (mprotect(map, size, prot)) {
ksft_test_result_skip("mprotect() failed\n");
ksft_print_msg("mprotect() failed\n");
err_map = MAP_MERGE_SKIP;
goto unmap;
}
if (use_prctl) {
switch (mode) {
case KSM_MERGE_PRCTL:
ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0);
if (ret < 0 && errno == EINVAL) {
ksft_test_result_skip("PR_SET_MEMORY_MERGE not supported\n");
ksft_print_msg("PR_SET_MEMORY_MERGE not supported\n");
err_map = MAP_MERGE_SKIP;
goto unmap;
} else if (ret) {
ksft_test_result_fail("PR_SET_MEMORY_MERGE=1 failed\n");
ksft_print_msg("PR_SET_MEMORY_MERGE=1 failed\n");
goto unmap;
}
} else if (madvise(map, size, MADV_MERGEABLE)) {
ksft_test_result_fail("MADV_MERGEABLE failed\n");
goto unmap;
break;
case KSM_MERGE_MADVISE:
if (madvise(map, size, MADV_MERGEABLE)) {
ksft_print_msg("MADV_MERGEABLE failed\n");
goto unmap;
}
break;
case KSM_MERGE_NONE:
break;
}
/* Run KSM to trigger merging and wait. */
if (ksm_merge()) {
ksft_test_result_fail("Running KSM failed\n");
ksft_print_msg("Running KSM failed\n");
goto unmap;
}
......@@ -209,14 +228,31 @@ static char *mmap_and_merge_range(char val, unsigned long size, int prot,
* accounted differently (depending on kernel support).
*/
if (val && !get_my_merging_pages()) {
ksft_test_result_fail("No pages got merged\n");
ksft_print_msg("No pages got merged\n");
goto unmap;
}
return map;
unmap:
munmap(map, size);
return MAP_FAILED;
return err_map;
}
static char *mmap_and_merge_range(char val, unsigned long size, int prot,
enum ksm_merge_mode mode)
{
char *map;
char *ret = MAP_FAILED;
map = __mmap_and_merge_range(val, size, prot, mode);
if (map == MAP_MERGE_FAIL)
ksft_test_result_fail("Merging memory failed");
else if (map == MAP_MERGE_SKIP)
ksft_test_result_skip("Merging memory skipped");
else
ret = map;
return ret;
}
static void test_unmerge(void)
......@@ -226,7 +262,7 @@ static void test_unmerge(void)
ksft_print_msg("[RUN] %s\n", __func__);
map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, false);
map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_MADVISE);
if (map == MAP_FAILED)
return;
......@@ -264,7 +300,7 @@ static void test_unmerge_zero_pages(void)
}
/* Let KSM deduplicate zero pages. */
map = mmap_and_merge_range(0x00, size, PROT_READ | PROT_WRITE, false);
map = mmap_and_merge_range(0x00, size, PROT_READ | PROT_WRITE, KSM_MERGE_MADVISE);
if (map == MAP_FAILED)
return;
......@@ -312,7 +348,7 @@ static void test_unmerge_discarded(void)
ksft_print_msg("[RUN] %s\n", __func__);
map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, false);
map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_MADVISE);
if (map == MAP_FAILED)
return;
......@@ -344,7 +380,7 @@ static void test_unmerge_uffd_wp(void)
ksft_print_msg("[RUN] %s\n", __func__);
map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, false);
map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_MADVISE);
if (map == MAP_FAILED)
return;
......@@ -545,7 +581,7 @@ static void test_prctl_unmerge(void)
ksft_print_msg("[RUN] %s\n", __func__);
map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, true);
map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_PRCTL);
if (map == MAP_FAILED)
return;
......@@ -568,7 +604,7 @@ static void test_prot_none(void)
ksft_print_msg("[RUN] %s\n", __func__);
map = mmap_and_merge_range(0x11, size, PROT_NONE, false);
map = mmap_and_merge_range(0x11, size, PROT_NONE, KSM_MERGE_MADVISE);
if (map == MAP_FAILED)
goto unmap;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment