Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af585b92 authored by Gleb Natapov's avatar Gleb Natapov Committed by Avi Kivity
Browse files

KVM: Halt vcpu if page it tries to access is swapped out



If a guest accesses swapped out memory do not swap it in from vcpu thread
context. Schedule work to do swapping and put vcpu into halted state
instead.

Interrupts will still be delivered to the guest and if interrupt will
cause reschedule guest will continue to run another task.

[avi: remove call to get_user_pages_noio(), nacked by Linus; this
      makes everything synchrnous again]

Acked-by: default avatarRik van Riel <riel@redhat.com>
Signed-off-by: default avatarGleb Natapov <gleb@redhat.com>
Signed-off-by: default avatarMarcelo Tosatti <mtosatti@redhat.com>
parent 010c520e
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -83,11 +83,14 @@
#define KVM_NR_FIXED_MTRR_REGION 88
#define KVM_NR_VAR_MTRR 8

#define ASYNC_PF_PER_VCPU 64

extern spinlock_t kvm_lock;
extern struct list_head vm_list;

struct kvm_vcpu;
struct kvm;
struct kvm_async_pf;

enum kvm_reg {
	VCPU_REGS_RAX = 0,
@@ -412,6 +415,11 @@ struct kvm_vcpu_arch {
	u64 hv_vapic;

	cpumask_var_t wbinvd_dirty_mask;

	struct {
		bool halted;
		gfn_t gfns[roundup_pow_of_two(ASYNC_PF_PER_VCPU)];
	} apf;
};

struct kvm_arch {
@@ -585,6 +593,10 @@ struct kvm_x86_ops {
	const struct trace_print_flags *exit_reasons_str;
};

struct kvm_arch_async_pf {
	gfn_t gfn;
};

extern struct kvm_x86_ops *kvm_x86_ops;

int kvm_mmu_module_init(void);
@@ -799,4 +811,10 @@ void kvm_set_shared_msr(unsigned index, u64 val, u64 mask);

bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip);

void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
				     struct kvm_async_pf *work);
void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
				 struct kvm_async_pf *work);
extern bool kvm_find_async_pf_gfn(struct kvm_vcpu *vcpu, gfn_t gfn);

#endif /* _ASM_X86_KVM_HOST_H */
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ config KVM
	select HAVE_KVM_IRQCHIP
	select HAVE_KVM_EVENTFD
	select KVM_APIC_ARCHITECTURE
	select KVM_ASYNC_PF
	select USER_RETURN_NOTIFIER
	select KVM_MMIO
	---help---
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ kvm-y += $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \
				coalesced_mmio.o irq_comm.o eventfd.o \
				assigned-dev.o)
kvm-$(CONFIG_IOMMU_API)	+= $(addprefix ../../../virt/kvm/, iommu.o)
kvm-$(CONFIG_KVM_ASYNC_PF)	+= $(addprefix ../../../virt/kvm/, async_pf.o)

kvm-y			+= x86.o mmu.o emulate.o i8259.o irq.o lapic.o \
			   i8254.o timer.o
+51 −1
Original line number Diff line number Diff line
@@ -18,9 +18,11 @@
 *
 */

#include "irq.h"
#include "mmu.h"
#include "x86.h"
#include "kvm_cache_regs.h"
#include "x86.h"

#include <linux/kvm_host.h>
#include <linux/types.h>
@@ -2587,6 +2589,50 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
			     error_code & PFERR_WRITE_MASK, gfn);
}

int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn)
{
	struct kvm_arch_async_pf arch;
	arch.gfn = gfn;

	return kvm_setup_async_pf(vcpu, gva, gfn, &arch);
}

static bool can_do_async_pf(struct kvm_vcpu *vcpu)
{
	if (unlikely(!irqchip_in_kernel(vcpu->kvm) ||
		     kvm_event_needs_reinjection(vcpu)))
		return false;

	return kvm_x86_ops->interrupt_allowed(vcpu);
}

static bool try_async_pf(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gva,
			 pfn_t *pfn)
{
	bool async;

	*pfn = gfn_to_pfn_async(vcpu->kvm, gfn, &async);

	if (!async)
		return false; /* *pfn has correct page already */

	put_page(pfn_to_page(*pfn));

	if (can_do_async_pf(vcpu)) {
		trace_kvm_try_async_get_page(async, *pfn);
		if (kvm_find_async_pf_gfn(vcpu, gfn)) {
			trace_kvm_async_pf_doublefault(gva, gfn);
			kvm_make_request(KVM_REQ_APF_HALT, vcpu);
			return true;
		} else if (kvm_arch_setup_async_pf(vcpu, gva, gfn))
			return true;
	}

	*pfn = gfn_to_pfn(vcpu->kvm, gfn);

	return false;
}

static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa,
				u32 error_code)
{
@@ -2609,7 +2655,11 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa,

	mmu_seq = vcpu->kvm->mmu_notifier_seq;
	smp_rmb();
	pfn = gfn_to_pfn(vcpu->kvm, gfn);

	if (try_async_pf(vcpu, gfn, gpa, &pfn))
		return 0;

	/* mmio */
	if (is_error_pfn(pfn))
		return kvm_handle_bad_page(vcpu->kvm, gfn, pfn);
	spin_lock(&vcpu->kvm->mmu_lock);
+3 −1
Original line number Diff line number Diff line
@@ -568,7 +568,9 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,

	mmu_seq = vcpu->kvm->mmu_notifier_seq;
	smp_rmb();
	pfn = gfn_to_pfn(vcpu->kvm, walker.gfn);

	if (try_async_pf(vcpu, walker.gfn, addr, &pfn))
		return 0;

	/* mmio */
	if (is_error_pfn(pfn))
Loading