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 | |
| 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>
| -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 | ||||
| -rw-r--r-- | virt/kvm/kvm_main.c | 10 |
6 files changed, 15 insertions, 38 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 | } |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 2907d05cfcc3..cd34f73513d3 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
| @@ -723,9 +723,6 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn) | |||
| 723 | } | 723 | } |
| 724 | EXPORT_SYMBOL_GPL(gfn_to_hva); | 724 | EXPORT_SYMBOL_GPL(gfn_to_hva); |
| 725 | 725 | ||
| 726 | /* | ||
| 727 | * Requires current->mm->mmap_sem to be held | ||
| 728 | */ | ||
| 729 | pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn) | 726 | pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn) |
| 730 | { | 727 | { |
| 731 | struct page *page[1]; | 728 | struct page *page[1]; |
| @@ -741,20 +738,23 @@ pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn) | |||
| 741 | return page_to_pfn(bad_page); | 738 | return page_to_pfn(bad_page); |
| 742 | } | 739 | } |
| 743 | 740 | ||
| 744 | npages = get_user_pages(current, current->mm, addr, 1, 1, 0, page, | 741 | npages = get_user_pages_fast(addr, 1, 1, page); |
| 745 | NULL); | ||
| 746 | 742 | ||
| 747 | if (unlikely(npages != 1)) { | 743 | if (unlikely(npages != 1)) { |
| 748 | struct vm_area_struct *vma; | 744 | struct vm_area_struct *vma; |
| 749 | 745 | ||
| 746 | down_read(¤t->mm->mmap_sem); | ||
| 750 | vma = find_vma(current->mm, addr); | 747 | vma = find_vma(current->mm, addr); |
| 748 | |||
| 751 | if (vma == NULL || addr < vma->vm_start || | 749 | if (vma == NULL || addr < vma->vm_start || |
| 752 | !(vma->vm_flags & VM_PFNMAP)) { | 750 | !(vma->vm_flags & VM_PFNMAP)) { |
| 751 | up_read(¤t->mm->mmap_sem); | ||
| 753 | get_page(bad_page); | 752 | get_page(bad_page); |
| 754 | return page_to_pfn(bad_page); | 753 | return page_to_pfn(bad_page); |
| 755 | } | 754 | } |
| 756 | 755 | ||
| 757 | pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; | 756 | pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; |
| 757 | up_read(¤t->mm->mmap_sem); | ||
| 758 | BUG_ON(!is_mmio_pfn(pfn)); | 758 | BUG_ON(!is_mmio_pfn(pfn)); |
| 759 | } else | 759 | } else |
| 760 | pfn = page_to_pfn(page[0]); | 760 | pfn = page_to_pfn(page[0]); |
