public inbox for linux-mm@kvack.org
 help / color / mirror / Atom feed
* ksm: add mremap selftests for ksm_rmap_walk
@ 2026-04-07  6:08 xu.xin16
  2026-04-07  9:43 ` Lorenzo Stoakes (Oracle)
  0 siblings, 1 reply; 2+ messages in thread
From: xu.xin16 @ 2026-04-07  6:08 UTC (permalink / raw)
  To: hughd, akpm, david; +Cc: michel, ljs, chengming.zhou, linux-kernel, linux-mm

From: xu xin <xu.xin16@zte.com.cn>

The existing tools/testing/selftests/mm/rmap.c has already one testcase
for ksm_rmap_walk in TEST_F(migrate, ksm), which takes use of migration
of page from one NUMA node to another NUMA node. However, it just lacks
the senario of mremapped VMAs.

Before migrating, we add the calling of mremap() to address mapped with KSM
pages, which is specailly to test a optimization which is introduced by this
patch ("ksm: Optimize rmap_walk_ksm by passing a suitable address range")
https://lore.kernel.org/all/20260212193045556CbzCX8p9gDu73tQ2nvHEI@zte.com.cn/

Result:
TAP version 13
1..5
ok 1 migrate.anon
ok 2 migrate.shm
ok 3 migrate.file # SKIP Failed in worker
ok 4 migrate.ksm
ok 5 migrate.ksm_and_mremap

Signed-off-by: xu xin <xu.xin16@zte.com.cn>
---
 tools/testing/selftests/mm/rmap.c    | 69 ++++++++++++++++++++++++++++
 tools/testing/selftests/mm/vm_util.c | 38 +++++++++++++++
 tools/testing/selftests/mm/vm_util.h |  2 +
 3 files changed, 109 insertions(+)

diff --git a/tools/testing/selftests/mm/rmap.c b/tools/testing/selftests/mm/rmap.c
index 53f2058b0ef2..65470def2bf1 100644
--- a/tools/testing/selftests/mm/rmap.c
+++ b/tools/testing/selftests/mm/rmap.c
@@ -430,4 +430,73 @@ TEST_F(migrate, ksm)
 	propagate_children(_metadata, data);
 }

+/* To test if ksm page can be migrated when it's mremapped */
+int merge_mremap_and_migrate(struct global_data *data)
+{
+	int ret = 0;
+	/* Allocate range and set the same data */
+	data->mapsize = 3*getpagesize();
+	data->region = mmap(NULL, data->mapsize, PROT_READ|PROT_WRITE,
+			   MAP_PRIVATE|MAP_ANON, -1, 0);
+	if (data->region == MAP_FAILED)
+		ksft_exit_fail_perror("mmap failed");
+
+	memset(data->region, 0x77, data->mapsize);
+
+	if (ksm_start() < 0)
+		return FAIL_ON_CHECK;
+
+	/* 1  2 expected */
+	ksft_print_msg("Shared: %ld (1 expected) Sharing: %ld (2 expected)\n",
+		ksm_get_pages_shared(), ksm_get_pages_sharing());
+
+	/*
+	 * Mremap the second pagesize address range into the third pagesize
+	 * address.
+	 */
+	data->region = mremap(data->region + getpagesize(), getpagesize(), getpagesize(),
+			 MREMAP_MAYMOVE|MREMAP_FIXED, data->region + 2*getpagesize());
+
+	if (data->region == MAP_FAILED)
+		return FAIL_ON_CHECK;
+
+	/* Check if we can migrate this region successfully */
+	ret = try_to_move_page(data->region);
+	if (ret != 0)
+		return ret;
+
+	/* Wait ksm scan two turns at least */
+	if (ksm_start() < 0)
+		return FAIL_ON_CHECK;
+
+	/* 1  1 expected */
+	ksft_print_msg("Shared: %ld (1 expected) Sharing: %ld (1 expected)\n",
+		ksm_get_pages_shared(), ksm_get_pages_sharing());
+
+	return 0;
+}
+
+TEST_F(migrate, ksm_and_mremap)
+{
+	int ret;
+	struct global_data *data = &self->data;
+
+	/* prepare KSM interface setting */
+	if (ksm_stop() < 0)
+		SKIP(return, "accessing \"/sys/kernel/mm/ksm/run\") failed");
+	if (ksm_get_full_scans() < 0)
+		SKIP(return, "accessing \"/sys/kernel/mm/ksm/full_scan\") failed");
+
+	ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0);
+	if (ret < 0 && errno == EINVAL)
+		SKIP(return, "PR_SET_MEMORY_MERGE not supported");
+	else if (ret)
+		ksft_exit_fail_perror("PR_SET_MEMORY_MERGE=1 failed");
+
+	/* Start to merge same pages and mremap one of the three page area,
+	 * and test if ksm page can be migrated when it's mremapped */
+	ASSERT_EQ(merge_mremap_and_migrate(data), 0);
+}
+
+
 TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
index 9428f4d7bf55..47402b771ef8 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -646,6 +646,44 @@ long ksm_get_self_merging_pages(void)
 	return strtol(buf, NULL, 10);
 }

+long ksm_get_pages_shared(void)
+{
+	int ksm_pages_shared_fd;
+	char buf[10];
+	ssize_t ret;
+
+	ksm_pages_shared_fd = open("/sys/kernel/mm/ksm/pages_shared", O_RDONLY);
+	if (ksm_pages_shared_fd < 0)
+		return -errno;
+
+	ret = pread(ksm_pages_shared_fd, buf, sizeof(buf) - 1, 0);
+	close(ksm_pages_shared_fd);
+	if (ret <= 0)
+		return -errno;
+	buf[ret] = 0;
+
+	return strtol(buf, NULL, 10);
+}
+
+long ksm_get_pages_sharing(void)
+{
+	int ksm_pages_sharing_fd;
+	char buf[10];
+	ssize_t ret;
+
+	ksm_pages_sharing_fd = open("/sys/kernel/mm/ksm/pages_sharing", O_RDONLY);
+	if (ksm_pages_sharing_fd < 0)
+		return -errno;
+
+	ret = pread(ksm_pages_sharing_fd, buf, sizeof(buf) - 1, 0);
+	close(ksm_pages_sharing_fd);
+	if (ret <= 0)
+		return -errno;
+	buf[ret] = 0;
+
+	return strtol(buf, NULL, 10);
+}
+
 long ksm_get_full_scans(void)
 {
 	int ksm_full_scans_fd;
diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
index e9c4e24769c1..b0dd190f83e4 100644
--- a/tools/testing/selftests/mm/vm_util.h
+++ b/tools/testing/selftests/mm/vm_util.h
@@ -151,6 +151,8 @@ void *sys_mremap(void *old_address, unsigned long old_size,

 long ksm_get_self_zero_pages(void);
 long ksm_get_self_merging_pages(void);
+long ksm_get_pages_shared(void);
+long ksm_get_pages_sharing(void);
 long ksm_get_full_scans(void);
 int ksm_use_zero_pages(void);
 int ksm_start(void);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: ksm: add mremap selftests for ksm_rmap_walk
  2026-04-07  6:08 ksm: add mremap selftests for ksm_rmap_walk xu.xin16
@ 2026-04-07  9:43 ` Lorenzo Stoakes (Oracle)
  0 siblings, 0 replies; 2+ messages in thread
From: Lorenzo Stoakes (Oracle) @ 2026-04-07  9:43 UTC (permalink / raw)
  To: xu.xin16; +Cc: hughd, akpm, david, michel, chengming.zhou, linux-kernel,
	linux-mm

On Tue, Apr 07, 2026 at 02:08:05PM +0800, xu.xin16@zte.com.cn wrote:
> From: xu xin <xu.xin16@zte.com.cn>
>
> The existing tools/testing/selftests/mm/rmap.c has already one testcase
> for ksm_rmap_walk in TEST_F(migrate, ksm), which takes use of migration
> of page from one NUMA node to another NUMA node. However, it just lacks
> the senario of mremapped VMAs.
>
> Before migrating, we add the calling of mremap() to address mapped with KSM
> pages, which is specailly to test a optimization which is introduced by this
> patch ("ksm: Optimize rmap_walk_ksm by passing a suitable address range")
> https://lore.kernel.org/all/20260212193045556CbzCX8p9gDu73tQ2nvHEI@zte.com.cn/
>
> Result:
> TAP version 13
> 1..5
> ok 1 migrate.anon
> ok 2 migrate.shm
> ok 3 migrate.file # SKIP Failed in worker
> ok 4 migrate.ksm
> ok 5 migrate.ksm_and_mremap
>
> Signed-off-by: xu xin <xu.xin16@zte.com.cn>

Thanks for this, tests are always good, but I think we should bundle this in the
same series as with the rmap_walk_ksm optimisation, assuming we can be sure
whatever-form-of-that-we-end-up-with is ok.

I currently share Hugh's doubts as to correctness, so let's put the two together
I think.

Cheers, Lorenzo

> ---
>  tools/testing/selftests/mm/rmap.c    | 69 ++++++++++++++++++++++++++++
>  tools/testing/selftests/mm/vm_util.c | 38 +++++++++++++++
>  tools/testing/selftests/mm/vm_util.h |  2 +
>  3 files changed, 109 insertions(+)
>
> diff --git a/tools/testing/selftests/mm/rmap.c b/tools/testing/selftests/mm/rmap.c
> index 53f2058b0ef2..65470def2bf1 100644
> --- a/tools/testing/selftests/mm/rmap.c
> +++ b/tools/testing/selftests/mm/rmap.c
> @@ -430,4 +430,73 @@ TEST_F(migrate, ksm)
>  	propagate_children(_metadata, data);
>  }
>
> +/* To test if ksm page can be migrated when it's mremapped */
> +int merge_mremap_and_migrate(struct global_data *data)
> +{
> +	int ret = 0;
> +	/* Allocate range and set the same data */
> +	data->mapsize = 3*getpagesize();
> +	data->region = mmap(NULL, data->mapsize, PROT_READ|PROT_WRITE,
> +			   MAP_PRIVATE|MAP_ANON, -1, 0);
> +	if (data->region == MAP_FAILED)
> +		ksft_exit_fail_perror("mmap failed");
> +
> +	memset(data->region, 0x77, data->mapsize);
> +
> +	if (ksm_start() < 0)
> +		return FAIL_ON_CHECK;
> +
> +	/* 1  2 expected */
> +	ksft_print_msg("Shared: %ld (1 expected) Sharing: %ld (2 expected)\n",
> +		ksm_get_pages_shared(), ksm_get_pages_sharing());
> +
> +	/*
> +	 * Mremap the second pagesize address range into the third pagesize
> +	 * address.
> +	 */
> +	data->region = mremap(data->region + getpagesize(), getpagesize(), getpagesize(),
> +			 MREMAP_MAYMOVE|MREMAP_FIXED, data->region + 2*getpagesize());
> +
> +	if (data->region == MAP_FAILED)
> +		return FAIL_ON_CHECK;
> +
> +	/* Check if we can migrate this region successfully */
> +	ret = try_to_move_page(data->region);
> +	if (ret != 0)
> +		return ret;
> +
> +	/* Wait ksm scan two turns at least */
> +	if (ksm_start() < 0)
> +		return FAIL_ON_CHECK;
> +
> +	/* 1  1 expected */
> +	ksft_print_msg("Shared: %ld (1 expected) Sharing: %ld (1 expected)\n",
> +		ksm_get_pages_shared(), ksm_get_pages_sharing());
> +
> +	return 0;
> +}
> +
> +TEST_F(migrate, ksm_and_mremap)
> +{
> +	int ret;
> +	struct global_data *data = &self->data;
> +
> +	/* prepare KSM interface setting */
> +	if (ksm_stop() < 0)
> +		SKIP(return, "accessing \"/sys/kernel/mm/ksm/run\") failed");
> +	if (ksm_get_full_scans() < 0)
> +		SKIP(return, "accessing \"/sys/kernel/mm/ksm/full_scan\") failed");
> +
> +	ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0);
> +	if (ret < 0 && errno == EINVAL)
> +		SKIP(return, "PR_SET_MEMORY_MERGE not supported");
> +	else if (ret)
> +		ksft_exit_fail_perror("PR_SET_MEMORY_MERGE=1 failed");
> +
> +	/* Start to merge same pages and mremap one of the three page area,
> +	 * and test if ksm page can be migrated when it's mremapped */
> +	ASSERT_EQ(merge_mremap_and_migrate(data), 0);
> +}
> +
> +
>  TEST_HARNESS_MAIN
> diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
> index 9428f4d7bf55..47402b771ef8 100644
> --- a/tools/testing/selftests/mm/vm_util.c
> +++ b/tools/testing/selftests/mm/vm_util.c
> @@ -646,6 +646,44 @@ long ksm_get_self_merging_pages(void)
>  	return strtol(buf, NULL, 10);
>  }
>
> +long ksm_get_pages_shared(void)
> +{
> +	int ksm_pages_shared_fd;
> +	char buf[10];
> +	ssize_t ret;
> +
> +	ksm_pages_shared_fd = open("/sys/kernel/mm/ksm/pages_shared", O_RDONLY);
> +	if (ksm_pages_shared_fd < 0)
> +		return -errno;
> +
> +	ret = pread(ksm_pages_shared_fd, buf, sizeof(buf) - 1, 0);
> +	close(ksm_pages_shared_fd);
> +	if (ret <= 0)
> +		return -errno;
> +	buf[ret] = 0;
> +
> +	return strtol(buf, NULL, 10);
> +}
> +
> +long ksm_get_pages_sharing(void)
> +{
> +	int ksm_pages_sharing_fd;
> +	char buf[10];
> +	ssize_t ret;
> +
> +	ksm_pages_sharing_fd = open("/sys/kernel/mm/ksm/pages_sharing", O_RDONLY);
> +	if (ksm_pages_sharing_fd < 0)
> +		return -errno;
> +
> +	ret = pread(ksm_pages_sharing_fd, buf, sizeof(buf) - 1, 0);
> +	close(ksm_pages_sharing_fd);
> +	if (ret <= 0)
> +		return -errno;
> +	buf[ret] = 0;
> +
> +	return strtol(buf, NULL, 10);
> +}
> +
>  long ksm_get_full_scans(void)
>  {
>  	int ksm_full_scans_fd;
> diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
> index e9c4e24769c1..b0dd190f83e4 100644
> --- a/tools/testing/selftests/mm/vm_util.h
> +++ b/tools/testing/selftests/mm/vm_util.h
> @@ -151,6 +151,8 @@ void *sys_mremap(void *old_address, unsigned long old_size,
>
>  long ksm_get_self_zero_pages(void);
>  long ksm_get_self_merging_pages(void);
> +long ksm_get_pages_shared(void);
> +long ksm_get_pages_sharing(void);
>  long ksm_get_full_scans(void);
>  int ksm_use_zero_pages(void);
>  int ksm_start(void);
> --
> 2.25.1


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-04-07  9:43 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-07  6:08 ksm: add mremap selftests for ksm_rmap_walk xu.xin16
2026-04-07  9:43 ` Lorenzo Stoakes (Oracle)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox