invlpg only need update unsync page, sp->unsync and sp->unsync_children can help us to find it Now, a gfn may have many shadow pages, when one sp need be synced, we write protect sp->gfn and sync this sp but we keep other shadow pages asynchronous So, while gfn happen page fault, let it not touch unsync page, the unsync page only updated at invlpg/flush TLB time Signed-off-by: Xiao Guangrong <xiaoguangrong@xxxxxxxxxxxxxx> --- arch/x86/kvm/mmu.c | 3 ++- arch/x86/kvm/paging_tmpl.h | 23 +++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index add4658..3886207 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -2697,7 +2697,8 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, restart: hlist_for_each_entry_safe(sp, node, n, bucket, hash_link) { - if (sp->gfn != gfn || sp->role.direct || sp->role.invalid) + if (sp->gfn != gfn || sp->role.direct || sp->role.invalid || + sp->unsync) continue; pte_size = sp->role.cr4_pae ? 8 : 4; misaligned = (offset ^ (offset + bytes - 1)) & ~(pte_size - 1); diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 38b4d23..b4fb737 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -474,16 +474,16 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) level = iterator.level; sptep = iterator.sptep; + sp = page_header(__pa(sptep)); if (is_last_spte(*sptep, level)) { - sp = page_header(__pa(sptep)); - - if (PTTYPE == 32) { - if (level == PT_DIRECTORY_LEVEL) - offset = PAGE_SHIFT - 4; - else - offset = PT64_LEVEL_BITS; - offset = sp->role.quadrant << offset; - } + if (!sp->unsync) + break; + + WARN_ON(level != PT_PAGE_TABLE_LEVEL); + + if (PTTYPE == 32) + offset = sp->role.quadrant << PT64_LEVEL_BITS; + gfn = sp->gfn; offset = (sptep - sp->spt + offset) * sizeof(pt_element_t); @@ -498,7 +498,7 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) break; } - if (!is_shadow_present_pte(*sptep)) + if (!is_shadow_present_pte(*sptep) || !sp->unsync_children) break; } @@ -520,8 +520,7 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) mmu_guess_page_from_pte_write(vcpu, gfn_to_gpa(gfn) + offset, gentry); spin_lock(&vcpu->kvm->mmu_lock); - if (atomic_read(&vcpu->kvm->arch.invlpg_counter) == invlpg_counter && - sp->role.level == PT_PAGE_TABLE_LEVEL) { + if (atomic_read(&vcpu->kvm->arch.invlpg_counter) == invlpg_counter) { ++vcpu->kvm->stat.mmu_pte_updated; FNAME(update_pte)(vcpu, sp, sptep, &gentry); } -- 1.6.1.2 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html