From patchwork Mon Mar 16 10:45:26 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Avi Kivity X-Patchwork-Id: 12385 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n2GAjjkR020858 for ; Mon, 16 Mar 2009 10:45:45 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753215AbZCPKpp (ORCPT ); Mon, 16 Mar 2009 06:45:45 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752618AbZCPKpp (ORCPT ); Mon, 16 Mar 2009 06:45:45 -0400 Received: from mx2.redhat.com ([66.187.237.31]:40779 "EHLO mx2.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751835AbZCPKpo (ORCPT ); Mon, 16 Mar 2009 06:45:44 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n2GAjhZ4017108 for ; Mon, 16 Mar 2009 06:45:43 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n2GAjhrd007920; Mon, 16 Mar 2009 06:45:43 -0400 Received: from cleopatra.tlv.redhat.com (cleopatra.tlv.redhat.com [10.35.255.11]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n2GAjfGP004948; Mon, 16 Mar 2009 06:45:42 -0400 Received: from localhost.localdomain (cleopatra.tlv.redhat.com [10.35.255.11]) by cleopatra.tlv.redhat.com (Postfix) with ESMTP id 9FE7CA0117; Mon, 16 Mar 2009 12:45:26 +0200 (IST) From: Avi Kivity To: Andrea Arcangeli , Marcelo Tosatti Cc: kvm@vger.kernel.org Subject: [PATCH] KVM: Defer remote tlb flushes on invlpg Date: Mon, 16 Mar 2009 12:45:26 +0200 Message-Id: <1237200326-1651-1-git-send-email-avi@redhat.com> X-Scanned-By: MIMEDefang 2.58 on 172.16.27.26 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org KVM flushes tlbs on remote cpus for two purposes: to protect guest pages that it needs to collect information about, and to prevent stale tlb entries from pointing to pages that no longer belong to the guest. We can defer the latter flushes to the point when we actually free the pages, which is during an mmu notifier invocation. To this end, we add a new state remote_tlbs_dirty which marks whether the guest tlb might be inconsistent with the the shadow page tables. Whenever we do a conditional flush of remote tlbs, we check this state, and if the remote tlbs are dirty we flush them to ensure no inconsistency. Signed-off-by: Avi Kivity --- arch/x86/include/asm/kvm_host.h | 1 - arch/x86/kvm/mmu.c | 4 ++-- arch/x86/kvm/paging_tmpl.h | 6 ++++-- include/linux/kvm_host.h | 1 + virt/kvm/kvm_main.c | 8 ++++++-- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 4627627..eb1ab29 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -383,7 +383,6 @@ struct kvm_mem_alias { struct kvm_arch{ int naliases; struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS]; - unsigned int n_free_mmu_pages; unsigned int n_requested_mmu_pages; unsigned int n_alloc_mmu_pages; diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 2a36f7f..a10c96b 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -675,7 +675,7 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn) spte = rmap_next(kvm, rmapp, spte); } - return write_protected; + return write_protected || kvm->remote_tlbs_dirty; } static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp) @@ -690,7 +690,7 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp) set_shadow_pte(spte, shadow_trap_nonpresent_pte); need_tlb_flush = 1; } - return need_tlb_flush; + return need_tlb_flush || kvm->remote_tlbs_dirty; } static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 855eb71..18abdf9 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -475,8 +475,10 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) break; } - if (need_flush) - kvm_flush_remote_tlbs(vcpu->kvm); + if (need_flush) { + vcpu->kvm->remote_tlbs_dirty = true; + kvm_x86_ops->tlb_flush(vcpu); + } spin_unlock(&vcpu->kvm->mmu_lock); if (pte_gpa == -1) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 11eb702..e7813bd 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -125,6 +125,7 @@ struct kvm_kernel_irq_routing_entry { struct kvm { struct mutex lock; /* protects the vcpus array and APIC accesses */ spinlock_t mmu_lock; + bool remote_tlbs_dirty; struct rw_semaphore slots_lock; struct mm_struct *mm; /* userspace tied to this vm */ int nmemslots; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 68b217e..8b48891 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -758,6 +758,8 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req) void kvm_flush_remote_tlbs(struct kvm *kvm) { + kvm->remote_tlbs_dirty = false; + wmb(); if (make_all_cpus_request(kvm, KVM_REQ_TLB_FLUSH)) ++kvm->stat.remote_tlb_flush; } @@ -840,8 +842,9 @@ static void kvm_mmu_notifier_invalidate_page(struct mmu_notifier *mn, need_tlb_flush = kvm_unmap_hva(kvm, address); spin_unlock(&kvm->mmu_lock); + rmb(); /* we've to flush the tlb before the pages can be freed */ - if (need_tlb_flush) + if (need_tlb_flush || kvm->remote_tlbs_dirty) kvm_flush_remote_tlbs(kvm); } @@ -865,8 +868,9 @@ static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, need_tlb_flush |= kvm_unmap_hva(kvm, start); spin_unlock(&kvm->mmu_lock); + rmb(); /* we've to flush the tlb before the pages can be freed */ - if (need_tlb_flush) + if (need_tlb_flush || kvm->remote_tlbs_dirty) kvm_flush_remote_tlbs(kvm); }