On Thu, Sep 13, 2012 at 6:19 AM, Marc Zyngier <marc.zyngier@xxxxxxx> wrote: > On 13/09/12 05:09, Christoffer Dall wrote: >> When we take a write fault on an existing page mapped read-only in the >> guest, we need to make sure that a another guest CPU does not access a >> page that got freed on the host, so we need to get a reference for the >> existing read-only page until the TLB is flushed and the stage-2 table >> is updated. >> >> Also flushes the TLB when updating an existing present pte entry. >> >> Signed-off-by: Christoffer Dall <c.dall@xxxxxxxxxxxxxxxxxxxxxx> >> --- >> arch/arm/kvm/mmu.c | 44 +++++++++++++++++++++++++++++++------------- >> 1 file changed, 31 insertions(+), 13 deletions(-) >> >> diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c >> index 0c45cc2..e741d1d 100644 >> --- a/arch/arm/kvm/mmu.c >> +++ b/arch/arm/kvm/mmu.c >> @@ -420,7 +420,7 @@ static void stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, >> pgd_t *pgd; >> pud_t *pud; >> pmd_t *pmd; >> - pte_t *pte; >> + pte_t *pte, old_pte; >> >> /* Create 2nd stage page table mapping - Level 1 */ >> pgd = kvm->arch.pgd + pgd_index(addr); >> @@ -448,9 +448,11 @@ static void stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, >> pte = pte_offset_kernel(pmd, addr); >> >> /* Create 2nd stage page table mapping - Level 3 */ >> - BUG_ON(pte_none(pte)); >> + old_pte = *pte; >> set_pte_ext(pte, *new_pte, 0); >> get_page(virt_to_page(pte)); >> + if (pte_present(old_pte)) >> + __kvm_tlb_flush_vmid(kvm); > > Hmmm. If we're updating the pte, the ref-count must stay the same. Here, > you're leaking the pte page. > > nice catch, this should fix it: commit 9bb29b91b4b7111b8afbe49a74e3e59e25d31b54 Author: Christoffer Dall <c.dall@xxxxxxxxxxxxxxxxxxxxxx> Date: Thu Sep 13 11:28:23 2012 -0400 fixup! KVM: ARM: Fix race condition in guest fault handling diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index e395055..b7d8f93 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -450,9 +450,10 @@ static void stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, /* Create 2nd stage page table mapping - Level 3 */ old_pte = *pte; set_pte_ext(pte, *new_pte, 0); - get_page(virt_to_page(pte)); if (pte_present(old_pte)) __kvm_tlb_flush_vmid(kvm); + else + get_page(virt_to_page(pte)); } /** _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm