[patch 04/13] KVM: MMU: switch prefetch_page to gfn_to_page_atomic

Marcelo Tosatti
2008-09-06T19:27:08Z

[-- Attachment #1: prefetch-page-use-gfn-to-page-atomic --]
[-- Type: text/plain, Size: 1796 bytes --]

Close to 50% improvement for prefetch_page.

Index: kvm/arch/x86/kvm/paging_tmpl.h
===================================================================
--- kvm.orig/arch/x86/kvm/paging_tmpl.h
+++ kvm/arch/x86/kvm/paging_tmpl.h
@@ -477,9 +477,10 @@ static gpa_t FNAME(gva_to_gpa)(struct kv
static void FNAME(prefetch_page)(struct kvm_vcpu *vcpu,
struct kvm_mmu_page *sp)
{
- int i, j, offset, r;
- pt_element_t pt[256 / sizeof(pt_element_t)];
- gpa_t pte_gpa;
+ int i;
+ struct page *page;
+ pt_element_t *pt;
+ void *gpte_kaddr;

if (sp->role.metaphysical
|| (PTTYPE == 32 && sp->role.level > PT_PAGE_TABLE_LEVEL)) {
@@ -487,21 +488,26 @@ static void FNAME(prefetch_page)(struct
return;
}

- pte_gpa = gfn_to_gpa(sp->gfn);
- if (PTTYPE == 32) {
- offset = sp->role.quadrant << PT64_LEVEL_BITS;
- pte_gpa += offset * sizeof(pt_element_t);
+ page = gfn_to_page_atomic(vcpu->kvm, sp->gfn);
+ if (is_error_page(page)) {
+ nonpaging_prefetch_page(vcpu, sp);
+ kvm_release_page_clean(page);
+ return;
}
+ gpte_kaddr = pt = kmap_atomic(page, KM_USER0);
+
+ if (PTTYPE == 32)
+ pt += sp->role.quadrant << PT64_LEVEL_BITS;

- for (i = 0; i < PT64_ENT_PER_PAGE; i += ARRAY_SIZE(pt)) {
- r = kvm_read_guest_atomic(vcpu->kvm, pte_gpa, pt, sizeof pt);
- pte_gpa += ARRAY_SIZE(pt) * sizeof(pt_element_t);
- for (j = 0; j < ARRAY_SIZE(pt); ++j)
- if (r || is_present_pte(pt[j]))
- sp->spt[i+j] = shadow_trap_nonpresent_pte;
- else
- sp->spt[i+j] = shadow_notrap_nonpresent_pte;
+ for (i = 0; i < PT64_ENT_PER_PAGE; i++) {
+ if (is_present_pte(*pt))
+ sp->spt[i] = shadow_trap_nonpresent_pte;
+ else
+ sp->spt[i] = shadow_notrap_nonpresent_pte;
+ pt++;
}
+ kunmap_atomic(gpte_kaddr, KM_USER0);
+ kvm_release_page_clean(page);
}

#undef pt_element_t

--