Re: [PATCH v3 10/11] KVM: MMU: clear write-flooding on the fast path of tracked page

From: Paolo Bonzini
Date: Fri Feb 19 2016 - 06:55:24 EST




On 14/02/2016 12:31, Xiao Guangrong wrote:
> If the page fault is caused by write access on write tracked page, the
> real shadow page walking is skipped, we lost the chance to clear write
> flooding for the page structure current vcpu is using
>
> Fix it by locklessly waking shadow page table to clear write flooding
> on the shadow page structure out of mmu-lock. So that we change the
> count to atomic_t

Should this be moved earlier in the series, so that the issue never
surfaces?

Paolo

> Signed-off-by: Xiao Guangrong <guangrong.xiao@xxxxxxxxxxxxxxx>
> ---
> arch/x86/include/asm/kvm_host.h | 2 +-
> arch/x86/kvm/mmu.c | 22 ++++++++++++++++++++--
> arch/x86/kvm/paging_tmpl.h | 4 +++-
> 3 files changed, 24 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 282bc2f..254d103 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -277,7 +277,7 @@ struct kvm_mmu_page {
> #endif
>
> /* Number of writes since the last time traversal visited this page. */
> - int write_flooding_count;
> + atomic_t write_flooding_count;
> };
>
> struct kvm_pio_request {
> diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
> index 4986615..f924e6c 100644
> --- a/arch/x86/kvm/mmu.c
> +++ b/arch/x86/kvm/mmu.c
> @@ -2073,7 +2073,7 @@ static void mmu_sync_children(struct kvm_vcpu *vcpu,
>
> static void __clear_sp_write_flooding_count(struct kvm_mmu_page *sp)
> {
> - sp->write_flooding_count = 0;
> + atomic_set(&sp->write_flooding_count, 0);
> }
>
> static void clear_sp_write_flooding_count(u64 *spte)
> @@ -3407,6 +3407,23 @@ static bool page_fault_handle_page_track(struct kvm_vcpu *vcpu,
> return false;
> }
>
> +static void shadow_page_table_clear_flood(struct kvm_vcpu *vcpu, gva_t addr)
> +{
> + struct kvm_shadow_walk_iterator iterator;
> + u64 spte;
> +
> + if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
> + return;
> +
> + walk_shadow_page_lockless_begin(vcpu);
> + for_each_shadow_entry_lockless(vcpu, addr, iterator, spte) {
> + clear_sp_write_flooding_count(iterator.sptep);
> + if (!is_shadow_present_pte(spte))
> + break;
> + }
> + walk_shadow_page_lockless_end(vcpu);
> +}
> +
> static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
> u32 error_code, bool prefault)
> {
> @@ -4236,7 +4253,8 @@ static bool detect_write_flooding(struct kvm_mmu_page *sp)
> if (sp->role.level == PT_PAGE_TABLE_LEVEL)
> return false;
>
> - return ++sp->write_flooding_count >= 3;
> + atomic_inc(&sp->write_flooding_count);
> + return atomic_read(&sp->write_flooding_count) >= 3;
> }
>
> /*
> diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
> index c3a30c2..5985156 100644
> --- a/arch/x86/kvm/paging_tmpl.h
> +++ b/arch/x86/kvm/paging_tmpl.h
> @@ -735,8 +735,10 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
> return 0;
> }
>
> - if (page_fault_handle_page_track(vcpu, error_code, walker.gfn))
> + if (page_fault_handle_page_track(vcpu, error_code, walker.gfn)) {
> + shadow_page_table_clear_flood(vcpu, addr);
> return 1;
> + }
>
> vcpu->arch.write_fault_to_shadow_pgtable = false;
>
>