diff options
author | Marcelo Tosatti <mtosatti@redhat.com> | 2008-09-16 19:54:47 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2008-10-15 08:25:06 -0400 |
commit | 4c2155ce81c193788082d4b8cdbc26d79edebc58 (patch) | |
tree | 5c028fe4a18c55b5c0e9c4e80be459dad3f96da7 /arch | |
parent | 777b3f49d297e387866604093b635e5bc9b9d2a6 (diff) |
KVM: switch to get_user_pages_fast
Convert gfn_to_pfn to use get_user_pages_fast, which can do lockless
pagetable lookups on x86. Kernel compilation on 4-way guest is 3.7%
faster on VMX.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/kvm/44x_tlb.c | 2 | ||||
-rw-r--r-- | arch/x86/kvm/mmu.c | 23 | ||||
-rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 8 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 4 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 6 |
5 files changed, 10 insertions, 33 deletions
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c index 7b11fd7be542..2e227a412bc2 100644 --- a/arch/powerpc/kvm/44x_tlb.c +++ b/arch/powerpc/kvm/44x_tlb.c | |||
@@ -147,9 +147,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid, | |||
147 | stlbe = &vcpu->arch.shadow_tlb[victim]; | 147 | stlbe = &vcpu->arch.shadow_tlb[victim]; |
148 | 148 | ||
149 | /* Get reference to new page. */ | 149 | /* Get reference to new page. */ |
150 | down_read(¤t->mm->mmap_sem); | ||
151 | new_page = gfn_to_page(vcpu->kvm, gfn); | 150 | new_page = gfn_to_page(vcpu->kvm, gfn); |
152 | up_read(¤t->mm->mmap_sem); | ||
153 | if (is_error_page(new_page)) { | 151 | if (is_error_page(new_page)) { |
154 | printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n", gfn); | 152 | printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n", gfn); |
155 | kvm_release_page_clean(new_page); | 153 | kvm_release_page_clean(new_page); |
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index bce3e25ec79b..5779a2323e23 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -405,16 +405,19 @@ static int host_largepage_backed(struct kvm *kvm, gfn_t gfn) | |||
405 | { | 405 | { |
406 | struct vm_area_struct *vma; | 406 | struct vm_area_struct *vma; |
407 | unsigned long addr; | 407 | unsigned long addr; |
408 | int ret = 0; | ||
408 | 409 | ||
409 | addr = gfn_to_hva(kvm, gfn); | 410 | addr = gfn_to_hva(kvm, gfn); |
410 | if (kvm_is_error_hva(addr)) | 411 | if (kvm_is_error_hva(addr)) |
411 | return 0; | 412 | return ret; |
412 | 413 | ||
414 | down_read(¤t->mm->mmap_sem); | ||
413 | vma = find_vma(current->mm, addr); | 415 | vma = find_vma(current->mm, addr); |
414 | if (vma && is_vm_hugetlb_page(vma)) | 416 | if (vma && is_vm_hugetlb_page(vma)) |
415 | return 1; | 417 | ret = 1; |
418 | up_read(¤t->mm->mmap_sem); | ||
416 | 419 | ||
417 | return 0; | 420 | return ret; |
418 | } | 421 | } |
419 | 422 | ||
420 | static int is_largepage_backed(struct kvm_vcpu *vcpu, gfn_t large_gfn) | 423 | static int is_largepage_backed(struct kvm_vcpu *vcpu, gfn_t large_gfn) |
@@ -1140,9 +1143,7 @@ struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva) | |||
1140 | if (gpa == UNMAPPED_GVA) | 1143 | if (gpa == UNMAPPED_GVA) |
1141 | return NULL; | 1144 | return NULL; |
1142 | 1145 | ||
1143 | down_read(¤t->mm->mmap_sem); | ||
1144 | page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); | 1146 | page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); |
1145 | up_read(¤t->mm->mmap_sem); | ||
1146 | 1147 | ||
1147 | return page; | 1148 | return page; |
1148 | } | 1149 | } |
@@ -1330,16 +1331,14 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) | |||
1330 | pfn_t pfn; | 1331 | pfn_t pfn; |
1331 | unsigned long mmu_seq; | 1332 | unsigned long mmu_seq; |
1332 | 1333 | ||
1333 | down_read(¤t->mm->mmap_sem); | ||
1334 | if (is_largepage_backed(vcpu, gfn & ~(KVM_PAGES_PER_HPAGE-1))) { | 1334 | if (is_largepage_backed(vcpu, gfn & ~(KVM_PAGES_PER_HPAGE-1))) { |
1335 | gfn &= ~(KVM_PAGES_PER_HPAGE-1); | 1335 | gfn &= ~(KVM_PAGES_PER_HPAGE-1); |
1336 | largepage = 1; | 1336 | largepage = 1; |
1337 | } | 1337 | } |
1338 | 1338 | ||
1339 | mmu_seq = vcpu->kvm->mmu_notifier_seq; | 1339 | mmu_seq = vcpu->kvm->mmu_notifier_seq; |
1340 | /* implicit mb(), we'll read before PT lock is unlocked */ | 1340 | smp_rmb(); |
1341 | pfn = gfn_to_pfn(vcpu->kvm, gfn); | 1341 | pfn = gfn_to_pfn(vcpu->kvm, gfn); |
1342 | up_read(¤t->mm->mmap_sem); | ||
1343 | 1342 | ||
1344 | /* mmio */ | 1343 | /* mmio */ |
1345 | if (is_error_pfn(pfn)) { | 1344 | if (is_error_pfn(pfn)) { |
@@ -1488,15 +1487,13 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, | |||
1488 | if (r) | 1487 | if (r) |
1489 | return r; | 1488 | return r; |
1490 | 1489 | ||
1491 | down_read(¤t->mm->mmap_sem); | ||
1492 | if (is_largepage_backed(vcpu, gfn & ~(KVM_PAGES_PER_HPAGE-1))) { | 1490 | if (is_largepage_backed(vcpu, gfn & ~(KVM_PAGES_PER_HPAGE-1))) { |
1493 | gfn &= ~(KVM_PAGES_PER_HPAGE-1); | 1491 | gfn &= ~(KVM_PAGES_PER_HPAGE-1); |
1494 | largepage = 1; | 1492 | largepage = 1; |
1495 | } | 1493 | } |
1496 | mmu_seq = vcpu->kvm->mmu_notifier_seq; | 1494 | mmu_seq = vcpu->kvm->mmu_notifier_seq; |
1497 | /* implicit mb(), we'll read before PT lock is unlocked */ | 1495 | smp_rmb(); |
1498 | pfn = gfn_to_pfn(vcpu->kvm, gfn); | 1496 | pfn = gfn_to_pfn(vcpu->kvm, gfn); |
1499 | up_read(¤t->mm->mmap_sem); | ||
1500 | if (is_error_pfn(pfn)) { | 1497 | if (is_error_pfn(pfn)) { |
1501 | kvm_release_pfn_clean(pfn); | 1498 | kvm_release_pfn_clean(pfn); |
1502 | return 1; | 1499 | return 1; |
@@ -1809,15 +1806,13 @@ static void mmu_guess_page_from_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
1809 | return; | 1806 | return; |
1810 | gfn = (gpte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; | 1807 | gfn = (gpte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; |
1811 | 1808 | ||
1812 | down_read(¤t->mm->mmap_sem); | ||
1813 | if (is_large_pte(gpte) && is_largepage_backed(vcpu, gfn)) { | 1809 | if (is_large_pte(gpte) && is_largepage_backed(vcpu, gfn)) { |
1814 | gfn &= ~(KVM_PAGES_PER_HPAGE-1); | 1810 | gfn &= ~(KVM_PAGES_PER_HPAGE-1); |
1815 | vcpu->arch.update_pte.largepage = 1; | 1811 | vcpu->arch.update_pte.largepage = 1; |
1816 | } | 1812 | } |
1817 | vcpu->arch.update_pte.mmu_seq = vcpu->kvm->mmu_notifier_seq; | 1813 | vcpu->arch.update_pte.mmu_seq = vcpu->kvm->mmu_notifier_seq; |
1818 | /* implicit mb(), we'll read before PT lock is unlocked */ | 1814 | smp_rmb(); |
1819 | pfn = gfn_to_pfn(vcpu->kvm, gfn); | 1815 | pfn = gfn_to_pfn(vcpu->kvm, gfn); |
1820 | up_read(¤t->mm->mmap_sem); | ||
1821 | 1816 | ||
1822 | if (is_error_pfn(pfn)) { | 1817 | if (is_error_pfn(pfn)) { |
1823 | kvm_release_pfn_clean(pfn); | 1818 | kvm_release_pfn_clean(pfn); |
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index b671f61be41e..6dd08e096e24 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h | |||
@@ -102,14 +102,10 @@ static bool FNAME(cmpxchg_gpte)(struct kvm *kvm, | |||
102 | pt_element_t *table; | 102 | pt_element_t *table; |
103 | struct page *page; | 103 | struct page *page; |
104 | 104 | ||
105 | down_read(¤t->mm->mmap_sem); | ||
106 | page = gfn_to_page(kvm, table_gfn); | 105 | page = gfn_to_page(kvm, table_gfn); |
107 | up_read(¤t->mm->mmap_sem); | ||
108 | 106 | ||
109 | table = kmap_atomic(page, KM_USER0); | 107 | table = kmap_atomic(page, KM_USER0); |
110 | |||
111 | ret = CMPXCHG(&table[index], orig_pte, new_pte); | 108 | ret = CMPXCHG(&table[index], orig_pte, new_pte); |
112 | |||
113 | kunmap_atomic(table, KM_USER0); | 109 | kunmap_atomic(table, KM_USER0); |
114 | 110 | ||
115 | kvm_release_page_dirty(page); | 111 | kvm_release_page_dirty(page); |
@@ -418,7 +414,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, | |||
418 | return 0; | 414 | return 0; |
419 | } | 415 | } |
420 | 416 | ||
421 | down_read(¤t->mm->mmap_sem); | ||
422 | if (walker.level == PT_DIRECTORY_LEVEL) { | 417 | if (walker.level == PT_DIRECTORY_LEVEL) { |
423 | gfn_t large_gfn; | 418 | gfn_t large_gfn; |
424 | large_gfn = walker.gfn & ~(KVM_PAGES_PER_HPAGE-1); | 419 | large_gfn = walker.gfn & ~(KVM_PAGES_PER_HPAGE-1); |
@@ -428,9 +423,8 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, | |||
428 | } | 423 | } |
429 | } | 424 | } |
430 | mmu_seq = vcpu->kvm->mmu_notifier_seq; | 425 | mmu_seq = vcpu->kvm->mmu_notifier_seq; |
431 | /* implicit mb(), we'll read before PT lock is unlocked */ | 426 | smp_rmb(); |
432 | pfn = gfn_to_pfn(vcpu->kvm, walker.gfn); | 427 | pfn = gfn_to_pfn(vcpu->kvm, walker.gfn); |
433 | up_read(¤t->mm->mmap_sem); | ||
434 | 428 | ||
435 | /* mmio */ | 429 | /* mmio */ |
436 | if (is_error_pfn(pfn)) { | 430 | if (is_error_pfn(pfn)) { |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 046a91b5a4ba..025bf4011abc 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -2010,9 +2010,7 @@ static int alloc_apic_access_page(struct kvm *kvm) | |||
2010 | if (r) | 2010 | if (r) |
2011 | goto out; | 2011 | goto out; |
2012 | 2012 | ||
2013 | down_read(¤t->mm->mmap_sem); | ||
2014 | kvm->arch.apic_access_page = gfn_to_page(kvm, 0xfee00); | 2013 | kvm->arch.apic_access_page = gfn_to_page(kvm, 0xfee00); |
2015 | up_read(¤t->mm->mmap_sem); | ||
2016 | out: | 2014 | out: |
2017 | up_write(&kvm->slots_lock); | 2015 | up_write(&kvm->slots_lock); |
2018 | return r; | 2016 | return r; |
@@ -2034,10 +2032,8 @@ static int alloc_identity_pagetable(struct kvm *kvm) | |||
2034 | if (r) | 2032 | if (r) |
2035 | goto out; | 2033 | goto out; |
2036 | 2034 | ||
2037 | down_read(¤t->mm->mmap_sem); | ||
2038 | kvm->arch.ept_identity_pagetable = gfn_to_page(kvm, | 2035 | kvm->arch.ept_identity_pagetable = gfn_to_page(kvm, |
2039 | VMX_EPT_IDENTITY_PAGETABLE_ADDR >> PAGE_SHIFT); | 2036 | VMX_EPT_IDENTITY_PAGETABLE_ADDR >> PAGE_SHIFT); |
2040 | up_read(¤t->mm->mmap_sem); | ||
2041 | out: | 2037 | out: |
2042 | up_write(&kvm->slots_lock); | 2038 | up_write(&kvm->slots_lock); |
2043 | return r; | 2039 | return r; |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 61eddbeabeb4..108f07267e87 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -946,10 +946,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) | |||
946 | /* ...but clean it before doing the actual write */ | 946 | /* ...but clean it before doing the actual write */ |
947 | vcpu->arch.time_offset = data & ~(PAGE_MASK | 1); | 947 | vcpu->arch.time_offset = data & ~(PAGE_MASK | 1); |
948 | 948 | ||
949 | down_read(¤t->mm->mmap_sem); | ||
950 | vcpu->arch.time_page = | 949 | vcpu->arch.time_page = |
951 | gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT); | 950 | gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT); |
952 | up_read(¤t->mm->mmap_sem); | ||
953 | 951 | ||
954 | if (is_error_page(vcpu->arch.time_page)) { | 952 | if (is_error_page(vcpu->arch.time_page)) { |
955 | kvm_release_page_clean(vcpu->arch.time_page); | 953 | kvm_release_page_clean(vcpu->arch.time_page); |
@@ -2322,9 +2320,7 @@ static int emulator_cmpxchg_emulated(unsigned long addr, | |||
2322 | 2320 | ||
2323 | val = *(u64 *)new; | 2321 | val = *(u64 *)new; |
2324 | 2322 | ||
2325 | down_read(¤t->mm->mmap_sem); | ||
2326 | page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); | 2323 | page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); |
2327 | up_read(¤t->mm->mmap_sem); | ||
2328 | 2324 | ||
2329 | kaddr = kmap_atomic(page, KM_USER0); | 2325 | kaddr = kmap_atomic(page, KM_USER0); |
2330 | set_64bit((u64 *)(kaddr + offset_in_page(gpa)), val); | 2326 | set_64bit((u64 *)(kaddr + offset_in_page(gpa)), val); |
@@ -3089,9 +3085,7 @@ static void vapic_enter(struct kvm_vcpu *vcpu) | |||
3089 | if (!apic || !apic->vapic_addr) | 3085 | if (!apic || !apic->vapic_addr) |
3090 | return; | 3086 | return; |
3091 | 3087 | ||
3092 | down_read(¤t->mm->mmap_sem); | ||
3093 | page = gfn_to_page(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT); | 3088 | page = gfn_to_page(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT); |
3094 | up_read(¤t->mm->mmap_sem); | ||
3095 | 3089 | ||
3096 | vcpu->arch.apic->vapic_page = page; | 3090 | vcpu->arch.apic->vapic_page = page; |
3097 | } | 3091 | } |