From patchwork Tue Aug 4 12:17:18 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcelo Tosatti X-Patchwork-Id: 39102 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 n74CINjU005126 for ; Tue, 4 Aug 2009 12:18:23 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755079AbZHDMSU (ORCPT ); Tue, 4 Aug 2009 08:18:20 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1754999AbZHDMSU (ORCPT ); Tue, 4 Aug 2009 08:18:20 -0400 Received: from mx2.redhat.com ([66.187.237.31]:33671 "EHLO mx2.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754726AbZHDMSU (ORCPT ); Tue, 4 Aug 2009 08:18:20 -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 n74CILM9001060 for ; Tue, 4 Aug 2009 08:18:21 -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 n74CIKB0001364; Tue, 4 Aug 2009 08:18:20 -0400 Received: from amt.cnet (vpn-10-29.str.redhat.com [10.32.10.29]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n74CIIwJ021409; Tue, 4 Aug 2009 08:18:19 -0400 Received: from amt.cnet (amt.cnet [127.0.0.1]) by amt.cnet (Postfix) with ESMTP id 786C65580E7; Tue, 4 Aug 2009 09:17:20 -0300 (BRT) Received: (from marcelo@localhost) by amt.cnet (8.14.3/8.14.3/Submit) id n74CHIwE018537; Tue, 4 Aug 2009 09:17:18 -0300 Date: Tue, 4 Aug 2009 09:17:18 -0300 From: Marcelo Tosatti To: kvm , Avi Kivity Subject: KVM: MMU: limit rmap chain length Message-ID: <20090804121718.GA18476@amt.cnet> References: <20090728024019.GA26080@amt.cnet> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20090728024019.GA26080@amt.cnet> User-Agent: Mutt/1.5.19 (2009-01-05) 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 Otherwise the host can spend too long traversing an rmap chain, which happens under a spinlock. Cc: stable@kernel.org Signed-off-by: Marcelo Tosatti --- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 24e4188..08b6d98 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -550,16 +550,19 @@ static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int level) * * If rmapp bit zero is one, (then rmap & ~1) points to a struct kvm_rmap_desc * containing more mappings. + * + * Returns the number of rmap entries before the spte was added or zero if + * the spte was not added. */ -static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) +static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) { struct kvm_mmu_page *sp; struct kvm_rmap_desc *desc; unsigned long *rmapp; - int i; + int i, count = 0; if (!is_rmap_spte(*spte)) - return; + return count; gfn = unalias_gfn(vcpu->kvm, gfn); sp = page_header(__pa(spte)); sp->gfns[spte - sp->spt] = gfn; @@ -576,8 +579,10 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) } else { rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte); desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul); - while (desc->sptes[RMAP_EXT-1] && desc->more) + while (desc->sptes[RMAP_EXT-1] && desc->more) { desc = desc->more; + count += RMAP_EXT; + } if (desc->sptes[RMAP_EXT-1]) { desc->more = mmu_alloc_rmap_desc(vcpu); desc = desc->more; @@ -586,6 +591,7 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) ; desc->sptes[i] = spte; } + return count; } static void rmap_desc_remove_entry(unsigned long *rmapp, @@ -822,6 +828,22 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp) return young; } +#define RMAP_RECYCLE_THRESHOLD 1000 + +static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) +{ + unsigned long *rmapp; + struct kvm_mmu_page *sp; + + sp = page_header(__pa(spte)); + + gfn = unalias_gfn(vcpu->kvm, gfn); + rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level); + + kvm_unmap_rmapp(vcpu->kvm, rmapp); + kvm_flush_remote_tlbs(vcpu->kvm); +} + int kvm_age_hva(struct kvm *kvm, unsigned long hva) { return kvm_handle_hva(kvm, hva, kvm_age_rmapp); @@ -1809,6 +1831,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, { int was_rmapped = 0; int was_writeble = is_writeble_pte(*sptep); + int rmap_count; pgprintk("%s: spte %llx access %x write_fault %d" " user_fault %d gfn %lx\n", @@ -1852,9 +1875,11 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, page_header_update_slot(vcpu->kvm, sptep, gfn); if (!was_rmapped) { - rmap_add(vcpu, sptep, gfn); + rmap_count = rmap_add(vcpu, sptep, gfn); if (!is_rmap_spte(*sptep)) kvm_release_pfn_clean(pfn); + if (rmap_count > RMAP_RECYCLE_THRESHOLD) + rmap_recycle(vcpu, sptep, gfn); } else { if (was_writeble) kvm_release_pfn_dirty(pfn);