diff mbox series

[v1] KVM: s390x: selftests: Add shared zeropage test

Message ID 20240412084329.30315-1-david@redhat.com (mailing list archive)
State New, archived
Headers show
Series [v1] KVM: s390x: selftests: Add shared zeropage test | expand

Commit Message

David Hildenbrand April 12, 2024, 8:43 a.m. UTC
Let's test that we can have shared zeropages in our process as long as
storage keys are not getting used, that shared zeropages are properly
unshared (replaced by anonymous pages) once storage keys are enabled,
and that no new shared zeropages are populated after storage keys
were enabled.

We require the new pagemap interface to detect the shared zeropage.

On an old kernel (zeropages always disabled):
	# ./s390x/shared_zeropage_test
	TAP version 13
	1..3
	not ok 1 Shared zeropages should be enabled
	ok 2 Shared zeropage should be gone
	ok 3 Shared zeropages should be disabled
	# Totals: pass:2 fail:1 xfail:0 xpass:0 skip:0 error:0

On a fixed kernel:
	# ./s390x/shared_zeropage_test
	TAP version 13
	1..3
	ok 1 Shared zeropages should be enabled
	ok 2 Shared zeropage should be gone
	ok 3 Shared zeropages should be disabled
	# Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0

Testing of UFFDIO_ZEROPAGE can be added later.

Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
Cc: Janosch Frank <frankja@linux.ibm.com>
Cc: Claudio Imbrenda <imbrenda@linux.ibm.com>
Cc: Thomas Huth <thuth@redhat.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Shuah Khan <shuah@kernel.org>
Signed-off-by: David Hildenbrand <david@redhat.com>
---

To get it right this time, test the relevant cases.

v3 of fixes are at:
 https://lore.kernel.org/all/20240411161441.910170-1-david@redhat.com/T/#u

---
 tools/testing/selftests/kvm/Makefile          |   1 +
 .../kvm/s390x/shared_zeropage_test.c          | 110 ++++++++++++++++++
 2 files changed, 111 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/s390x/shared_zeropage_test.c

Comments

Alexander Gordeev April 15, 2024, 2:19 p.m. UTC | #1
On Fri, Apr 12, 2024 at 10:43:29AM +0200, David Hildenbrand wrote:
Hi David,
>  tools/testing/selftests/kvm/Makefile          |   1 +
>  .../kvm/s390x/shared_zeropage_test.c          | 110 ++++++++++++++++++
>  2 files changed, 111 insertions(+)
>  create mode 100644 tools/testing/selftests/kvm/s390x/shared_zeropage_test.c

Tested-by: Alexander Gordeev <agordeev@linux.ibm.com>

@Janosch, Christian,

I think this patch should go via s390 tree together with
https://lore.kernel.org/r/20240411161441.910170-3-david@redhat.com

Do you agree?

Thanks!
David Hildenbrand April 15, 2024, 2:22 p.m. UTC | #2
On 15.04.24 16:19, Alexander Gordeev wrote:
> On Fri, Apr 12, 2024 at 10:43:29AM +0200, David Hildenbrand wrote:
> Hi David,
>>   tools/testing/selftests/kvm/Makefile          |   1 +
>>   .../kvm/s390x/shared_zeropage_test.c          | 110 ++++++++++++++++++
>>   2 files changed, 111 insertions(+)
>>   create mode 100644 tools/testing/selftests/kvm/s390x/shared_zeropage_test.c
> 
> Tested-by: Alexander Gordeev <agordeev@linux.ibm.com>

Thanks Alexander, especially also for discovering that nasty ifdef bug!
Christian Borntraeger April 15, 2024, 2:27 p.m. UTC | #3
Am 15.04.24 um 16:19 schrieb Alexander Gordeev:
> On Fri, Apr 12, 2024 at 10:43:29AM +0200, David Hildenbrand wrote:
> Hi David,
>>   tools/testing/selftests/kvm/Makefile          |   1 +
>>   .../kvm/s390x/shared_zeropage_test.c          | 110 ++++++++++++++++++
>>   2 files changed, 111 insertions(+)
>>   create mode 100644 tools/testing/selftests/kvm/s390x/shared_zeropage_test.c
> 
> Tested-by: Alexander Gordeev <agordeev@linux.ibm.com>
> 
> @Janosch, Christian,
> 
> I think this patch should go via s390 tree together with
> https://lore.kernel.org/r/20240411161441.910170-3-david@redhat.com
> 
> Do you agree?

Yes, thank you

Acked-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Alexander Gordeev April 15, 2024, 2:52 p.m. UTC | #4
On Fri, Apr 12, 2024 at 10:43:29AM +0200, David Hildenbrand wrote:
>  tools/testing/selftests/kvm/Makefile          |   1 +
>  .../kvm/s390x/shared_zeropage_test.c          | 110 ++++++++++++++++++
>  2 files changed, 111 insertions(+)
>  create mode 100644 tools/testing/selftests/kvm/s390x/shared_zeropage_test.c

Applied, thanks, David!
Muhammad Usama Anjum April 15, 2024, 6:43 p.m. UTC | #5
On 4/12/24 1:43 PM, David Hildenbrand wrote:
> Let's test that we can have shared zeropages in our process as long as
> storage keys are not getting used, that shared zeropages are properly
> unshared (replaced by anonymous pages) once storage keys are enabled,
> and that no new shared zeropages are populated after storage keys
> were enabled.
> 
> We require the new pagemap interface to detect the shared zeropage.
> 
> On an old kernel (zeropages always disabled):
> 	# ./s390x/shared_zeropage_test
> 	TAP version 13
> 	1..3
> 	not ok 1 Shared zeropages should be enabled
> 	ok 2 Shared zeropage should be gone
> 	ok 3 Shared zeropages should be disabled
> 	# Totals: pass:2 fail:1 xfail:0 xpass:0 skip:0 error:0
> 
> On a fixed kernel:
> 	# ./s390x/shared_zeropage_test
> 	TAP version 13
> 	1..3
> 	ok 1 Shared zeropages should be enabled
> 	ok 2 Shared zeropage should be gone
> 	ok 3 Shared zeropages should be disabled
> 	# Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0
> 
> Testing of UFFDIO_ZEROPAGE can be added later.
> 
> Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
> Cc: Janosch Frank <frankja@linux.ibm.com>
> Cc: Claudio Imbrenda <imbrenda@linux.ibm.com>
> Cc: Thomas Huth <thuth@redhat.com>
> Cc: Alexander Gordeev <agordeev@linux.ibm.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Shuah Khan <shuah@kernel.org>
> Signed-off-by: David Hildenbrand <david@redhat.com>
Acked-by: Muhammad Usama Anjum <usama.anjum@collabora.com>

> ---
> 
> To get it right this time, test the relevant cases.
> 
> v3 of fixes are at:
>  https://lore.kernel.org/all/20240411161441.910170-1-david@redhat.com/T/#u
> 
> ---
>  tools/testing/selftests/kvm/Makefile          |   1 +
>  .../kvm/s390x/shared_zeropage_test.c          | 110 ++++++++++++++++++
>  2 files changed, 111 insertions(+)
>  create mode 100644 tools/testing/selftests/kvm/s390x/shared_zeropage_test.c
> 
> diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
> index 741c7dc16afc..ed4ad591f193 100644
> --- a/tools/testing/selftests/kvm/Makefile
> +++ b/tools/testing/selftests/kvm/Makefile
> @@ -180,6 +180,7 @@ TEST_GEN_PROGS_s390x += s390x/sync_regs_test
>  TEST_GEN_PROGS_s390x += s390x/tprot
>  TEST_GEN_PROGS_s390x += s390x/cmma_test
>  TEST_GEN_PROGS_s390x += s390x/debug_test
> +TEST_GEN_PROGS_s390x += s390x/shared_zeropage_test
>  TEST_GEN_PROGS_s390x += demand_paging_test
>  TEST_GEN_PROGS_s390x += dirty_log_test
>  TEST_GEN_PROGS_s390x += guest_print_test
> diff --git a/tools/testing/selftests/kvm/s390x/shared_zeropage_test.c b/tools/testing/selftests/kvm/s390x/shared_zeropage_test.c
> new file mode 100644
> index 000000000000..74e829748fb1
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/s390x/shared_zeropage_test.c
> @@ -0,0 +1,110 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Test shared zeropage handling (with/without storage keys)
> + *
> + * Copyright (C) 2024, Red Hat, Inc.
> + */
> +#include <sys/mman.h>
> +
> +#include <linux/fs.h>
> +
> +#include "test_util.h"
> +#include "kvm_util.h"
> +#include "kselftest.h"
> +
> +static void set_storage_key(void *addr, uint8_t skey)
> +{
> +	asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
> +}
> +
> +static void guest_code(void)
> +{
> +	/* Issue some storage key instruction. */
> +	set_storage_key((void *)0, 0x98);
> +	GUEST_DONE();
> +}
> +
> +/*
> + * Returns 1 if the shared zeropage is mapped, 0 if something else is mapped.
> + * Returns < 0 on error or if nothing is mapped.
> + */
> +static int maps_shared_zeropage(int pagemap_fd, void *addr)
> +{
> +	struct page_region region;
> +	struct pm_scan_arg arg = {
> +		.start = (uintptr_t)addr,
> +		.end = (uintptr_t)addr + 4096,
> +		.vec = (uintptr_t)&region,
> +		.vec_len = 1,
> +		.size = sizeof(struct pm_scan_arg),
> +		.category_mask = PAGE_IS_PFNZERO,
> +		.category_anyof_mask = PAGE_IS_PRESENT,
> +		.return_mask = PAGE_IS_PFNZERO,
> +	};
> +	return ioctl(pagemap_fd, PAGEMAP_SCAN, &arg);Its good to see more users for it.

> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	char *mem, *page0, *page1, *page2, tmp;
> +	const size_t pagesize = getpagesize();
> +	struct kvm_vcpu *vcpu;
> +	struct kvm_vm *vm;
> +	struct ucall uc;
> +	int pagemap_fd;
> +
> +	ksft_print_header();
> +	ksft_set_plan(3);
> +
> +	/*
> +	 * We'll use memory that is not mapped into the VM for simplicity.
> +	 * Shared zeropages are enabled/disabled per-process.
> +	 */
> +	mem = mmap(0, 3 * pagesize, PROT_READ, MAP_PRIVATE|MAP_ANON, -1, 0);
> +	TEST_ASSERT(mem != MAP_FAILED, "mmap() failed");
> +
> +	/* Disable THP. Ignore errors on older kernels. */
> +	madvise(mem, 3 * pagesize, MADV_NOHUGEPAGE);
> +
> +	page0 = mem;
> +	page1 = page0 + pagesize;
> +	page2 = page1 + pagesize;
> +
> +	/* Can we even detect shared zeropages? */
> +	pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
> +	TEST_REQUIRE(pagemap_fd >= 0);
> +
> +	tmp = *page0;
> +	asm volatile("" : "+r" (tmp));
> +	TEST_REQUIRE(maps_shared_zeropage(pagemap_fd, page0) == 1);
> +
> +	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
> +
> +	/* Verify that we get the shared zeropage after VM creation. */
> +	tmp = *page1;
> +	asm volatile("" : "+r" (tmp));
> +	ksft_test_result(maps_shared_zeropage(pagemap_fd, page1) == 1,
> +			 "Shared zeropages should be enabled\n");
> +
> +	/*
> +	 * Let our VM execute a storage key instruction that should
> +	 * unshare all shared zeropages.
> +	 */
> +	vcpu_run(vcpu);
> +	get_ucall(vcpu, &uc);
> +	TEST_ASSERT_EQ(uc.cmd, UCALL_DONE);
> +
> +	/* Verify that we don't have a shared zeropage anymore. */
> +	ksft_test_result(!maps_shared_zeropage(pagemap_fd, page1),
> +			 "Shared zeropage should be gone\n");
> +
> +	/* Verify that we don't get any new shared zeropages. */
> +	tmp = *page2;
> +	asm volatile("" : "+r" (tmp));
> +	ksft_test_result(!maps_shared_zeropage(pagemap_fd, page2),
> +			 "Shared zeropages should be disabled\n");
> +
> +	kvm_vm_free(vm);
> +
> +	ksft_finished();
> +}
diff mbox series

Patch

diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index 741c7dc16afc..ed4ad591f193 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -180,6 +180,7 @@  TEST_GEN_PROGS_s390x += s390x/sync_regs_test
 TEST_GEN_PROGS_s390x += s390x/tprot
 TEST_GEN_PROGS_s390x += s390x/cmma_test
 TEST_GEN_PROGS_s390x += s390x/debug_test
+TEST_GEN_PROGS_s390x += s390x/shared_zeropage_test
 TEST_GEN_PROGS_s390x += demand_paging_test
 TEST_GEN_PROGS_s390x += dirty_log_test
 TEST_GEN_PROGS_s390x += guest_print_test
diff --git a/tools/testing/selftests/kvm/s390x/shared_zeropage_test.c b/tools/testing/selftests/kvm/s390x/shared_zeropage_test.c
new file mode 100644
index 000000000000..74e829748fb1
--- /dev/null
+++ b/tools/testing/selftests/kvm/s390x/shared_zeropage_test.c
@@ -0,0 +1,110 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Test shared zeropage handling (with/without storage keys)
+ *
+ * Copyright (C) 2024, Red Hat, Inc.
+ */
+#include <sys/mman.h>
+
+#include <linux/fs.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "kselftest.h"
+
+static void set_storage_key(void *addr, uint8_t skey)
+{
+	asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
+}
+
+static void guest_code(void)
+{
+	/* Issue some storage key instruction. */
+	set_storage_key((void *)0, 0x98);
+	GUEST_DONE();
+}
+
+/*
+ * Returns 1 if the shared zeropage is mapped, 0 if something else is mapped.
+ * Returns < 0 on error or if nothing is mapped.
+ */
+static int maps_shared_zeropage(int pagemap_fd, void *addr)
+{
+	struct page_region region;
+	struct pm_scan_arg arg = {
+		.start = (uintptr_t)addr,
+		.end = (uintptr_t)addr + 4096,
+		.vec = (uintptr_t)&region,
+		.vec_len = 1,
+		.size = sizeof(struct pm_scan_arg),
+		.category_mask = PAGE_IS_PFNZERO,
+		.category_anyof_mask = PAGE_IS_PRESENT,
+		.return_mask = PAGE_IS_PFNZERO,
+	};
+	return ioctl(pagemap_fd, PAGEMAP_SCAN, &arg);
+}
+
+int main(int argc, char *argv[])
+{
+	char *mem, *page0, *page1, *page2, tmp;
+	const size_t pagesize = getpagesize();
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	struct ucall uc;
+	int pagemap_fd;
+
+	ksft_print_header();
+	ksft_set_plan(3);
+
+	/*
+	 * We'll use memory that is not mapped into the VM for simplicity.
+	 * Shared zeropages are enabled/disabled per-process.
+	 */
+	mem = mmap(0, 3 * pagesize, PROT_READ, MAP_PRIVATE|MAP_ANON, -1, 0);
+	TEST_ASSERT(mem != MAP_FAILED, "mmap() failed");
+
+	/* Disable THP. Ignore errors on older kernels. */
+	madvise(mem, 3 * pagesize, MADV_NOHUGEPAGE);
+
+	page0 = mem;
+	page1 = page0 + pagesize;
+	page2 = page1 + pagesize;
+
+	/* Can we even detect shared zeropages? */
+	pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
+	TEST_REQUIRE(pagemap_fd >= 0);
+
+	tmp = *page0;
+	asm volatile("" : "+r" (tmp));
+	TEST_REQUIRE(maps_shared_zeropage(pagemap_fd, page0) == 1);
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+
+	/* Verify that we get the shared zeropage after VM creation. */
+	tmp = *page1;
+	asm volatile("" : "+r" (tmp));
+	ksft_test_result(maps_shared_zeropage(pagemap_fd, page1) == 1,
+			 "Shared zeropages should be enabled\n");
+
+	/*
+	 * Let our VM execute a storage key instruction that should
+	 * unshare all shared zeropages.
+	 */
+	vcpu_run(vcpu);
+	get_ucall(vcpu, &uc);
+	TEST_ASSERT_EQ(uc.cmd, UCALL_DONE);
+
+	/* Verify that we don't have a shared zeropage anymore. */
+	ksft_test_result(!maps_shared_zeropage(pagemap_fd, page1),
+			 "Shared zeropage should be gone\n");
+
+	/* Verify that we don't get any new shared zeropages. */
+	tmp = *page2;
+	asm volatile("" : "+r" (tmp));
+	ksft_test_result(!maps_shared_zeropage(pagemap_fd, page2),
+			 "Shared zeropages should be disabled\n");
+
+	kvm_vm_free(vm);
+
+	ksft_finished();
+}