Skip to content

Commit bc1a5cd

Browse files
yamahatabonzini
authored andcommitted
KVM: Add KVM_PRE_FAULT_MEMORY vcpu ioctl to pre-populate guest memory
Add a new ioctl KVM_PRE_FAULT_MEMORY in the KVM common code. It iterates on the memory range and calls the arch-specific function. The implementation is optional and enabled by a Kconfig symbol. Suggested-by: Sean Christopherson <[email protected]> Signed-off-by: Isaku Yamahata <[email protected]> Reviewed-by: Rick Edgecombe <[email protected]> Message-ID: <819322b8f25971f2b9933bfa4506e618508ad782.1712785629.git.isaku.yamahata@intel.com> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 9aed7a6 commit bc1a5cd

File tree

4 files changed

+78
-0
lines changed

4 files changed

+78
-0
lines changed

include/linux/kvm_host.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2477,4 +2477,9 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t gfn, void __user *src, long npages
24772477
void kvm_arch_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end);
24782478
#endif
24792479

2480+
#ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY
2481+
long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,
2482+
struct kvm_pre_fault_memory *range);
2483+
#endif
2484+
24802485
#endif

include/uapi/linux/kvm.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,7 @@ struct kvm_enable_cap {
917917
#define KVM_CAP_MEMORY_ATTRIBUTES 233
918918
#define KVM_CAP_GUEST_MEMFD 234
919919
#define KVM_CAP_VM_TYPES 235
920+
#define KVM_CAP_PRE_FAULT_MEMORY 236
920921

921922
struct kvm_irq_routing_irqchip {
922923
__u32 irqchip;
@@ -1548,4 +1549,13 @@ struct kvm_create_guest_memfd {
15481549
__u64 reserved[6];
15491550
};
15501551

1552+
#define KVM_PRE_FAULT_MEMORY _IOWR(KVMIO, 0xd5, struct kvm_pre_fault_memory)
1553+
1554+
struct kvm_pre_fault_memory {
1555+
__u64 gpa;
1556+
__u64 size;
1557+
__u64 flags;
1558+
__u64 padding[5];
1559+
};
1560+
15511561
#endif /* __LINUX_KVM_H */

virt/kvm/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ config HAVE_KVM_INVALID_WAKEUPS
6767
config KVM_GENERIC_DIRTYLOG_READ_PROTECT
6868
bool
6969

70+
config KVM_GENERIC_PRE_FAULT_MEMORY
71+
bool
72+
7073
config KVM_COMPAT
7174
def_bool y
7275
depends on KVM && COMPAT && !(S390 || ARM64 || RISCV)

virt/kvm/kvm_main.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4373,6 +4373,52 @@ static int kvm_vcpu_ioctl_get_stats_fd(struct kvm_vcpu *vcpu)
43734373
return fd;
43744374
}
43754375

4376+
#ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY
4377+
static int kvm_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,
4378+
struct kvm_pre_fault_memory *range)
4379+
{
4380+
int idx;
4381+
long r;
4382+
u64 full_size;
4383+
4384+
if (range->flags)
4385+
return -EINVAL;
4386+
4387+
if (!PAGE_ALIGNED(range->gpa) ||
4388+
!PAGE_ALIGNED(range->size) ||
4389+
range->gpa + range->size <= range->gpa)
4390+
return -EINVAL;
4391+
4392+
vcpu_load(vcpu);
4393+
idx = srcu_read_lock(&vcpu->kvm->srcu);
4394+
4395+
full_size = range->size;
4396+
do {
4397+
if (signal_pending(current)) {
4398+
r = -EINTR;
4399+
break;
4400+
}
4401+
4402+
r = kvm_arch_vcpu_pre_fault_memory(vcpu, range);
4403+
if (WARN_ON_ONCE(r == 0 || r == -EIO))
4404+
break;
4405+
4406+
if (r < 0)
4407+
break;
4408+
4409+
range->size -= r;
4410+
range->gpa += r;
4411+
cond_resched();
4412+
} while (range->size);
4413+
4414+
srcu_read_unlock(&vcpu->kvm->srcu, idx);
4415+
vcpu_put(vcpu);
4416+
4417+
/* Return success if at least one page was mapped successfully. */
4418+
return full_size == range->size ? r : 0;
4419+
}
4420+
#endif
4421+
43764422
static long kvm_vcpu_ioctl(struct file *filp,
43774423
unsigned int ioctl, unsigned long arg)
43784424
{
@@ -4573,6 +4619,20 @@ static long kvm_vcpu_ioctl(struct file *filp,
45734619
r = kvm_vcpu_ioctl_get_stats_fd(vcpu);
45744620
break;
45754621
}
4622+
#ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY
4623+
case KVM_PRE_FAULT_MEMORY: {
4624+
struct kvm_pre_fault_memory range;
4625+
4626+
r = -EFAULT;
4627+
if (copy_from_user(&range, argp, sizeof(range)))
4628+
break;
4629+
r = kvm_vcpu_pre_fault_memory(vcpu, &range);
4630+
/* Pass back leftover range. */
4631+
if (copy_to_user(argp, &range, sizeof(range)))
4632+
r = -EFAULT;
4633+
break;
4634+
}
4635+
#endif
45764636
default:
45774637
r = kvm_arch_vcpu_ioctl(filp, ioctl, arg);
45784638
}

0 commit comments

Comments
 (0)