From bacd64eb0068d729ce68bbab731bfb1d6ec3d3c6 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti <mtosatti@redhat.com> Date: Mon, 13 Jul 2009 17:15:53 -0300 Subject: [PATCH] KVM: fix missing locking in alloc_mmu_pages n_requested_mmu_pages/n_free_mmu_pages are used by kvm_mmu_change_mmu_pages to calculate the number of pages to zap. alloc_mmu_pages, called from the vcpu initialization path, modifies this variables without proper locking, which can result in a negative value in kvm_mmu_change_mmu_pages (say, with cpu hotplug). Also free_mmu_pages should only touch vcpu local data (this is already fixed upstream). Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Bugzilla: 510770 Bugzilla: 505629 Message-ID: <20090713201553.GA14136@amt.cnet> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> Acked-by: Izik Eidus <ieidus@redhat.com> Acked-by: Juan Quintela <quintela@redhat.com> Acked-by: john cooper <john.cooper@redhat.com> Acked-by: Gleb Natapov <gleb@redhat.com> --- arch/x86/kvm/mmu.c | 14 ++++++++++---- arch/x86/kvm/mmu.h | 2 ++ arch/x86/kvm/x86.c | 1 + 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 6c1d15f..c58076d 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -2760,16 +2760,20 @@ void kvm_disable_tdp(void) } EXPORT_SYMBOL_GPL(kvm_disable_tdp); -static void free_mmu_pages(struct kvm_vcpu *vcpu) +void kvm_mmu_free_all(struct kvm *kvm) { struct kvm_mmu_page *sp; - while (!list_empty(&vcpu->kvm->arch.active_mmu_pages)) { - sp = container_of(vcpu->kvm->arch.active_mmu_pages.next, + while (!list_empty(&kvm->arch.active_mmu_pages)) { + sp = container_of(kvm->arch.active_mmu_pages.next, struct kvm_mmu_page, link); - kvm_mmu_zap_page(vcpu->kvm, sp); + kvm_mmu_zap_page(kvm, sp); cond_resched(); } +} + +static void free_mmu_pages(struct kvm_vcpu *vcpu) +{ free_page((unsigned long)vcpu->arch.mmu.pae_root); } @@ -2780,12 +2784,14 @@ static int alloc_mmu_pages(struct kvm_vcpu *vcpu) ASSERT(vcpu); + spin_lock(&vcpu->kvm->mmu_lock); if (vcpu->kvm->arch.n_requested_mmu_pages) vcpu->kvm->arch.n_free_mmu_pages = vcpu->kvm->arch.n_requested_mmu_pages; else vcpu->kvm->arch.n_free_mmu_pages = vcpu->kvm->arch.n_alloc_mmu_pages; + spin_unlock(&vcpu->kvm->mmu_lock); /* * When emulating 32-bit mode, cr3 is only 32 bits even on x86_64. * Therefore we need to allocate shadow page tables in the first diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index eaab214..7beb917 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -37,6 +37,8 @@ #define PT32_ROOT_LEVEL 2 #define PT32E_ROOT_LEVEL 3 +void kvm_mmu_free_all(struct kvm *kvm); + static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) { if (unlikely(vcpu->kvm->arch.n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES)) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ad7d148..f69c19b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4304,6 +4304,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) kfree(kvm->arch.vpic); kfree(kvm->arch.vioapic); kvm_free_vcpus(kvm); + kvm_mmu_free_all(kvm); kvm_free_physmem(kvm); if (kvm->arch.apic_access_page) put_page(kvm->arch.apic_access_page); -- 1.6.3.rc4.29.g8146