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 @@ ...@@ -28,6 +28,15 @@
#define MiB (1024 * KiB) #define MiB (1024 * KiB)
#define FORK_EXEC_CHILD_PRG_NAME "ksm_fork_exec_child" #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 mem_fd;
static int ksm_fd; static int ksm_fd;
static int ksm_full_scans_fd; static int ksm_full_scans_fd;
...@@ -146,33 +155,34 @@ static int ksm_unmerge(void) ...@@ -146,33 +155,34 @@ static int ksm_unmerge(void)
return 0; return 0;
} }
static char *mmap_and_merge_range(char val, unsigned long size, int prot, static char *__mmap_and_merge_range(char val, unsigned long size, int prot,
bool use_prctl) enum ksm_merge_mode mode)
{ {
char *map; char *map;
char *err_map = MAP_MERGE_FAIL;
int ret; int ret;
/* Stabilize accounting by disabling KSM completely. */ /* Stabilize accounting by disabling KSM completely. */
if (ksm_unmerge()) { if (ksm_unmerge()) {
ksft_test_result_fail("Disabling (unmerging) KSM failed\n"); ksft_print_msg("Disabling (unmerging) KSM failed\n");
return MAP_FAILED; return err_map;
} }
if (get_my_merging_pages() > 0) { if (get_my_merging_pages() > 0) {
ksft_test_result_fail("Still pages merged\n"); ksft_print_msg("Still pages merged\n");
return MAP_FAILED; return err_map;
} }
map = mmap(NULL, size, PROT_READ|PROT_WRITE, map = mmap(NULL, size, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANON, -1, 0); MAP_PRIVATE|MAP_ANON, -1, 0);
if (map == MAP_FAILED) { if (map == MAP_FAILED) {
ksft_test_result_fail("mmap() failed\n"); ksft_print_msg("mmap() failed\n");
return MAP_FAILED; return err_map;
} }
/* Don't use THP. Ignore if THP are not around on a kernel. */ /* Don't use THP. Ignore if THP are not around on a kernel. */
if (madvise(map, size, MADV_NOHUGEPAGE) && errno != EINVAL) { 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; goto unmap;
} }
...@@ -180,27 +190,36 @@ static char *mmap_and_merge_range(char val, unsigned long size, int prot, ...@@ -180,27 +190,36 @@ static char *mmap_and_merge_range(char val, unsigned long size, int prot,
memset(map, val, size); memset(map, val, size);
if (mprotect(map, size, prot)) { 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; goto unmap;
} }
if (use_prctl) { switch (mode) {
case KSM_MERGE_PRCTL:
ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0); ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0);
if (ret < 0 && errno == EINVAL) { 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; goto unmap;
} else if (ret) { } 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; goto unmap;
} }
} else if (madvise(map, size, MADV_MERGEABLE)) { break;
ksft_test_result_fail("MADV_MERGEABLE failed\n"); case KSM_MERGE_MADVISE:
goto unmap; 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. */ /* Run KSM to trigger merging and wait. */
if (ksm_merge()) { if (ksm_merge()) {
ksft_test_result_fail("Running KSM failed\n"); ksft_print_msg("Running KSM failed\n");
goto unmap; goto unmap;
} }
...@@ -209,14 +228,31 @@ static char *mmap_and_merge_range(char val, unsigned long size, int prot, ...@@ -209,14 +228,31 @@ static char *mmap_and_merge_range(char val, unsigned long size, int prot,
* accounted differently (depending on kernel support). * accounted differently (depending on kernel support).
*/ */
if (val && !get_my_merging_pages()) { 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; goto unmap;
} }
return map; return map;
unmap: unmap:
munmap(map, size); 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) static void test_unmerge(void)
...@@ -226,7 +262,7 @@ static void test_unmerge(void) ...@@ -226,7 +262,7 @@ static void test_unmerge(void)
ksft_print_msg("[RUN] %s\n", __func__); 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) if (map == MAP_FAILED)
return; return;
...@@ -264,7 +300,7 @@ static void test_unmerge_zero_pages(void) ...@@ -264,7 +300,7 @@ static void test_unmerge_zero_pages(void)
} }
/* Let KSM deduplicate zero pages. */ /* 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) if (map == MAP_FAILED)
return; return;
...@@ -312,7 +348,7 @@ static void test_unmerge_discarded(void) ...@@ -312,7 +348,7 @@ static void test_unmerge_discarded(void)
ksft_print_msg("[RUN] %s\n", __func__); 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) if (map == MAP_FAILED)
return; return;
...@@ -344,7 +380,7 @@ static void test_unmerge_uffd_wp(void) ...@@ -344,7 +380,7 @@ static void test_unmerge_uffd_wp(void)
ksft_print_msg("[RUN] %s\n", __func__); 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) if (map == MAP_FAILED)
return; return;
...@@ -545,7 +581,7 @@ static void test_prctl_unmerge(void) ...@@ -545,7 +581,7 @@ static void test_prctl_unmerge(void)
ksft_print_msg("[RUN] %s\n", __func__); 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) if (map == MAP_FAILED)
return; return;
...@@ -568,7 +604,7 @@ static void test_prot_none(void) ...@@ -568,7 +604,7 @@ static void test_prot_none(void)
ksft_print_msg("[RUN] %s\n", __func__); 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) if (map == MAP_FAILED)
goto unmap; 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