Re: [PATCH 4/4] KVM: MMU: cleanup update_pte, pte_prefetch andsync_page functions

From: Marcelo Tosatti
Date: Tue Nov 16 2010 - 15:53:07 EST


On Fri, Nov 12, 2010 at 06:35:38PM +0800, Xiao Guangrong wrote:
> Some operation of these functions is very similar, so introduce a
> common function to cleanup them
>
> Signed-off-by: Xiao Guangrong <xiaoguangrong@xxxxxxxxxxxxxx>
> ---
> arch/x86/kvm/mmu.c | 3 -
> arch/x86/kvm/paging_tmpl.h | 191 ++++++++++++++++++++++++-------------------
> 2 files changed, 107 insertions(+), 87 deletions(-)

This makes the code more complicated and error prone IMO, because there
are specialities of

> diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
> index 94d157f..d0bcca2 100644
> --- a/arch/x86/kvm/mmu.c
> +++ b/arch/x86/kvm/mmu.c
> @@ -3108,9 +3108,6 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
> return;
> }
>
> - if (is_rsvd_bits_set(&vcpu->arch.mmu, *(u64 *)new, PT_PAGE_TABLE_LEVEL))
> - return;
> -
> ++vcpu->kvm->stat.mmu_pte_updated;
> if (!sp->role.cr4_pae)
> paging32_update_pte(vcpu, sp, spte, new);
> diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
> index 952357a..1a1a0b9 100644
> --- a/arch/x86/kvm/paging_tmpl.h
> +++ b/arch/x86/kvm/paging_tmpl.h
> @@ -299,42 +299,90 @@ static int FNAME(walk_addr_nested)(struct guest_walker *walker,
> addr, access);
> }
>
> -static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
> - u64 *spte, const void *pte)
> +static bool FNAME(fetch_guest_pte)(struct kvm_vcpu *vcpu,
> + struct kvm_mmu_page *sp, u64 *spte,
> + bool clear_unsync, pt_element_t gpte,
> + pfn_t (get_pfn)(struct kvm_vcpu *, u64 *,
> + pt_element_t, unsigned, bool *))
> {
> - pt_element_t gpte;
> unsigned pte_access;
> + u64 nonpresent = shadow_trap_nonpresent_pte;
> + gfn_t gfn;
> pfn_t pfn;
> - u64 new_spte;
> + bool dirty, host_writeable;
>
> - gpte = *(const pt_element_t *)pte;
> - if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) {
> - if (!is_present_gpte(gpte)) {
> - if (sp->unsync)
> - new_spte = shadow_trap_nonpresent_pte;
> - else
> - new_spte = shadow_notrap_nonpresent_pte;
> - __set_spte(spte, new_spte);
> - }
> - return;
> + if (!is_present_gpte(gpte) ||
> + is_rsvd_bits_set(&vcpu->arch.mmu, gpte, PT_PAGE_TABLE_LEVEL)) {
> + if (!sp->unsync && !clear_unsync)
> + nonpresent = shadow_notrap_nonpresent_pte;
> + goto no_present;
> }
> - pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
> +
> + if (!(gpte & PT_ACCESSED_MASK))
> + goto no_present;
> +
> pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
> + gfn = gpte_to_gfn(gpte);
> + dirty = is_dirty_gpte(gpte);
> + pfn = get_pfn(vcpu, spte, gpte, pte_access, &host_writeable);
> +
> + if (is_error_pfn(pfn))
> + goto no_present;
> +
> + if (!host_writeable)
> + pte_access &= ~ACC_WRITE_MASK;
> +
> + if (spte_to_pfn(*spte) == pfn)
> + set_spte(vcpu, spte, pte_access, 0, 0,
> + dirty, PT_PAGE_TABLE_LEVEL, gfn,
> + pfn, true, false, host_writeable);
> + else
> + mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0,
> + dirty, NULL, PT_PAGE_TABLE_LEVEL, gfn,
> + pfn, true, host_writeable);

For example, the update path should always go through mmu_set_spte to
update last_pte_updated, last_pte_gfn.

Also the callbacks make it harder to read the code. Maybe the
unification works if you use common functions for common parts.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/