KVM: MMU: optimize pte write path if don't have protected sp
PATCH v2 1/7 KVM: MMU: optimize pte write path if don't have protected sp
Simply return from kvm_mmu_pte_write path if no shadow page is write-protected, then we can avoid to walk all shadow pages and hold mmu-lock
--- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/mmu.c | 9 +++++++++ 2 files changed, 10 insertions(+), 0 deletions(-)
arch/x86/include/asm/kvm_host.h +1 -0
@@ -441,6 +441,7 @@ struct kvm_arch {unsigned int n_used_mmu_pages;unsigned int n_requested_mmu_pages;unsigned int n_max_mmu_pages; +unsigned int indirect_shadow_pages;atomic_t invlpg_counter;struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES ];/*
arch/x86/kvm/mmu.c +9 -0
@@ -498,6 +498,7 @@ static void account_shadowed(struct kvm *kvm, gfn_t gfn) linfo =lpage_info_slot (gfn, slot, i); linfo->write_count +=1 ; } + kvm->arch.indirect_shadow_pages++; }static void unaccount_shadowed (struct kvm *kvm,gfn_t gfn)
@@ -513,6 +514,7 @@ static void unaccount_shadowed(struct kvm *kvm, gfn_t gfn) linfo->write_count -=1 ;WARN_ON (linfo->write_count <0 ); } + kvm->arch.indirect_shadow_pages--; } static int has_wrprotected_page(struct kvm *kvm,
@@ -3233,6 +3235,13 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,int level, npte, invlpg_counter, r, flooded =0 ;bool remote_flush, local_flush, zap_page; +/* +* If we don't have indirect shadow pages, it means no page is +* write-protected, so we can exit simply. +*/ +if (!ACCESS_ONCE (vcpu->kvm->arch.indirect_shadow_pages)) +return ; + zap_page = remote_flush = local_flush = false; offset =offset_in_page (gpa);
Signature · 1 line
1.7.4.4
PATCH v2 2/7 KVM: use __copy_to_user/__clear_user to write guest page
Simply use __copy_to_user/__clear_user to write guest page since we have already verified the user address when the memslot is set
--- arch/x86/kvm/x86.c | 4 ++-- virt/kvm/kvm_main.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
arch/x86/kvm/x86.c +2 -2
@@ -1388,7 +1388,7 @@ static int set_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data)return 1 ; kvm_x86_ops->patch_hypercall (vcpu, instructions); ((unsigned char *)instructions)[3 ] =0xc3 ;/* ret */ -if (copy_to_user ((void __user *)addr, instructions,4 )) +if (__copy_to_user ((void __user *)addr, instructions,4 ))return 1 ; kvm->arch.hv_hypercall = data;break ;
@@ -1415,7 +1415,7 @@ static int set_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 data) HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT);if (kvm_is_error_hva (addr))return 1 ; -if (clear_user ((void __user *)addr,PAGE_SIZE )) +if (__clear_user ((void __user *)addr,PAGE_SIZE ))return 1 ; vcpu->arch.hv_vapic = data;break ;
virt/kvm/kvm_main.c +2 -2
@@ -1342,7 +1342,7 @@ int kvm_write_guest_page(struct kvm *kvm, gfn_t gfn, const void *data, addr =gfn_to_hva (kvm, gfn);if (kvm_is_error_hva (addr))return -EFAULT ; - r =copy_to_user ((void __user *)addr + offset, data, len); + r =__copy_to_user ((void __user *)addr + offset, data, len);if (r)return -EFAULT ;mark_page_dirty (kvm, gfn);
@@ -1402,7 +1402,7 @@ int kvm_write_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,if (kvm_is_error_hva (ghc->hva))return -EFAULT ; - r =copy_to_user ((void __user *)ghc->hva, data, len); + r =__copy_to_user ((void __user *)ghc->hva, data, len);if (r)return -EFAULT ;mark_page_dirty_in_slot (kvm, ghc->memslot, ghc->gpa >>PAGE_SHIFT );
Signature · 1 line
1.7.4.4
PATCH v2 3/7 KVM: fix uninitialized warning
In reply to Xiao GuangrongFix:
warning: ‘cs_sel’ may be used uninitialized in this function
warning: ‘ss_sel’ may be used uninitialized in this function
--- arch/x86/kvm/emulate.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86/kvm/emulate.c +1 -1
@@ -2015,7 +2015,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)struct desc_struct cs, ss;u64 msr_data;int usermode; -u16 cs_sel, ss_sel; +u16 cs_sel =0 , ss_sel =0 ;/* inject #GP if in real mode or Virtual 8086 mode */ if (ctxt->mode == X86EMUL_MODE_REAL ||
Signature · 1 line
1.7.4.4
PATCH v2 4/7 KVM: MMU: abstract the operation of rmap
In reply to Xiao GuangrongAbstract the operation of rmap to spte_list, then we can use it for the reverse mapping of parent pte in the later patch
--- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/mmu.c | 260 +++++++++++++++++++++------------------ 2 files changed, 140 insertions(+), 122 deletions(-)
arch/x86/include/asm/kvm_host.h +1 -1
@@ -347,7 +347,7 @@ struct kvm_vcpu_arch {struct kvm_pv_mmu_op_buffer mmu_op_buffer;struct kvm_mmu_memory_cache mmu_pte_chain_cache; -struct kvm_mmu_memory_cache mmu_rmap_desc_cache; +struct kvm_mmu_memory_cache mmu_pte_list_desc_cache;struct kvm_mmu_memory_cache mmu_page_cache;struct kvm_mmu_memory_cache mmu_page_header_cache;
arch/x86/kvm/mmu.c +139 -121
380 lines not on this page · raw message
Signature · 1 line
1.7.4.4
PATCH v2 5/7 KVM: MMU: remove the arithmetic of parent pte rmap
In reply to Xiao GuangrongParent pte rmap and page rmap are very similar, so use the same arithmetic for them
--- arch/x86/include/asm/kvm_host.h | 7 +-- arch/x86/kvm/mmu.c | 189 +++++++++----------------------------- 2 files changed, 46 insertions(+), 150 deletions(-)
arch/x86/include/asm/kvm_host.h +1 -6
@@ -227,14 +227,10 @@ struct kvm_mmu_page {* in this shadow page. */ DECLARE_BITMAP (slot_bitmap,KVM_MEMORY_SLOTS +KVM_PRIVATE_MEM_SLOTS ); -bool multimapped;/* More than one parent_pte? */ bool unsync;int root_count;/* Currently serving as active root */ unsigned int unsync_children; -union { -u64 *parent_pte;/* !multimapped */ -struct hlist_head parent_ptes;/* multimapped, kvm_pte_chain */ - }; +unsigned long parent_ptes;/* Reverse mapping for parent_pte */ DECLARE_BITMAP (unsync_child_bitmap,512 ); };
@@ -346,7 +342,6 @@ struct kvm_vcpu_arch {* put it here to avoid allocation */ struct kvm_pv_mmu_op_buffer mmu_op_buffer; -struct kvm_mmu_memory_cache mmu_pte_chain_cache;struct kvm_mmu_memory_cache mmu_pte_list_desc_cache;struct kvm_mmu_memory_cache mmu_page_cache;struct kvm_mmu_memory_cache mmu_page_header_cache;
arch/x86/kvm/mmu.c +45 -144
267 lines not on this page · raw message
Signature · 1 line
1.7.4.4
PATCH v2 6/7 KVM: MMU: cleanup for kvm_mmu_page_unlink_children
In reply to Xiao GuangrongCleanup the same operation between kvm_mmu_page_unlink_children and mmu_pte_write_zap_pte
--- arch/x86/kvm/mmu.c | 66 ++++++++++++++++++--------------------------------- 1 files changed, 23 insertions(+), 43 deletions(-)
arch/x86/kvm/mmu.c +23 -43
@@ -1566,32 +1566,33 @@ static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep, } } +static void mmu_page_zap_pte (struct kvm *kvm,struct kvm_mmu_page *sp, +u64 *spte) +{ +u64 pte; +struct kvm_mmu_page *child; + + pte = *spte; +if (is_shadow_present_pte (pte)) { +if (is_last_spte (pte, sp->role.level)) +drop_spte (kvm, spte, shadow_trap_nonpresent_pte); +else { + child =page_header (pte &PT64_BASE_ADDR_MASK ); +mmu_page_remove_parent_pte (child, spte); + } + } +__set_spte (spte, shadow_trap_nonpresent_pte); +if (is_large_pte (pte)) + --kvm->stat.lpages; +} +static void kvm_mmu_page_unlink_children (struct kvm *kvm,struct kvm_mmu_page *sp) {unsigned i; -u64 *pt; -u64 ent; - - pt = sp->spt; -for (i =0 ; i <PT64_ENT_PER_PAGE ; ++i) { - ent = pt[i]; - -if (is_shadow_present_pte (ent)) { -if (!is_last_spte (ent, sp->role.level)) { - ent &=PT64_BASE_ADDR_MASK ; -mmu_page_remove_parent_pte (page_header (ent), - &pt[i]); - }else { -if (is_large_pte (ent)) - --kvm->stat.lpages; -drop_spte (kvm, &pt[i], - shadow_trap_nonpresent_pte); - } - } - pt[i] = shadow_trap_nonpresent_pte; - } +for (i =0 ; i <PT64_ENT_PER_PAGE ; ++i) +mmu_page_zap_pte (kvm, sp, sp->spt + i); }static void kvm_mmu_put_page (struct kvm_mmu_page *sp,u64 *parent_pte)
@@ -3069,27 +3070,6 @@ void kvm_mmu_unload(struct kvm_vcpu *vcpu) }EXPORT_SYMBOL_GPL (kvm_mmu_unload); -static void mmu_pte_write_zap_pte (struct kvm_vcpu *vcpu, -struct kvm_mmu_page *sp, -u64 *spte) -{ -u64 pte; -struct kvm_mmu_page *child; - - pte = *spte; -if (is_shadow_present_pte (pte)) { -if (is_last_spte (pte, sp->role.level)) -drop_spte (vcpu->kvm, spte, shadow_trap_nonpresent_pte); -else { - child =page_header (pte &PT64_BASE_ADDR_MASK ); -mmu_page_remove_parent_pte (child, spte); - } - } -__set_spte (spte, shadow_trap_nonpresent_pte); -if (is_large_pte (pte)) - --vcpu->kvm->stat.lpages; -} -static void mmu_pte_write_new_pte (struct kvm_vcpu *vcpu,struct kvm_mmu_page *sp,u64 *spte,const void *new)
@@ -3271,7 +3251,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, spte = &sp->spt[page_offset /sizeof (*spte)];while (npte--) { entry = *spte; -mmu_pte_write_zap_pte (vcpu, sp, spte); +mmu_page_zap_pte (vcpu->kvm, sp, spte);if (gentry && !((sp->role.word ^ vcpu->arch.mmu.base_role.word) & mask.word))
Signature · 1 line
1.7.4.4
PATCH v2 7/7 KVM: MMU: cleanup for dropping parent pte
In reply to Xiao GuangrongIntroduce drop_parent_pte to remove the rmap of parent pte and clear parent pte
--- arch/x86/kvm/mmu.c | 21 ++++++++++++--------- 1 files changed, 12 insertions(+), 9 deletions(-)
arch/x86/kvm/mmu.c +12 -9
@@ -1084,6 +1084,13 @@ static void mmu_page_remove_parent_pte(struct kvm_mmu_page *sp,pte_list_remove (parent_pte, &sp->parent_ptes); } +static void drop_parent_pte (struct kvm_mmu_page *sp, +u64 *parent_pte) +{ +mmu_page_remove_parent_pte (sp, parent_pte); +__set_spte (parent_pte, shadow_trap_nonpresent_pte); +} +static struct kvm_mmu_page *kvm_mmu_alloc_page (struct kvm_vcpu *vcpu,u64 *parent_pte,int direct) {
@@ -1560,8 +1567,7 @@ static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep,if (child->role.access == direct_access)return ; -mmu_page_remove_parent_pte (child, sptep); -__set_spte (sptep, shadow_trap_nonpresent_pte); +drop_parent_pte (child, sptep);kvm_flush_remote_tlbs (vcpu->kvm); } }
@@ -1578,7 +1584,7 @@ static void mmu_page_zap_pte(struct kvm *kvm, struct kvm_mmu_page *sp,drop_spte (kvm, spte, shadow_trap_nonpresent_pte); else { child =page_header (pte &PT64_BASE_ADDR_MASK ); -mmu_page_remove_parent_pte (child, spte); +drop_parent_pte (child, spte); } }__set_spte (spte, shadow_trap_nonpresent_pte);
@@ -1613,10 +1619,8 @@ static void kvm_mmu_unlink_parents(struct kvm *kvm, struct kvm_mmu_page *sp) {u64 *parent_pte; -while ((parent_pte =pte_list_next (&sp->parent_ptes,NULL ))) { -kvm_mmu_put_page (sp, parent_pte); -__set_spte (parent_pte, shadow_trap_nonpresent_pte); - } +while ((parent_pte =pte_list_next (&sp->parent_ptes,NULL ))) +drop_parent_pte (sp, parent_pte); } static int mmu_zap_unsync_children(struct kvm *kvm,
@@ -2046,8 +2050,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,u64 pte = *sptep; child =page_header (pte &PT64_BASE_ADDR_MASK ); -mmu_page_remove_parent_pte (child, sptep); -__set_spte (sptep, shadow_trap_nonpresent_pte); +drop_parent_pte (child, sptep);kvm_flush_remote_tlbs (vcpu->kvm); }else if (pfn !=spte_to_pfn (*sptep)) { pgprintk("hfn old %llx new %llx\n",
Signature · 1 line
1.7.4.4
Quoted 3 lines · Xiao Guangrong
Simply return from
kvm_mmu_pte_writepath if no shadow page is write-protected, then we can avoid to walk all shadow pages and hold mmu-lock
Patchset looks like a very good cleanup (plus the nice optimization in patch 1).
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 7 lines · Avi Kivity
Quoted 3 lines · Xiao Guangrong
Simply return from
kvm_mmu_pte_writepath if no shadow page is write-protected, then we can avoid to walk all shadow pages and hold mmu-lockPatchset looks like a very good cleanup (plus the nice optimization in patch 1).
What case is patch 1 optimizing for?
Quoted 11 lines · Marcelo Tosatti
Quoted 7 lines · Avi Kivity
Quoted 3 lines · Xiao Guangrong
Simply return from
kvm_mmu_pte_writepath if no shadow page is write-protected, then we can avoid to walk all shadow pages and hold mmu-lockPatchset looks like a very good cleanup (plus the nice optimization in patch 1).
What case is patch 1 optimizing for?
Say, kvmclock updates.
Signature · 1 line
error compiling committee.c: too many arguments to function
Marcelo Tosatti
AppliedQuoted 5 lines · Xiao Guangrong
Simply return from
kvm_mmu_pte_writepath if no shadow page is write-protected, then we can avoid to walk all shadow pages and hold mmu-lockSigned-off-by Xiao Guangrong <[email protected]>
Applied, thanks.