History

Merge tag 'kvm-x86-fixes-6.18-rc2' of https://github.com/kvm-x86/linux into HEAD

KVM x86 fixes for 6.18: - Expand the KVM_PRE_FAULT_MEMORY selftest to add a regression test for the bug fixed by commit 3ccbf6f47098 ("KVM: x86/mmu: Return -EAGAIN if userspace deletes/moves memslot during prefault") - Don't try to get PMU capabbilities from perf when running a CPU with hybrid CPUs/PMUs, as perf will rightly WARN. - Rework KVM_CAP_GUEST_MEMFD_MMAP (newly introduced in 6.18) into a more generic KVM_CAP_GUEST_MEMFD_FLAGS - Add a guest_memfd INIT_SHARED flag and require userspace to explicitly set said flag to initialize memory as SHARED, irrespective of MMAP. The behavior merged in 6.18 is that enabling mmap() implicitly initializes memory as SHARED, which would result in an ABI collision for x86 CoCo VMs as their memory is currently always initialized PRIVATE. - Allow mmap() on guest_memfd for x86 CoCo VMs, i.e. on VMs with private memory, to enable testing such setups, i.e. to hopefully flush out any other lurking ABI issues before 6.18 is officially released. - Add testcases to the guest_memfd selftest to cover guest_memfd without MMAP, and host userspace accesses to mmap()'d private memory.

Paolo Bonzini committed 1 year ago

Commit 4361f5a2 parents 5d26eaa 505f52217 files · +375 −185Browse files

Unified · Split

17 files
  1. Documentation/virt/kvm/api.rst +12 −3
  2. arch/x86/kvm/pmu.c +5 −3
  3. arch/x86/kvm/x86.c +4 −3
  4. include/linux/kvm_host.h +11 −1
  5. include/uapi/linux/kvm.h +3 −2
  6. tools/testing/selftests/kvm/guest_memfd_test.c +91 −78
  7. tools/testing/selftests/kvm/include/kvm_util.h +25 −0
  8. tools/testing/selftests/kvm/include/test_util.h +19 −0
  9. tools/testing/selftests/kvm/lib/kvm_util.c +15 −29
  10. tools/testing/selftests/kvm/lib/test_util.c +7 −0
  11. tools/testing/selftests/kvm/mmu_stress_test.c +2 −3
  12. tools/testing/selftests/kvm/pre_fault_memory_test.c +114 −17
  13. tools/testing/selftests/kvm/s390/ucontrol_test.c +7 −9
  14. tools/testing/selftests/kvm/set_memory_region_test.c +8 −9
  15. virt/kvm/Kconfig +1 −0
  16. virt/kvm/guest_memfd.c +49 −26
  17. virt/kvm/kvm_main.c +2 −2
Documentation/virt/kvm/api.rst+12−3
@@ -6437,9 +6437,18 @@ most one mapping per page, i.e. binding multiple memory regions to a single · 6436 unmodified lines
6437guest_memfd range is not allowed (any number of memory regions can be bound to6437guest_memfd range is not allowed (any number of memory regions can be bound to
6438a single guest_memfd file, but the bound ranges must not overlap).6438a single guest_memfd file, but the bound ranges must not overlap).
6439 6439
6440When the capability KVM_CAP_GUEST_MEMFD_MMAP is supported, the 'flags' field6440The capability KVM_CAP_GUEST_MEMFD_FLAGS enumerates the `flags` that can be
6441supports GUEST_MEMFD_FLAG_MMAP. Setting this flag on guest_memfd creation6441specified via KVM_CREATE_GUEST_MEMFD. Currently defined flags:
6442enables mmap() and faulting of guest_memfd memory to host userspace.6442
6443 ============================ ================================================
6444 GUEST_MEMFD_FLAG_MMAP Enable using mmap() on the guest_memfd file
6445 descriptor.
6446 GUEST_MEMFD_FLAG_INIT_SHARED Make all memory in the file shared during
6447 KVM_CREATE_GUEST_MEMFD (memory files created
6448 without INIT_SHARED will be marked private).
6449 Shared memory can be faulted into host userspace
6450 page tables. Private memory cannot.
6451 ============================ ================================================
6443 6452
6444When the KVM MMU performs a PFN lookup to service a guest fault and the backing6453When the KVM MMU performs a PFN lookup to service a guest fault and the backing
6445guest_memfd has the GUEST_MEMFD_FLAG_MMAP set, then the fault will always be6454guest_memfd has the GUEST_MEMFD_FLAG_MMAP set, then the fault will always be
arch/x86/kvm/pmu.c+5−3
@@ -108,16 +108,18 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops) · 107 unmodified lines
108 bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL;108 bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL;
109 int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS;109 int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS;
110 110
111 perf_get_x86_pmu_capability(&kvm_host_pmu);
112
113 /*111 /*
114 * Hybrid PMUs don't play nice with virtualization without careful112 * Hybrid PMUs don't play nice with virtualization without careful
115 * configuration by userspace, and KVM's APIs for reporting supported113 * configuration by userspace, and KVM's APIs for reporting supported
116 * vPMU features do not account for hybrid PMUs. Disable vPMU support114 * vPMU features do not account for hybrid PMUs. Disable vPMU support
117 * for hybrid PMUs until KVM gains a way to let userspace opt-in.115 * for hybrid PMUs until KVM gains a way to let userspace opt-in.
118 */116 */
119 if (cpu_feature_enabled(X86_FEATURE_HYBRID_CPU))117 if (cpu_feature_enabled(X86_FEATURE_HYBRID_CPU)) {
120 enable_pmu = false;118 enable_pmu = false;
119 memset(&kvm_host_pmu, 0, sizeof(kvm_host_pmu));
120 } else {
121 perf_get_x86_pmu_capability(&kvm_host_pmu);
122 }
121 123
122 if (enable_pmu) {124 if (enable_pmu) {
123 /*125 /*
arch/x86/kvm/x86.c+4−3
@@ -13941,10 +13941,11 @@ bool kvm_arch_no_poll(struct kvm_vcpu *vcpu) · 13940 unmodified lines
13941 13941
13942#ifdef CONFIG_KVM_GUEST_MEMFD13942#ifdef CONFIG_KVM_GUEST_MEMFD
13943/*13943/*
13944 * KVM doesn't yet support mmap() on guest_memfd for VMs with private memory13944 * KVM doesn't yet support initializing guest_memfd memory as shared for VMs
13945 * (the private vs. shared tracking needs to be moved into guest_memfd).13945 * with private memory (the private vs. shared tracking needs to be moved into
13946 * guest_memfd).
13946 */13947 */
13947bool kvm_arch_supports_gmem_mmap(struct kvm *kvm)13948bool kvm_arch_supports_gmem_init_shared(struct kvm *kvm)
13948{13949{
13949 return !kvm_arch_has_private_mem(kvm);13950 return !kvm_arch_has_private_mem(kvm);
13950}13951}
include/linux/kvm_host.h+11−1
@@ -729,7 +729,17 @@ static inline bool kvm_arch_has_private_mem(struct kvm *kvm) · 728 unmodified lines
729#endif729#endif
730 730
731#ifdef CONFIG_KVM_GUEST_MEMFD731#ifdef CONFIG_KVM_GUEST_MEMFD
732bool kvm_arch_supports_gmem_mmap(struct kvm *kvm);732bool kvm_arch_supports_gmem_init_shared(struct kvm *kvm);
733
734static inline u64 kvm_gmem_get_supported_flags(struct kvm *kvm)
735{
736 u64 flags = GUEST_MEMFD_FLAG_MMAP;
737
738 if (!kvm || kvm_arch_supports_gmem_init_shared(kvm))
739 flags |= GUEST_MEMFD_FLAG_INIT_SHARED;
740
741 return flags;
742}
733#endif743#endif
734 744
735#ifndef kvm_arch_has_readonly_mem745#ifndef kvm_arch_has_readonly_mem
include/uapi/linux/kvm.h+3−2
@@ -962,7 +962,7 @@ struct kvm_enable_cap { · 961 unmodified lines
962#define KVM_CAP_ARM_EL2_E2H0 241962#define KVM_CAP_ARM_EL2_E2H0 241
963#define KVM_CAP_RISCV_MP_STATE_RESET 242963#define KVM_CAP_RISCV_MP_STATE_RESET 242
964#define KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED 243964#define KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED 243
965#define KVM_CAP_GUEST_MEMFD_MMAP 244965#define KVM_CAP_GUEST_MEMFD_FLAGS 244
966 966
967struct kvm_irq_routing_irqchip {967struct kvm_irq_routing_irqchip {
968 __u32 irqchip;968 __u32 irqchip;
@@ -1599,7 +1599,8 @@ struct kvm_memory_attributes { · 630 unmodified lines
1599#define KVM_MEMORY_ATTRIBUTE_PRIVATE (1ULL << 3)1599#define KVM_MEMORY_ATTRIBUTE_PRIVATE (1ULL << 3)
1600 1600
1601#define KVM_CREATE_GUEST_MEMFD _IOWR(KVMIO, 0xd4, struct kvm_create_guest_memfd)1601#define KVM_CREATE_GUEST_MEMFD _IOWR(KVMIO, 0xd4, struct kvm_create_guest_memfd)
1602#define GUEST_MEMFD_FLAG_MMAP (1ULL << 0)1602#define GUEST_MEMFD_FLAG_MMAP (1ULL << 0)
1603#define GUEST_MEMFD_FLAG_INIT_SHARED (1ULL << 1)
1603 1604
1604struct kvm_create_guest_memfd {1605struct kvm_create_guest_memfd {
1605 __u64 size;1606 __u64 size;
tools/testing/selftests/kvm/guest_memfd_test.c+91−78
@@ -14,8 +14,6 @@ · 13 unmodified lines
14#include <linux/bitmap.h>14#include <linux/bitmap.h>
15#include <linux/falloc.h>15#include <linux/falloc.h>
16#include <linux/sizes.h>16#include <linux/sizes.h>
17#include <setjmp.h>
18#include <signal.h>
19#include <sys/mman.h>17#include <sys/mman.h>
20#include <sys/types.h>18#include <sys/types.h>
21#include <sys/stat.h>19#include <sys/stat.h>
@@ -24,7 +22,9 @@ · 2 unmodified lines
24#include "test_util.h"22#include "test_util.h"
25#include "ucall_common.h"23#include "ucall_common.h"
26 24
27static void test_file_read_write(int fd)25static size_t page_size;
26
27static void test_file_read_write(int fd, size_t total_size)
28{28{
29 char buf[64];29 char buf[64];
30 30
@@ -38,18 +38,22 @@ static void test_file_read_write(int fd) · 7 unmodified lines
38 "pwrite on a guest_mem fd should fail");38 "pwrite on a guest_mem fd should fail");
39}39}
40 40
41static void test_mmap_supported(int fd, size_t page_size, size_t total_size)41static void test_mmap_cow(int fd, size_t size)
42{
43 void *mem;
44
45 mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
46 TEST_ASSERT(mem == MAP_FAILED, "Copy-on-write not allowed by guest_memfd.");
47}
48
49static void test_mmap_supported(int fd, size_t total_size)
42{50{
43 const char val = 0xaa;51 const char val = 0xaa;
44 char *mem;52 char *mem;
45 size_t i;53 size_t i;
46 int ret;54 int ret;
47 55
48 mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);56 mem = kvm_mmap(total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);
49 TEST_ASSERT(mem == MAP_FAILED, "Copy-on-write not allowed by guest_memfd.");
50
51 mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
52 TEST_ASSERT(mem != MAP_FAILED, "mmap() for guest_memfd should succeed.");
53 57
54 memset(mem, val, total_size);58 memset(mem, val, total_size);
55 for (i = 0; i < total_size; i++)59 for (i = 0; i < total_size; i++)
@@ -68,45 +72,37 @@ static void test_mmap_supported(int fd, size_t page_size, size_t total_size) · 12 unmodified lines
68 for (i = 0; i < total_size; i++)72 for (i = 0; i < total_size; i++)
69 TEST_ASSERT_EQ(READ_ONCE(mem[i]), val);73 TEST_ASSERT_EQ(READ_ONCE(mem[i]), val);
70 74
71 ret = munmap(mem, total_size);75 kvm_munmap(mem, total_size);
72 TEST_ASSERT(!ret, "munmap() should succeed.");
73}
74
75static sigjmp_buf jmpbuf;
76void fault_sigbus_handler(int signum)
77{
78 siglongjmp(jmpbuf, 1);
79}76}
80 77
81static void test_fault_overflow(int fd, size_t page_size, size_t total_size)78static void test_fault_sigbus(int fd, size_t accessible_size, size_t map_size)
82{79{
83 struct sigaction sa_old, sa_new = {
84 .sa_handler = fault_sigbus_handler,
85 };
86 size_t map_size = total_size * 4;
87 const char val = 0xaa;80 const char val = 0xaa;
88 char *mem;81 char *mem;
89 size_t i;82 size_t i;
90 int ret;
91 83
92 mem = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);84 mem = kvm_mmap(map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);
93 TEST_ASSERT(mem != MAP_FAILED, "mmap() for guest_memfd should succeed.");
94 85
95 sigaction(SIGBUS, &sa_new, &sa_old);86 TEST_EXPECT_SIGBUS(memset(mem, val, map_size));
96 if (sigsetjmp(jmpbuf, 1) == 0) {87 TEST_EXPECT_SIGBUS((void)READ_ONCE(mem[accessible_size]));
97 memset(mem, 0xaa, map_size);
98 TEST_ASSERT(false, "memset() should have triggered SIGBUS.");
99 }
100 sigaction(SIGBUS, &sa_old, NULL);
101 88
102 for (i = 0; i < total_size; i++)89 for (i = 0; i < accessible_size; i++)
103 TEST_ASSERT_EQ(READ_ONCE(mem[i]), val);90 TEST_ASSERT_EQ(READ_ONCE(mem[i]), val);
104 91
105 ret = munmap(mem, map_size);92 kvm_munmap(mem, map_size);
106 TEST_ASSERT(!ret, "munmap() should succeed.");93}
94
95static void test_fault_overflow(int fd, size_t total_size)
96{
97 test_fault_sigbus(fd, total_size, total_size * 4);
98}
99
100static void test_fault_private(int fd, size_t total_size)
101{
102 test_fault_sigbus(fd, 0, total_size);
107}103}
108 104
109static void test_mmap_not_supported(int fd, size_t page_size, size_t total_size)105static void test_mmap_not_supported(int fd, size_t total_size)
110{106{
111 char *mem;107 char *mem;
112 108
@@ -117,7 +113,7 @@ static void test_mmap_not_supported(int fd, size_t page_size, size_t total_size) · 4 unmodified lines
117 TEST_ASSERT_EQ(mem, MAP_FAILED);113 TEST_ASSERT_EQ(mem, MAP_FAILED);
118}114}
119 115
120static void test_file_size(int fd, size_t page_size, size_t total_size)116static void test_file_size(int fd, size_t total_size)
121{117{
122 struct stat sb;118 struct stat sb;
123 int ret;119 int ret;
@@ -128,7 +124,7 @@ static void test_file_size(int fd, size_t page_size, size_t total_size) · 4 unmodified lines
128 TEST_ASSERT_EQ(sb.st_blksize, page_size);124 TEST_ASSERT_EQ(sb.st_blksize, page_size);
129}125}
130 126
131static void test_fallocate(int fd, size_t page_size, size_t total_size)127static void test_fallocate(int fd, size_t total_size)
132{128{
133 int ret;129 int ret;
134 130
@@ -165,7 +161,7 @@ static void test_fallocate(int fd, size_t page_size, size_t total_size) · 30 unmodified lines
165 TEST_ASSERT(!ret, "fallocate to restore punched hole should succeed");161 TEST_ASSERT(!ret, "fallocate to restore punched hole should succeed");
166}162}
167 163
168static void test_invalid_punch_hole(int fd, size_t page_size, size_t total_size)164static void test_invalid_punch_hole(int fd, size_t total_size)
169{165{
170 struct {166 struct {
171 off_t offset;167 off_t offset;
@@ -196,8 +192,7 @@ static void test_invalid_punch_hole(int fd, size_t page_size, size_t total_size) · 24 unmodified lines
196}192}
197 193
198static void test_create_guest_memfd_invalid_sizes(struct kvm_vm *vm,194static void test_create_guest_memfd_invalid_sizes(struct kvm_vm *vm,
199 uint64_t guest_memfd_flags,195 uint64_t guest_memfd_flags)
200 size_t page_size)
201{196{
202 size_t size;197 size_t size;
203 int fd;198 int fd;
@@ -214,7 +209,6 @@ static void test_create_guest_memfd_multiple(struct kvm_vm *vm) · 10 unmodified lines
214{209{
215 int fd1, fd2, ret;210 int fd1, fd2, ret;
216 struct stat st1, st2;211 struct stat st1, st2;
217 size_t page_size = getpagesize();
218 212
219 fd1 = __vm_create_guest_memfd(vm, page_size, 0);213 fd1 = __vm_create_guest_memfd(vm, page_size, 0);
220 TEST_ASSERT(fd1 != -1, "memfd creation should succeed");214 TEST_ASSERT(fd1 != -1, "memfd creation should succeed");
@@ -239,9 +233,9 @@ static void test_create_guest_memfd_multiple(struct kvm_vm *vm) · 18 unmodified lines
239 close(fd1);233 close(fd1);
240}234}
241 235
242static void test_guest_memfd_flags(struct kvm_vm *vm, uint64_t valid_flags)236static void test_guest_memfd_flags(struct kvm_vm *vm)
243{237{
244 size_t page_size = getpagesize();238 uint64_t valid_flags = vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS);
245 uint64_t flag;239 uint64_t flag;
246 int fd;240 int fd;
247 241
@@ -260,43 +254,57 @@ static void test_guest_memfd_flags(struct kvm_vm *vm, uint64_t valid_flags) · 12 unmodified lines
260 }254 }
261}255}
262 256
263static void test_guest_memfd(unsigned long vm_type)257#define gmem_test(__test, __vm, __flags) \
258do { \
259 int fd = vm_create_guest_memfd(__vm, page_size * 4, __flags); \
260 \
261 test_##__test(fd, page_size * 4); \
262 close(fd); \
263} while (0)
264
265static void __test_guest_memfd(struct kvm_vm *vm, uint64_t flags)
264{266{
265 uint64_t flags = 0;267 test_create_guest_memfd_multiple(vm);
266 struct kvm_vm *vm;268 test_create_guest_memfd_invalid_sizes(vm, flags);
267 size_t total_size;
268 size_t page_size;
269 int fd;
270 269
271 page_size = getpagesize();270 gmem_test(file_read_write, vm, flags);
272 total_size = page_size * 4;
273 271
274 vm = vm_create_barebones_type(vm_type);272 if (flags & GUEST_MEMFD_FLAG_MMAP) {
273 if (flags & GUEST_MEMFD_FLAG_INIT_SHARED) {
274 gmem_test(mmap_supported, vm, flags);
275 gmem_test(fault_overflow, vm, flags);
276 } else {
277 gmem_test(fault_private, vm, flags);
278 }
275 279
276 if (vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_MMAP))280 gmem_test(mmap_cow, vm, flags);
277 flags |= GUEST_MEMFD_FLAG_MMAP;281 } else {
282 gmem_test(mmap_not_supported, vm, flags);
283 }
278 284
279 test_create_guest_memfd_multiple(vm);285 gmem_test(file_size, vm, flags);
280 test_create_guest_memfd_invalid_sizes(vm, flags, page_size);286 gmem_test(fallocate, vm, flags);
287 gmem_test(invalid_punch_hole, vm, flags);
288}
281 289
282 fd = vm_create_guest_memfd(vm, total_size, flags);290static void test_guest_memfd(unsigned long vm_type)
291{
292 struct kvm_vm *vm = vm_create_barebones_type(vm_type);
293 uint64_t flags;
283 294
284 test_file_read_write(fd);295 test_guest_memfd_flags(vm);
285 296
286 if (flags & GUEST_MEMFD_FLAG_MMAP) {297 __test_guest_memfd(vm, 0);
287 test_mmap_supported(fd, page_size, total_size);
288 test_fault_overflow(fd, page_size, total_size);
289 } else {
290 test_mmap_not_supported(fd, page_size, total_size);
291 }
292 298
293 test_file_size(fd, page_size, total_size);299 flags = vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS);
294 test_fallocate(fd, page_size, total_size);300 if (flags & GUEST_MEMFD_FLAG_MMAP)
295 test_invalid_punch_hole(fd, page_size, total_size);301 __test_guest_memfd(vm, GUEST_MEMFD_FLAG_MMAP);
296 302
297 test_guest_memfd_flags(vm, flags);303 /* MMAP should always be supported if INIT_SHARED is supported. */
304 if (flags & GUEST_MEMFD_FLAG_INIT_SHARED)
305 __test_guest_memfd(vm, GUEST_MEMFD_FLAG_MMAP |
306 GUEST_MEMFD_FLAG_INIT_SHARED);
298 307
299 close(fd);
300 kvm_vm_free(vm);308 kvm_vm_free(vm);
301}309}
302 310
@@ -328,22 +336,26 @@ static void test_guest_memfd_guest(void) · 25 unmodified lines
328 size_t size;336 size_t size;
329 int fd, i;337 int fd, i;
330 338
331 if (!kvm_has_cap(KVM_CAP_GUEST_MEMFD_MMAP))339 if (!kvm_check_cap(KVM_CAP_GUEST_MEMFD_FLAGS))
332 return;340 return;
333 341
334 vm = __vm_create_shape_with_one_vcpu(VM_SHAPE_DEFAULT, &vcpu, 1, guest_code);342 vm = __vm_create_shape_with_one_vcpu(VM_SHAPE_DEFAULT, &vcpu, 1, guest_code);
335 343
336 TEST_ASSERT(vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_MMAP),344 TEST_ASSERT(vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS) & GUEST_MEMFD_FLAG_MMAP,
337 "Default VM type should always support guest_memfd mmap()");345 "Default VM type should support MMAP, supported flags = 0x%x",
346 vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS));
347 TEST_ASSERT(vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS) & GUEST_MEMFD_FLAG_INIT_SHARED,
348 "Default VM type should support INIT_SHARED, supported flags = 0x%x",
349 vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS));
338 350
339 size = vm->page_size;351 size = vm->page_size;
340 fd = vm_create_guest_memfd(vm, size, GUEST_MEMFD_FLAG_MMAP);352 fd = vm_create_guest_memfd(vm, size, GUEST_MEMFD_FLAG_MMAP |
353 GUEST_MEMFD_FLAG_INIT_SHARED);
341 vm_set_user_memory_region2(vm, slot, KVM_MEM_GUEST_MEMFD, gpa, size, NULL, fd, 0);354 vm_set_user_memory_region2(vm, slot, KVM_MEM_GUEST_MEMFD, gpa, size, NULL, fd, 0);
342 355
343 mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);356 mem = kvm_mmap(size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);
344 TEST_ASSERT(mem != MAP_FAILED, "mmap() on guest_memfd failed");
345 memset(mem, 0xaa, size);357 memset(mem, 0xaa, size);
346 munmap(mem, size);358 kvm_munmap(mem, size);
347 359
348 virt_pg_map(vm, gpa, gpa);360 virt_pg_map(vm, gpa, gpa);
349 vcpu_args_set(vcpu, 2, gpa, size);361 vcpu_args_set(vcpu, 2, gpa, size);
@@ -351,8 +363,7 @@ static void test_guest_memfd_guest(void) · 1 unmodified line
351 363
352 TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE);364 TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE);
353 365
354 mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);366 mem = kvm_mmap(size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);
355 TEST_ASSERT(mem != MAP_FAILED, "mmap() on guest_memfd failed");
356 for (i = 0; i < size; i++)367 for (i = 0; i < size; i++)
357 TEST_ASSERT_EQ(mem[i], 0xff);368 TEST_ASSERT_EQ(mem[i], 0xff);
358 369
@@ -366,6 +377,8 @@ int main(int argc, char *argv[]) · 7 unmodified lines
366 377
367 TEST_REQUIRE(kvm_has_cap(KVM_CAP_GUEST_MEMFD));378 TEST_REQUIRE(kvm_has_cap(KVM_CAP_GUEST_MEMFD));
368 379
380 page_size = getpagesize();
381
369 /*382 /*
370 * Not all architectures support KVM_CAP_VM_TYPES. However, those that383 * Not all architectures support KVM_CAP_VM_TYPES. However, those that
371 * support guest_memfd have that support for the default VM type.384 * support guest_memfd have that support for the default VM type.
tools/testing/selftests/kvm/include/kvm_util.h+25−0
@@ -286,6 +286,31 @@ static inline bool kvm_has_cap(long cap) · 285 unmodified lines
286#define __KVM_SYSCALL_ERROR(_name, _ret) \286#define __KVM_SYSCALL_ERROR(_name, _ret) \
287 "%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno)287 "%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno)
288 288
289static inline void *__kvm_mmap(size_t size, int prot, int flags, int fd,
290 off_t offset)
291{
292 void *mem;
293
294 mem = mmap(NULL, size, prot, flags, fd, offset);
295 TEST_ASSERT(mem != MAP_FAILED, __KVM_SYSCALL_ERROR("mmap()",
296 (int)(unsigned long)MAP_FAILED));
297
298 return mem;
299}
300
301static inline void *kvm_mmap(size_t size, int prot, int flags, int fd)
302{
303 return __kvm_mmap(size, prot, flags, fd, 0);
304}
305
306static inline void kvm_munmap(void *mem, size_t size)
307{
308 int ret;
309
310 ret = munmap(mem, size);
311 TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret));
312}
313
289/*314/*
290 * Use the "inner", double-underscore macro when reporting errors from within315 * Use the "inner", double-underscore macro when reporting errors from within
291 * other macros so that the name of ioctl() and not its literal numeric value316 * other macros so that the name of ioctl() and not its literal numeric value
tools/testing/selftests/kvm/include/test_util.h+19−0
@@ -8,6 +8,8 @@ · 7 unmodified lines
8#ifndef SELFTEST_KVM_TEST_UTIL_H8#ifndef SELFTEST_KVM_TEST_UTIL_H
9#define SELFTEST_KVM_TEST_UTIL_H9#define SELFTEST_KVM_TEST_UTIL_H
10 10
11#include <setjmp.h>
12#include <signal.h>
11#include <stdlib.h>13#include <stdlib.h>
12#include <stdarg.h>14#include <stdarg.h>
13#include <stdbool.h>15#include <stdbool.h>
@@ -78,6 +80,23 @@ do { \ · 64 unmodified lines
78 __builtin_unreachable(); \80 __builtin_unreachable(); \
79} while (0)81} while (0)
80 82
83extern sigjmp_buf expect_sigbus_jmpbuf;
84void expect_sigbus_handler(int signum);
85
86#define TEST_EXPECT_SIGBUS(action) \
87do { \
88 struct sigaction sa_old, sa_new = { \
89 .sa_handler = expect_sigbus_handler, \
90 }; \
91 \
92 sigaction(SIGBUS, &sa_new, &sa_old); \
93 if (sigsetjmp(expect_sigbus_jmpbuf, 1) == 0) { \
94 action; \
95 TEST_FAIL("'%s' should have triggered SIGBUS", #action); \
96 } \
97 sigaction(SIGBUS, &sa_old, NULL); \
98} while (0)
99
81size_t parse_size(const char *size);100size_t parse_size(const char *size);
82 101
83int64_t timespec_to_ns(struct timespec ts);102int64_t timespec_to_ns(struct timespec ts);
tools/testing/selftests/kvm/lib/kvm_util.c+15−29
@@ -741,13 +741,11 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct kvm_vcpu *vcpu) · 740 unmodified lines
741 int ret;741 int ret;
742 742
743 if (vcpu->dirty_gfns) {743 if (vcpu->dirty_gfns) {
744 ret = munmap(vcpu->dirty_gfns, vm->dirty_ring_size);744 kvm_munmap(vcpu->dirty_gfns, vm->dirty_ring_size);
745 TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret));
746 vcpu->dirty_gfns = NULL;745 vcpu->dirty_gfns = NULL;
747 }746 }
748 747
749 ret = munmap(vcpu->run, vcpu_mmap_sz());748 kvm_munmap(vcpu->run, vcpu_mmap_sz());
750 TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret));
751 749
752 ret = close(vcpu->fd);750 ret = close(vcpu->fd);
753 TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("close()", ret));751 TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("close()", ret));
@@ -783,20 +781,16 @@ void kvm_vm_release(struct kvm_vm *vmp) · 29 unmodified lines
783static void __vm_mem_region_delete(struct kvm_vm *vm,781static void __vm_mem_region_delete(struct kvm_vm *vm,
784 struct userspace_mem_region *region)782 struct userspace_mem_region *region)
785{783{
786 int ret;
787
788 rb_erase(&region->gpa_node, &vm->regions.gpa_tree);784 rb_erase(&region->gpa_node, &vm->regions.gpa_tree);
789 rb_erase(&region->hva_node, &vm->regions.hva_tree);785 rb_erase(&region->hva_node, &vm->regions.hva_tree);
790 hash_del(&region->slot_node);786 hash_del(&region->slot_node);
791 787
792 sparsebit_free(&region->unused_phy_pages);788 sparsebit_free(&region->unused_phy_pages);
793 sparsebit_free(&region->protected_phy_pages);789 sparsebit_free(&region->protected_phy_pages);
794 ret = munmap(region->mmap_start, region->mmap_size);790 kvm_munmap(region->mmap_start, region->mmap_size);
795 TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret));
796 if (region->fd >= 0) {791 if (region->fd >= 0) {
797 /* There's an extra map when using shared memory. */792 /* There's an extra map when using shared memory. */
798 ret = munmap(region->mmap_alias, region->mmap_size);793 kvm_munmap(region->mmap_alias, region->mmap_size);
799 TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret));
800 close(region->fd);794 close(region->fd);
801 }795 }
802 if (region->region.guest_memfd >= 0)796 if (region->region.guest_memfd >= 0)
@@ -1053,12 +1047,9 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, · 250 unmodified lines
1053 region->fd = kvm_memfd_alloc(region->mmap_size,1047 region->fd = kvm_memfd_alloc(region->mmap_size,
1054 src_type == VM_MEM_SRC_SHARED_HUGETLB);1048 src_type == VM_MEM_SRC_SHARED_HUGETLB);
1055 1049
1056 region->mmap_start = mmap(NULL, region->mmap_size,1050 region->mmap_start = kvm_mmap(region->mmap_size, PROT_READ | PROT_WRITE,
1057 PROT_READ | PROT_WRITE,1051 vm_mem_backing_src_alias(src_type)->flag,
1058 vm_mem_backing_src_alias(src_type)->flag,1052 region->fd);
1059 region->fd, 0);
1060 TEST_ASSERT(region->mmap_start != MAP_FAILED,
1061 __KVM_SYSCALL_ERROR("mmap()", (int)(unsigned long)MAP_FAILED));
1062 1053
1063 TEST_ASSERT(!is_backing_src_hugetlb(src_type) ||1054 TEST_ASSERT(!is_backing_src_hugetlb(src_type) ||
1064 region->mmap_start == align_ptr_up(region->mmap_start, backing_src_pagesz),1055 region->mmap_start == align_ptr_up(region->mmap_start, backing_src_pagesz),
@@ -1129,12 +1120,10 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, · 64 unmodified lines
1129 1120
1130 /* If shared memory, create an alias. */1121 /* If shared memory, create an alias. */
1131 if (region->fd >= 0) {1122 if (region->fd >= 0) {
1132 region->mmap_alias = mmap(NULL, region->mmap_size,1123 region->mmap_alias = kvm_mmap(region->mmap_size,
1133 PROT_READ | PROT_WRITE,1124 PROT_READ | PROT_WRITE,
1134 vm_mem_backing_src_alias(src_type)->flag,1125 vm_mem_backing_src_alias(src_type)->flag,
1135 region->fd, 0);1126 region->fd);
1136 TEST_ASSERT(region->mmap_alias != MAP_FAILED,
1137 __KVM_SYSCALL_ERROR("mmap()", (int)(unsigned long)MAP_FAILED));
1138 1127
1139 /* Align host alias address */1128 /* Align host alias address */
1140 region->host_alias = align_ptr_up(region->mmap_alias, alignment);1129 region->host_alias = align_ptr_up(region->mmap_alias, alignment);
@@ -1344,10 +1333,8 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id) · 203 unmodified lines
1344 TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->run), "vcpu mmap size "1333 TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->run), "vcpu mmap size "
1345 "smaller than expected, vcpu_mmap_sz: %zi expected_min: %zi",1334 "smaller than expected, vcpu_mmap_sz: %zi expected_min: %zi",
1346 vcpu_mmap_sz(), sizeof(*vcpu->run));1335 vcpu_mmap_sz(), sizeof(*vcpu->run));
1347 vcpu->run = (struct kvm_run *) mmap(NULL, vcpu_mmap_sz(),1336 vcpu->run = kvm_mmap(vcpu_mmap_sz(), PROT_READ | PROT_WRITE,
1348 PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd, 0);1337 MAP_SHARED, vcpu->fd);
1349 TEST_ASSERT(vcpu->run != MAP_FAILED,
1350 __KVM_SYSCALL_ERROR("mmap()", (int)(unsigned long)MAP_FAILED));
1351 1338
1352 if (kvm_has_cap(KVM_CAP_BINARY_STATS_FD))1339 if (kvm_has_cap(KVM_CAP_BINARY_STATS_FD))
1353 vcpu->stats.fd = vcpu_get_stats_fd(vcpu);1340 vcpu->stats.fd = vcpu_get_stats_fd(vcpu);
@@ -1794,9 +1781,8 @@ void *vcpu_map_dirty_ring(struct kvm_vcpu *vcpu) · 440 unmodified lines
1794 page_size * KVM_DIRTY_LOG_PAGE_OFFSET);1781 page_size * KVM_DIRTY_LOG_PAGE_OFFSET);
1795 TEST_ASSERT(addr == MAP_FAILED, "Dirty ring mapped exec");1782 TEST_ASSERT(addr == MAP_FAILED, "Dirty ring mapped exec");
1796 1783
1797 addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd,1784 addr = __kvm_mmap(size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd,
1798 page_size * KVM_DIRTY_LOG_PAGE_OFFSET);1785 page_size * KVM_DIRTY_LOG_PAGE_OFFSET);
1799 TEST_ASSERT(addr != MAP_FAILED, "Dirty ring map failed");
1800 1786
1801 vcpu->dirty_gfns = addr;1787 vcpu->dirty_gfns = addr;
1802 vcpu->dirty_gfns_count = size / sizeof(struct kvm_dirty_gfn);1788 vcpu->dirty_gfns_count = size / sizeof(struct kvm_dirty_gfn);
tools/testing/selftests/kvm/lib/test_util.c+7−0
@@ -18,6 +18,13 @@ · 17 unmodified lines
18 18
19#include "test_util.h"19#include "test_util.h"
20 20
21sigjmp_buf expect_sigbus_jmpbuf;
22
23void __attribute__((used)) expect_sigbus_handler(int signum)
24{
25 siglongjmp(expect_sigbus_jmpbuf, 1);
26}
27
21/*28/*
22 * Random number generator that is usable from guest code. This is the29 * Random number generator that is usable from guest code. This is the
23 * Park-Miller LCG using standard constants.30 * Park-Miller LCG using standard constants.
tools/testing/selftests/kvm/mmu_stress_test.c+2−3
@@ -339,8 +339,7 @@ int main(int argc, char *argv[]) · 338 unmodified lines
339 TEST_ASSERT(max_gpa > (4 * slot_size), "MAXPHYADDR <4gb ");339 TEST_ASSERT(max_gpa > (4 * slot_size), "MAXPHYADDR <4gb ");
340 340
341 fd = kvm_memfd_alloc(slot_size, hugepages);341 fd = kvm_memfd_alloc(slot_size, hugepages);
342 mem = mmap(NULL, slot_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);342 mem = kvm_mmap(slot_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);
343 TEST_ASSERT(mem != MAP_FAILED, "mmap() failed");
344 343
345 TEST_ASSERT(!madvise(mem, slot_size, MADV_NOHUGEPAGE), "madvise() failed");344 TEST_ASSERT(!madvise(mem, slot_size, MADV_NOHUGEPAGE), "madvise() failed");
346 345
@@ -413,7 +412,7 @@ int main(int argc, char *argv[]) · 66 unmodified lines
413 for (slot = (slot - 1) & ~1ull; slot >= first_slot; slot -= 2)412 for (slot = (slot - 1) & ~1ull; slot >= first_slot; slot -= 2)
414 vm_set_user_memory_region(vm, slot, 0, 0, 0, NULL);413 vm_set_user_memory_region(vm, slot, 0, 0, 0, NULL);
415 414
416 munmap(mem, slot_size / 2);415 kvm_munmap(mem, slot_size / 2);
417 416
418 /* Sanity check that the vCPUs actually ran. */417 /* Sanity check that the vCPUs actually ran. */
419 for (i = 0; i < nr_vcpus; i++)418 for (i = 0; i < nr_vcpus; i++)
tools/testing/selftests/kvm/pre_fault_memory_test.c+114−17
@@ -10,6 +10,7 @@ · 9 unmodified lines
10#include <test_util.h>10#include <test_util.h>
11#include <kvm_util.h>11#include <kvm_util.h>
12#include <processor.h>12#include <processor.h>
13#include <pthread.h>
13 14
14/* Arbitrarily chosen values */15/* Arbitrarily chosen values */
15#define TEST_SIZE (SZ_2M + PAGE_SIZE)16#define TEST_SIZE (SZ_2M + PAGE_SIZE)
@@ -30,18 +31,66 @@ static void guest_code(uint64_t base_gpa) · 14 unmodified lines
30 GUEST_DONE();31 GUEST_DONE();
31}32}
32 33
33static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 gpa, u64 size,34struct slot_worker_data {
34 u64 left)35 struct kvm_vm *vm;
36 u64 gpa;
37 uint32_t flags;
38 bool worker_ready;
39 bool prefault_ready;
40 bool recreate_slot;
41};
42
43static void *delete_slot_worker(void *__data)
44{
45 struct slot_worker_data *data = __data;
46 struct kvm_vm *vm = data->vm;
47
48 WRITE_ONCE(data->worker_ready, true);
49
50 while (!READ_ONCE(data->prefault_ready))
51 cpu_relax();
52
53 vm_mem_region_delete(vm, TEST_SLOT);
54
55 while (!READ_ONCE(data->recreate_slot))
56 cpu_relax();
57
58 vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, data->gpa,
59 TEST_SLOT, TEST_NPAGES, data->flags);
60
61 return NULL;
62}
63
64static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 base_gpa, u64 offset,
65 u64 size, u64 expected_left, bool private)
35{66{
36 struct kvm_pre_fault_memory range = {67 struct kvm_pre_fault_memory range = {
37 .gpa = gpa,68 .gpa = base_gpa + offset,
38 .size = size,69 .size = size,
39 .flags = 0,70 .flags = 0,
40 };71 };
41 u64 prev;72 struct slot_worker_data data = {
73 .vm = vcpu->vm,
74 .gpa = base_gpa,
75 .flags = private ? KVM_MEM_GUEST_MEMFD : 0,
76 };
77 bool slot_recreated = false;
78 pthread_t slot_worker;
42 int ret, save_errno;79 int ret, save_errno;
80 u64 prev;
81
82 /*
83 * Concurrently delete (and recreate) the slot to test KVM's handling
84 * of a racing memslot deletion with prefaulting.
85 */
86 pthread_create(&slot_worker, NULL, delete_slot_worker, &data);
43 87
44 do {88 while (!READ_ONCE(data.worker_ready))
89 cpu_relax();
90
91 WRITE_ONCE(data.prefault_ready, true);
92
93 for (;;) {
45 prev = range.size;94 prev = range.size;
46 ret = __vcpu_ioctl(vcpu, KVM_PRE_FAULT_MEMORY, &range);95 ret = __vcpu_ioctl(vcpu, KVM_PRE_FAULT_MEMORY, &range);
47 save_errno = errno;96 save_errno = errno;
@@ -49,18 +98,65 @@ static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 gpa, u64 size, · 1 unmodified line
49 "%sexpecting range.size to change on %s",98 "%sexpecting range.size to change on %s",
50 ret < 0 ? "not " : "",99 ret < 0 ? "not " : "",
51 ret < 0 ? "failure" : "success");100 ret < 0 ? "failure" : "success");
52 } while (ret >= 0 ? range.size : save_errno == EINTR);
53 101
54 TEST_ASSERT(range.size == left,102 /*
55 "Completed with %lld bytes left, expected %" PRId64,103 * Immediately retry prefaulting if KVM was interrupted by an
56 range.size, left);104 * unrelated signal/event.
105 */
106 if (ret < 0 && save_errno == EINTR)
107 continue;
108
109 /*
110 * Tell the worker to recreate the slot in order to complete
111 * prefaulting (if prefault didn't already succeed before the
112 * slot was deleted) and/or to prepare for the next testcase.
113 * Wait for the worker to exit so that the next invocation of
114 * prefaulting is guaranteed to complete (assuming no KVM bugs).
115 */
116 if (!slot_recreated) {
117 WRITE_ONCE(data.recreate_slot, true);
118 pthread_join(slot_worker, NULL);
119 slot_recreated = true;
120
121 /*
122 * Retry prefaulting to get a stable result, i.e. to
123 * avoid seeing random EAGAIN failures. Don't retry if
124 * prefaulting already succeeded, as KVM disallows
125 * prefaulting with size=0, i.e. blindly retrying would
126 * result in test failures due to EINVAL. KVM should
127 * always return success if all bytes are prefaulted,
128 * i.e. there is no need to guard against EAGAIN being
129 * returned.
130 */
131 if (range.size)
132 continue;
133 }
134
135 /*
136 * All done if there are no remaining bytes to prefault, or if
137 * prefaulting failed (EINTR was handled above, and EAGAIN due
138 * to prefaulting a memslot that's being actively deleted should
139 * be impossible since the memslot has already been recreated).
140 */
141 if (!range.size || ret < 0)
142 break;
143 }
57 144
58 if (left == 0)145 TEST_ASSERT(range.size == expected_left,
59 __TEST_ASSERT_VM_VCPU_IOCTL(!ret, "KVM_PRE_FAULT_MEMORY", ret, vcpu->vm);146 "Completed with %llu bytes left, expected %lu",
147 range.size, expected_left);
148
149 /*
150 * Assert success if prefaulting the entire range should succeed, i.e.
151 * complete with no bytes remaining. Otherwise prefaulting should have
152 * failed due to ENOENT (due to RET_PF_EMULATE for emulated MMIO when
153 * no memslot exists).
154 */
155 if (!expected_left)
156 TEST_ASSERT_VM_VCPU_IOCTL(!ret, KVM_PRE_FAULT_MEMORY, ret, vcpu->vm);
60 else157 else
61 /* No memory slot causes RET_PF_EMULATE. it results in -ENOENT. */158 TEST_ASSERT_VM_VCPU_IOCTL(ret && save_errno == ENOENT,
62 __TEST_ASSERT_VM_VCPU_IOCTL(ret && save_errno == ENOENT,159 KVM_PRE_FAULT_MEMORY, ret, vcpu->vm);
63 "KVM_PRE_FAULT_MEMORY", ret, vcpu->vm);
64}160}
65 161
66static void __test_pre_fault_memory(unsigned long vm_type, bool private)162static void __test_pre_fault_memory(unsigned long vm_type, bool private)
@@ -97,9 +193,10 @@ static void __test_pre_fault_memory(unsigned long vm_type, bool private) · 30 unmodified lines
97 193
98 if (private)194 if (private)
99 vm_mem_set_private(vm, guest_test_phys_mem, TEST_SIZE);195 vm_mem_set_private(vm, guest_test_phys_mem, TEST_SIZE);
100 pre_fault_memory(vcpu, guest_test_phys_mem, SZ_2M, 0);196
101 pre_fault_memory(vcpu, guest_test_phys_mem + SZ_2M, PAGE_SIZE * 2, PAGE_SIZE);197 pre_fault_memory(vcpu, guest_test_phys_mem, 0, SZ_2M, 0, private);
102 pre_fault_memory(vcpu, guest_test_phys_mem + TEST_SIZE, PAGE_SIZE, PAGE_SIZE);198 pre_fault_memory(vcpu, guest_test_phys_mem, SZ_2M, PAGE_SIZE * 2, PAGE_SIZE, private);
199 pre_fault_memory(vcpu, guest_test_phys_mem, TEST_SIZE, PAGE_SIZE, PAGE_SIZE, private);
103 200
104 vcpu_args_set(vcpu, 1, guest_test_virt_mem);201 vcpu_args_set(vcpu, 1, guest_test_virt_mem);
105 vcpu_run(vcpu);202 vcpu_run(vcpu);
tools/testing/selftests/kvm/s390/ucontrol_test.c+7−9
@@ -142,19 +142,17 @@ FIXTURE_SETUP(uc_kvm) · 141 unmodified lines
142 self->kvm_run_size = ioctl(self->kvm_fd, KVM_GET_VCPU_MMAP_SIZE, NULL);142 self->kvm_run_size = ioctl(self->kvm_fd, KVM_GET_VCPU_MMAP_SIZE, NULL);
143 ASSERT_GE(self->kvm_run_size, sizeof(struct kvm_run))143 ASSERT_GE(self->kvm_run_size, sizeof(struct kvm_run))
144 TH_LOG(KVM_IOCTL_ERROR(KVM_GET_VCPU_MMAP_SIZE, self->kvm_run_size));144 TH_LOG(KVM_IOCTL_ERROR(KVM_GET_VCPU_MMAP_SIZE, self->kvm_run_size));
145 self->run = (struct kvm_run *)mmap(NULL, self->kvm_run_size,145 self->run = kvm_mmap(self->kvm_run_size, PROT_READ | PROT_WRITE,
146 PROT_READ | PROT_WRITE, MAP_SHARED, self->vcpu_fd, 0);146 MAP_SHARED, self->vcpu_fd);
147 ASSERT_NE(self->run, MAP_FAILED);
148 /**147 /**
149 * For virtual cpus that have been created with S390 user controlled148 * For virtual cpus that have been created with S390 user controlled
150 * virtual machines, the resulting vcpu fd can be memory mapped at page149 * virtual machines, the resulting vcpu fd can be memory mapped at page
151 * offset KVM_S390_SIE_PAGE_OFFSET in order to obtain a memory map of150 * offset KVM_S390_SIE_PAGE_OFFSET in order to obtain a memory map of
152 * the virtual cpu's hardware control block.151 * the virtual cpu's hardware control block.
153 */152 */
154 self->sie_block = (struct kvm_s390_sie_block *)mmap(NULL, PAGE_SIZE,153 self->sie_block = __kvm_mmap(PAGE_SIZE, PROT_READ | PROT_WRITE,
155 PROT_READ | PROT_WRITE, MAP_SHARED,154 MAP_SHARED, self->vcpu_fd,
156 self->vcpu_fd, KVM_S390_SIE_PAGE_OFFSET << PAGE_SHIFT);155 KVM_S390_SIE_PAGE_OFFSET << PAGE_SHIFT);
157 ASSERT_NE(self->sie_block, MAP_FAILED);
158 156
159 TH_LOG("VM created %p %p", self->run, self->sie_block);157 TH_LOG("VM created %p %p", self->run, self->sie_block);
160 158
@@ -186,8 +184,8 @@ FIXTURE_SETUP(uc_kvm) · 25 unmodified lines
186 184
187FIXTURE_TEARDOWN(uc_kvm)185FIXTURE_TEARDOWN(uc_kvm)
188{186{
189 munmap(self->sie_block, PAGE_SIZE);187 kvm_munmap(self->sie_block, PAGE_SIZE);
190 munmap(self->run, self->kvm_run_size);188 kvm_munmap(self->run, self->kvm_run_size);
191 close(self->vcpu_fd);189 close(self->vcpu_fd);
192 close(self->vm_fd);190 close(self->vm_fd);
193 close(self->kvm_fd);191 close(self->kvm_fd);
tools/testing/selftests/kvm/set_memory_region_test.c+8−9
@@ -433,10 +433,10 @@ static void test_add_max_memory_regions(void) · 432 unmodified lines
433 pr_info("Adding slots 0..%i, each memory region with %dK size\n",433 pr_info("Adding slots 0..%i, each memory region with %dK size\n",
434 (max_mem_slots - 1), MEM_REGION_SIZE >> 10);434 (max_mem_slots - 1), MEM_REGION_SIZE >> 10);
435 435
436 mem = mmap(NULL, (size_t)max_mem_slots * MEM_REGION_SIZE + alignment,436
437 PROT_READ | PROT_WRITE,437 mem = kvm_mmap((size_t)max_mem_slots * MEM_REGION_SIZE + alignment,
438 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);438 PROT_READ | PROT_WRITE,
439 TEST_ASSERT(mem != MAP_FAILED, "Failed to mmap() host");439 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1);
440 mem_aligned = (void *)(((size_t) mem + alignment - 1) & ~(alignment - 1));440 mem_aligned = (void *)(((size_t) mem + alignment - 1) & ~(alignment - 1));
441 441
442 for (slot = 0; slot < max_mem_slots; slot++)442 for (slot = 0; slot < max_mem_slots; slot++)
@@ -446,9 +446,8 @@ static void test_add_max_memory_regions(void) · 3 unmodified lines
446 mem_aligned + (uint64_t)slot * MEM_REGION_SIZE);446 mem_aligned + (uint64_t)slot * MEM_REGION_SIZE);
447 447
448 /* Check it cannot be added memory slots beyond the limit */448 /* Check it cannot be added memory slots beyond the limit */
449 mem_extra = mmap(NULL, MEM_REGION_SIZE, PROT_READ | PROT_WRITE,449 mem_extra = kvm_mmap(MEM_REGION_SIZE, PROT_READ | PROT_WRITE,
450 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);450 MAP_PRIVATE | MAP_ANONYMOUS, -1);
451 TEST_ASSERT(mem_extra != MAP_FAILED, "Failed to mmap() host");
452 451
453 ret = __vm_set_user_memory_region(vm, max_mem_slots, 0,452 ret = __vm_set_user_memory_region(vm, max_mem_slots, 0,
454 (uint64_t)max_mem_slots * MEM_REGION_SIZE,453 (uint64_t)max_mem_slots * MEM_REGION_SIZE,
@@ -456,8 +455,8 @@ static void test_add_max_memory_regions(void) · 1 unmodified line
456 TEST_ASSERT(ret == -1 && errno == EINVAL,455 TEST_ASSERT(ret == -1 && errno == EINVAL,
457 "Adding one more memory slot should fail with EINVAL");456 "Adding one more memory slot should fail with EINVAL");
458 457
459 munmap(mem, (size_t)max_mem_slots * MEM_REGION_SIZE + alignment);458 kvm_munmap(mem, (size_t)max_mem_slots * MEM_REGION_SIZE + alignment);
460 munmap(mem_extra, MEM_REGION_SIZE);459 kvm_munmap(mem_extra, MEM_REGION_SIZE);
461 kvm_vm_free(vm);460 kvm_vm_free(vm);
462}461}
463 462
virt/kvm/Kconfig+1−0
@@ -113,6 +113,7 @@ config KVM_GENERIC_MEMORY_ATTRIBUTES · 112 unmodified lines
113 bool113 bool
114 114
115config KVM_GUEST_MEMFD115config KVM_GUEST_MEMFD
116 depends on KVM_GENERIC_MMU_NOTIFIER
116 select XARRAY_MULTI117 select XARRAY_MULTI
117 bool118 bool
118 119
virt/kvm/guest_memfd.c+49−26
@@ -102,8 +102,17 @@ static struct folio *kvm_gmem_get_folio(struct inode *inode, pgoff_t index) · 101 unmodified lines
102 return filemap_grab_folio(inode->i_mapping, index);102 return filemap_grab_folio(inode->i_mapping, index);
103}103}
104 104
105static void kvm_gmem_invalidate_begin(struct kvm_gmem *gmem, pgoff_t start,105static enum kvm_gfn_range_filter kvm_gmem_get_invalidate_filter(struct inode *inode)
106 pgoff_t end)106{
107 if ((u64)inode->i_private & GUEST_MEMFD_FLAG_INIT_SHARED)
108 return KVM_FILTER_SHARED;
109
110 return KVM_FILTER_PRIVATE;
111}
112
113static void __kvm_gmem_invalidate_begin(struct kvm_gmem *gmem, pgoff_t start,
114 pgoff_t end,
115 enum kvm_gfn_range_filter attr_filter)
107{116{
108 bool flush = false, found_memslot = false;117 bool flush = false, found_memslot = false;
109 struct kvm_memory_slot *slot;118 struct kvm_memory_slot *slot;
@@ -118,8 +127,7 @@ static void kvm_gmem_invalidate_begin(struct kvm_gmem *gmem, pgoff_t start, · 8 unmodified lines
118 .end = slot->base_gfn + min(pgoff + slot->npages, end) - pgoff,127 .end = slot->base_gfn + min(pgoff + slot->npages, end) - pgoff,
119 .slot = slot,128 .slot = slot,
120 .may_block = true,129 .may_block = true,
121 /* guest memfd is relevant to only private mappings. */130 .attr_filter = attr_filter,
122 .attr_filter = KVM_FILTER_PRIVATE,
123 };131 };
124 132
125 if (!found_memslot) {133 if (!found_memslot) {
@@ -139,8 +147,21 @@ static void kvm_gmem_invalidate_begin(struct kvm_gmem *gmem, pgoff_t start, · 13 unmodified lines
139 KVM_MMU_UNLOCK(kvm);147 KVM_MMU_UNLOCK(kvm);
140}148}
141 149
142static void kvm_gmem_invalidate_end(struct kvm_gmem *gmem, pgoff_t start,150static void kvm_gmem_invalidate_begin(struct inode *inode, pgoff_t start,
143 pgoff_t end)151 pgoff_t end)
152{
153 struct list_head *gmem_list = &inode->i_mapping->i_private_list;
154 enum kvm_gfn_range_filter attr_filter;
155 struct kvm_gmem *gmem;
156
157 attr_filter = kvm_gmem_get_invalidate_filter(inode);
158
159 list_for_each_entry(gmem, gmem_list, entry)
160 __kvm_gmem_invalidate_begin(gmem, start, end, attr_filter);
161}
162
163static void __kvm_gmem_invalidate_end(struct kvm_gmem *gmem, pgoff_t start,
164 pgoff_t end)
144{165{
145 struct kvm *kvm = gmem->kvm;166 struct kvm *kvm = gmem->kvm;
146 167
@@ -151,12 +172,20 @@ static void kvm_gmem_invalidate_end(struct kvm_gmem *gmem, pgoff_t start, · 4 unmodified lines
151 }172 }
152}173}
153 174
154static long kvm_gmem_punch_hole(struct inode *inode, loff_t offset, loff_t len)175static void kvm_gmem_invalidate_end(struct inode *inode, pgoff_t start,
176 pgoff_t end)
155{177{
156 struct list_head *gmem_list = &inode->i_mapping->i_private_list;178 struct list_head *gmem_list = &inode->i_mapping->i_private_list;
179 struct kvm_gmem *gmem;
180
181 list_for_each_entry(gmem, gmem_list, entry)
182 __kvm_gmem_invalidate_end(gmem, start, end);
183}
184
185static long kvm_gmem_punch_hole(struct inode *inode, loff_t offset, loff_t len)
186{
157 pgoff_t start = offset >> PAGE_SHIFT;187 pgoff_t start = offset >> PAGE_SHIFT;
158 pgoff_t end = (offset + len) >> PAGE_SHIFT;188 pgoff_t end = (offset + len) >> PAGE_SHIFT;
159 struct kvm_gmem *gmem;
160 189
161 /*190 /*
162 * Bindings must be stable across invalidation to ensure the start+end191 * Bindings must be stable across invalidation to ensure the start+end
@@ -164,13 +193,11 @@ static long kvm_gmem_punch_hole(struct inode *inode, loff_t offset, loff_t len) · 1 unmodified line
164 */193 */
165 filemap_invalidate_lock(inode->i_mapping);194 filemap_invalidate_lock(inode->i_mapping);
166 195
167 list_for_each_entry(gmem, gmem_list, entry)196 kvm_gmem_invalidate_begin(inode, start, end);
168 kvm_gmem_invalidate_begin(gmem, start, end);
169 197
170 truncate_inode_pages_range(inode->i_mapping, offset, offset + len - 1);198 truncate_inode_pages_range(inode->i_mapping, offset, offset + len - 1);
171 199
172 list_for_each_entry(gmem, gmem_list, entry)200 kvm_gmem_invalidate_end(inode, start, end);
173 kvm_gmem_invalidate_end(gmem, start, end);
174 201
175 filemap_invalidate_unlock(inode->i_mapping);202 filemap_invalidate_unlock(inode->i_mapping);
176 203
@@ -280,8 +307,9 @@ static int kvm_gmem_release(struct inode *inode, struct file *file) · 103 unmodified lines
280 * Zap all SPTEs pointed at by this file. Do not free the backing307 * Zap all SPTEs pointed at by this file. Do not free the backing
281 * memory, as its lifetime is associated with the inode, not the file.308 * memory, as its lifetime is associated with the inode, not the file.
282 */309 */
283 kvm_gmem_invalidate_begin(gmem, 0, -1ul);310 __kvm_gmem_invalidate_begin(gmem, 0, -1ul,
284 kvm_gmem_invalidate_end(gmem, 0, -1ul);311 kvm_gmem_get_invalidate_filter(inode));
312 __kvm_gmem_invalidate_end(gmem, 0, -1ul);
285 313
286 list_del(&gmem->entry);314 list_del(&gmem->entry);
287 315
@@ -328,6 +356,9 @@ static vm_fault_t kvm_gmem_fault_user_mapping(struct vm_fault *vmf) · 40 unmodified lines
328 if (((loff_t)vmf->pgoff << PAGE_SHIFT) >= i_size_read(inode))356 if (((loff_t)vmf->pgoff << PAGE_SHIFT) >= i_size_read(inode))
329 return VM_FAULT_SIGBUS;357 return VM_FAULT_SIGBUS;
330 358
359 if (!((u64)inode->i_private & GUEST_MEMFD_FLAG_INIT_SHARED))
360 return VM_FAULT_SIGBUS;
361
331 folio = kvm_gmem_get_folio(inode, vmf->pgoff);362 folio = kvm_gmem_get_folio(inode, vmf->pgoff);
332 if (IS_ERR(folio)) {363 if (IS_ERR(folio)) {
333 int err = PTR_ERR(folio);364 int err = PTR_ERR(folio);
@@ -400,8 +431,6 @@ static int kvm_gmem_migrate_folio(struct address_space *mapping, · 66 unmodified lines
400 431
401static int kvm_gmem_error_folio(struct address_space *mapping, struct folio *folio)432static int kvm_gmem_error_folio(struct address_space *mapping, struct folio *folio)
402{433{
403 struct list_head *gmem_list = &mapping->i_private_list;
404 struct kvm_gmem *gmem;
405 pgoff_t start, end;434 pgoff_t start, end;
406 435
407 filemap_invalidate_lock_shared(mapping);436 filemap_invalidate_lock_shared(mapping);
@@ -409,8 +438,7 @@ static int kvm_gmem_error_folio(struct address_space *mapping, struct folio *fol · 1 unmodified line
409 start = folio->index;438 start = folio->index;
410 end = start + folio_nr_pages(folio);439 end = start + folio_nr_pages(folio);
411 440
412 list_for_each_entry(gmem, gmem_list, entry)441 kvm_gmem_invalidate_begin(mapping->host, start, end);
413 kvm_gmem_invalidate_begin(gmem, start, end);
414 442
415 /*443 /*
416 * Do not truncate the range, what action is taken in response to the444 * Do not truncate the range, what action is taken in response to the
@@ -421,8 +449,7 @@ static int kvm_gmem_error_folio(struct address_space *mapping, struct folio *fol · 4 unmodified lines
421 * error to userspace.449 * error to userspace.
422 */450 */
423 451
424 list_for_each_entry(gmem, gmem_list, entry)452 kvm_gmem_invalidate_end(mapping->host, start, end);
425 kvm_gmem_invalidate_end(gmem, start, end);
426 453
427 filemap_invalidate_unlock_shared(mapping);454 filemap_invalidate_unlock_shared(mapping);
428 455
@@ -458,7 +485,7 @@ static const struct inode_operations kvm_gmem_iops = { · 29 unmodified lines
458 .setattr = kvm_gmem_setattr,485 .setattr = kvm_gmem_setattr,
459};486};
460 487
461bool __weak kvm_arch_supports_gmem_mmap(struct kvm *kvm)488bool __weak kvm_arch_supports_gmem_init_shared(struct kvm *kvm)
462{489{
463 return true;490 return true;
464}491}
@@ -522,12 +549,8 @@ int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args) · 57 unmodified lines
522{549{
523 loff_t size = args->size;550 loff_t size = args->size;
524 u64 flags = args->flags;551 u64 flags = args->flags;
525 u64 valid_flags = 0;
526
527 if (kvm_arch_supports_gmem_mmap(kvm))
528 valid_flags |= GUEST_MEMFD_FLAG_MMAP;
529 552
530 if (flags & ~valid_flags)553 if (flags & ~kvm_gmem_get_supported_flags(kvm))
531 return -EINVAL;554 return -EINVAL;
532 555
533 if (size <= 0 || !PAGE_ALIGNED(size))556 if (size <= 0 || !PAGE_ALIGNED(size))
virt/kvm/kvm_main.c+2−2
@@ -4928,8 +4928,8 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg) · 4927 unmodified lines
4928#ifdef CONFIG_KVM_GUEST_MEMFD4928#ifdef CONFIG_KVM_GUEST_MEMFD
4929 case KVM_CAP_GUEST_MEMFD:4929 case KVM_CAP_GUEST_MEMFD:
4930 return 1;4930 return 1;
4931 case KVM_CAP_GUEST_MEMFD_MMAP:4931 case KVM_CAP_GUEST_MEMFD_FLAGS:
4932 return !kvm || kvm_arch_supports_gmem_mmap(kvm);4932 return kvm_gmem_get_supported_flags(kvm);
4933#endif4933#endif
4934 default:4934 default:
4935 break;4935 break;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t