summaryrefslogtreecommitdiffstats
path: root/drivers/kvm
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-06-05 12:17:03 +0300
committerAvi Kivity <avi@qumranet.com>2007-07-16 12:05:45 +0300
commit7b53aa56508479507c6e5667bb252ca7c2cd19cf (patch)
treed2020d70e6578f0d6405cba3f3b5a1ccdc62a581 /drivers/kvm
parent313899477f7578d37e82ead1af10f794a6da3c90 (diff)
downloadlinux-7b53aa56508479507c6e5667bb252ca7c2cd19cf.tar.gz
linux-7b53aa56508479507c6e5667bb252ca7c2cd19cf.tar.bz2
linux-7b53aa56508479507c6e5667bb252ca7c2cd19cf.zip
KVM: Fix vcpu freeing for guest smp
A vcpu can pin up to four mmu shadow pages, which means the freeing loop will never terminate. Fix by first unpinning shadow pages on all vcpus, then freeing shadow pages. Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm')
-rw-r--r--drivers/kvm/kvm_main.c15
-rw-r--r--drivers/kvm/mmu.c4
2 files changed, 17 insertions, 2 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 3c3231d8dabf..3ff8ee56279c 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -381,6 +381,16 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
}
}
+static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
+{
+ if (!vcpu->vmcs)
+ return;
+
+ vcpu_load(vcpu);
+ kvm_mmu_unload(vcpu);
+ vcpu_put(vcpu);
+}
+
static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
{
if (!vcpu->vmcs)
@@ -401,6 +411,11 @@ static void kvm_free_vcpus(struct kvm *kvm)
{
unsigned int i;
+ /*
+ * Unpin any mmu pages first.
+ */
+ for (i = 0; i < KVM_MAX_VCPUS; ++i)
+ kvm_unload_vcpu_mmu(&kvm->vcpus[i]);
for (i = 0; i < KVM_MAX_VCPUS; ++i)
kvm_free_vcpu(&kvm->vcpus[i]);
}
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 5915d7a1c4f7..d4de988d1828 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -838,11 +838,12 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
int i;
struct kvm_mmu_page *page;
+ if (!VALID_PAGE(vcpu->mmu.root_hpa))
+ return;
#ifdef CONFIG_X86_64
if (vcpu->mmu.shadow_root_level == PT64_ROOT_LEVEL) {
hpa_t root = vcpu->mmu.root_hpa;
- ASSERT(VALID_PAGE(root));
page = page_header(root);
--page->root_count;
vcpu->mmu.root_hpa = INVALID_PAGE;
@@ -853,7 +854,6 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
hpa_t root = vcpu->mmu.pae_root[i];
if (root) {
- ASSERT(VALID_PAGE(root));
root &= PT64_BASE_ADDR_MASK;
page = page_header(root);
--page->root_count;