Skip to content

Commit 01c51a3

Browse files
davidhildenbrandAlexander Gordeev
authored andcommitted
KVM: s390x: selftests: Add shared zeropage test
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. [ agordeev: Fixed checkpatch complaint, added ucall_common.h include ] 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: Christian Borntraeger <borntraeger@linux.ibm.com> Acked-by: Muhammad Usama Anjum <usama.anjum@collabora.com> Tested-by: Alexander Gordeev <agordeev@linux.ibm.com> Link: https://lore.kernel.org/r/20240412084329.30315-1-david@redhat.com Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
1 parent d38e485 commit 01c51a3

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

tools/testing/selftests/kvm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ TEST_GEN_PROGS_s390x += s390x/sync_regs_test
183183
TEST_GEN_PROGS_s390x += s390x/tprot
184184
TEST_GEN_PROGS_s390x += s390x/cmma_test
185185
TEST_GEN_PROGS_s390x += s390x/debug_test
186+
TEST_GEN_PROGS_s390x += s390x/shared_zeropage_test
186187
TEST_GEN_PROGS_s390x += demand_paging_test
187188
TEST_GEN_PROGS_s390x += dirty_log_test
188189
TEST_GEN_PROGS_s390x += guest_print_test
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Test shared zeropage handling (with/without storage keys)
4+
*
5+
* Copyright (C) 2024, Red Hat, Inc.
6+
*/
7+
#include <sys/mman.h>
8+
9+
#include <linux/fs.h>
10+
11+
#include "test_util.h"
12+
#include "kvm_util.h"
13+
#include "kselftest.h"
14+
#include "ucall_common.h"
15+
16+
static void set_storage_key(void *addr, uint8_t skey)
17+
{
18+
asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
19+
}
20+
21+
static void guest_code(void)
22+
{
23+
/* Issue some storage key instruction. */
24+
set_storage_key((void *)0, 0x98);
25+
GUEST_DONE();
26+
}
27+
28+
/*
29+
* Returns 1 if the shared zeropage is mapped, 0 if something else is mapped.
30+
* Returns < 0 on error or if nothing is mapped.
31+
*/
32+
static int maps_shared_zeropage(int pagemap_fd, void *addr)
33+
{
34+
struct page_region region;
35+
struct pm_scan_arg arg = {
36+
.start = (uintptr_t)addr,
37+
.end = (uintptr_t)addr + 4096,
38+
.vec = (uintptr_t)&region,
39+
.vec_len = 1,
40+
.size = sizeof(struct pm_scan_arg),
41+
.category_mask = PAGE_IS_PFNZERO,
42+
.category_anyof_mask = PAGE_IS_PRESENT,
43+
.return_mask = PAGE_IS_PFNZERO,
44+
};
45+
return ioctl(pagemap_fd, PAGEMAP_SCAN, &arg);
46+
}
47+
48+
int main(int argc, char *argv[])
49+
{
50+
char *mem, *page0, *page1, *page2, tmp;
51+
const size_t pagesize = getpagesize();
52+
struct kvm_vcpu *vcpu;
53+
struct kvm_vm *vm;
54+
struct ucall uc;
55+
int pagemap_fd;
56+
57+
ksft_print_header();
58+
ksft_set_plan(3);
59+
60+
/*
61+
* We'll use memory that is not mapped into the VM for simplicity.
62+
* Shared zeropages are enabled/disabled per-process.
63+
*/
64+
mem = mmap(0, 3 * pagesize, PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0);
65+
TEST_ASSERT(mem != MAP_FAILED, "mmap() failed");
66+
67+
/* Disable THP. Ignore errors on older kernels. */
68+
madvise(mem, 3 * pagesize, MADV_NOHUGEPAGE);
69+
70+
page0 = mem;
71+
page1 = page0 + pagesize;
72+
page2 = page1 + pagesize;
73+
74+
/* Can we even detect shared zeropages? */
75+
pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
76+
TEST_REQUIRE(pagemap_fd >= 0);
77+
78+
tmp = *page0;
79+
asm volatile("" : "+r" (tmp));
80+
TEST_REQUIRE(maps_shared_zeropage(pagemap_fd, page0) == 1);
81+
82+
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
83+
84+
/* Verify that we get the shared zeropage after VM creation. */
85+
tmp = *page1;
86+
asm volatile("" : "+r" (tmp));
87+
ksft_test_result(maps_shared_zeropage(pagemap_fd, page1) == 1,
88+
"Shared zeropages should be enabled\n");
89+
90+
/*
91+
* Let our VM execute a storage key instruction that should
92+
* unshare all shared zeropages.
93+
*/
94+
vcpu_run(vcpu);
95+
get_ucall(vcpu, &uc);
96+
TEST_ASSERT_EQ(uc.cmd, UCALL_DONE);
97+
98+
/* Verify that we don't have a shared zeropage anymore. */
99+
ksft_test_result(!maps_shared_zeropage(pagemap_fd, page1),
100+
"Shared zeropage should be gone\n");
101+
102+
/* Verify that we don't get any new shared zeropages. */
103+
tmp = *page2;
104+
asm volatile("" : "+r" (tmp));
105+
ksft_test_result(!maps_shared_zeropage(pagemap_fd, page2),
106+
"Shared zeropages should be disabled\n");
107+
108+
kvm_vm_free(vm);
109+
110+
ksft_finished();
111+
}

0 commit comments

Comments
 (0)