aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2008-09-16 19:54:47 -0400
committerAvi Kivity <avi@redhat.com>2008-10-15 08:25:06 -0400
commit4c2155ce81c193788082d4b8cdbc26d79edebc58 (patch)
tree5c028fe4a18c55b5c0e9c4e80be459dad3f96da7
parent777b3f49d297e387866604093b635e5bc9b9d2a6 (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.c2
-rw-r--r--arch/x86/kvm/mmu.c23
-rw-r--r--arch/x86/kvm/paging_tmpl.h8
-rw-r--r--arch/x86/kvm/vmx.c4
-rw-r--r--arch/x86/kvm/x86.c6
-rw-r--r--virt/kvm/kvm_main.c10
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(&current->mm->mmap_sem);
151 new_page = gfn_to_page(vcpu->kvm, gfn); 150 new_page = gfn_to_page(vcpu->kvm, gfn);
152 up_read(&current->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(&current->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(&current->mm->mmap_sem);
416 419
417 return 0; 420 return ret;
418} 421}
419 422
420static int is_largepage_backed(struct kvm_vcpu *vcpu, gfn_t large_gfn) 423static 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(&current->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(&current->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(&current->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(&current->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(&current->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(&current->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(&current->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(&current->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(&current->mm->mmap_sem);
106 page = gfn_to_page(kvm, table_gfn); 105 page = gfn_to_page(kvm, table_gfn);
107 up_read(&current->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(&current->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(&current->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(&current->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(&current->mm->mmap_sem);
2016out: 2014out:
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(&current->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(&current->mm->mmap_sem);
2041out: 2037out:
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(&current->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(&current->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(&current->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(&current->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(&current->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(&current->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}
724EXPORT_SYMBOL_GPL(gfn_to_hva); 724EXPORT_SYMBOL_GPL(gfn_to_hva);
725 725
726/*
727 * Requires current->mm->mmap_sem to be held
728 */
729pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn) 726pfn_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(&current->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(&current->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(&current->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]);