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

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.com


Signed-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
Loading
Loading
Loading
Loading
+61 −25
Original line number Diff line number Diff line
@@ -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");
		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;