convert slotslock to SRCU
cover convert slotslock to SRCU
Now that synchronize_srcu_expedited is in the tree, we can continue the convertion of slots_lock to SRCU.
Results:
up:
srcu-memslot:
cpuid 2157
vmcall 1992mov_from_cr8 11mov_to_cr8 17inl_from_pmtimer 11226
ipi (skipped)
ipi+halt (skipped)
stock:
cpuid 2272
vmcall 2114mov_from_cr8 11mov_to_cr8 17inl_from_pmtimer 11521
ipi (skipped)
ipi+halt (skipped)
vmcall 6.1% improvement
smp 2:
srcu-memslot:
cpuid 2333
vmcall 2165mov_from_cr8 11mov_to_cr8 18inl_from_pmtimer 12233
ipi 40734
ipi+halt 41675
stock:
cpuid 2512
vmcall 2367mov_from_cr8 11mov_to_cr8 18inl_from_pmtimer 12821
ipi 42941
ipi+halt 43146
vmcall 9.3% improvement
PATCH 1/11 KVM: modify memslots layout in struct kvm
Have a pointer to an allocated region inside struct kvm.
arch/x86/kvm/mmu.c +6 -5
@@ -809,13 +809,14 @@ static int kvm_handle_hva(struct kvm *kv {int i, j;int retval =0 ; +struct kvm_memslots *slots = kvm->memslots;/* * If mmap_sem isn't taken, we can look the memslots with only * the mmu_lock by skipping over the slots with userspace_addr == 0. */ -for (i =0 ; i < kvm->nmemslots; i++) { -struct kvm_memory_slot *memslot = &kvm->memslots[i]; +for (i =0 ; i < slots->nmemslots; i++) { +struct kvm_memory_slot *memslot = &slots->memslots[i];unsigned long start = memslot->userspace_addr;unsigned long end;
@@ -3023,8 +3024,8 @@ unsigned int kvm_mmu_calculate_mmu_pagesunsigned int nr_mmu_pages;unsigned int nr_pages =0 ; -for (i =0 ; i < kvm->nmemslots; i++) - nr_pages += kvm->memslots[i].npages; +for (i =0 ; i < kvm->memslots->nmemslots; i++) + nr_pages += kvm->memslots->memslots[i].npages; nr_mmu_pages = nr_pages *KVM_PERMILLE_MMU_PAGES /1000 ; nr_mmu_pages = max(nr_mmu_pages,
@@ -3297,7 +3298,7 @@ static int count_rmaps(struct kvm_vcpu *int i, j, k;for (i =0 ; i <KVM_MEMORY_SLOTS ; ++i) { -struct kvm_memory_slot *m = &vcpu->kvm->memslots[i]; +struct kvm_memory_slot *m = &vcpu->kvm->memslots->memslots[i];struct kvm_rmap_desc *d;for (j =0 ; j < m->npages; ++j) {
arch/x86/kvm/vmx.c +2 -2
@@ -1503,8 +1503,8 @@ static void enter_pmode(struct kvm_vcpustatic gva_t rmode_tss_base (struct kvm *kvm) {if (!kvm->arch.tss_addr) { -gfn_t base_gfn = kvm->memslots[0 ].base_gfn + - kvm->memslots[0 ].npages -3 ; +gfn_t base_gfn = kvm->memslots->memslots[0 ].base_gfn + + kvm->memslots->memslots[0 ].npages -3 ;return base_gfn <<PAGE_SHIFT ; }return kvm->arch.tss_addr;
arch/x86/kvm/x86.c +2 -2
@@ -2428,7 +2428,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvspin_lock (&kvm->mmu_lock);kvm_mmu_slot_remove_write_access (kvm, log->slot);spin_unlock (&kvm->mmu_lock); - memslot = &kvm->memslots[log->slot]; + memslot = &kvm->memslots->memslots[log->slot]; n =ALIGN (memslot->npages,BITS_PER_LONG ) /8 ;memset (memslot->dirty_bitmap,0 , n); }
@@ -5222,7 +5222,7 @@ int kvm_arch_set_memory_region(struct kv int user_alloc) {int npages = mem->memory_size >>PAGE_SHIFT ; -struct kvm_memory_slot *memslot = &kvm->memslots[mem->slot]; +struct kvm_memory_slot *memslot = &kvm->memslots->memslots[mem->slot];/*To keep backward compatibility with older userspace, *x86 needs to hanlde !user_alloc case.
include/linux/kvm_host.h +8 -4
@@ -150,14 +150,18 @@ struct kvm_irq_routing_table {};#endif +struct kvm_memslots { +int nmemslots; +struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS + +KVM_PRIVATE_MEM_SLOTS ]; +}; +struct kvm {spinlock_t mmu_lock;spinlock_t requests_lock;struct rw_semaphore slots_lock;struct mm_struct *mm;/* userspace tied to this vm */ -int nmemslots; -struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS + -KVM_PRIVATE_MEM_SLOTS ]; +struct kvm_memslots *memslots;#ifdef CONFIG_KVM_APIC_ARCHITECTURE u32 bsp_vcpu_id;struct kvm_vcpu *bsp_vcpu;
@@ -482,7 +486,7 @@ static inline void kvm_guest_exit(void)static inline int memslot_id (struct kvm *kvm,struct kvm_memory_slot *slot) { -return slot - kvm->memslots; +return slot - kvm->memslots->memslots; }static inline gpa_t gfn_to_gpa (gfn_t gfn)
virt/kvm/iommu.c +12 -6
@@ -76,10 +76,13 @@ unmap_pages:static int kvm_iommu_map_memslots (struct kvm *kvm) {int i, r =0 ; +struct kvm_memslots *slots; -for (i =0 ; i < kvm->nmemslots; i++) { - r =kvm_iommu_map_pages (kvm, kvm->memslots[i].base_gfn, - kvm->memslots[i].npages); + slots = kvm->memslots; + +for (i =0 ; i < slots->nmemslots; i++) { + r =kvm_iommu_map_pages (kvm, slots->memslots[i].base_gfn, + slots->memslots[i].npages);if (r)break ; }
@@ -210,10 +213,13 @@ static void kvm_iommu_put_pages(struct kstatic int kvm_iommu_unmap_memslots (struct kvm *kvm) {int i; +struct kvm_memslots *slots; + + slots = kvm->memslots; -for (i =0 ; i < kvm->nmemslots; i++) { -kvm_iommu_put_pages (kvm, kvm->memslots[i].base_gfn, - kvm->memslots[i].npages); +for (i =0 ; i < slots->nmemslots; i++) { +kvm_iommu_put_pages (kvm, slots->memslots[i].base_gfn, + slots->memslots[i].npages); }return 0 ;
virt/kvm/kvm_main.c +23 -13
@@ -375,12 +375,16 @@ static struct kvm *kvm_create_vm(void)INIT_HLIST_HEAD (&kvm->irq_ack_notifier_list);#endif + r = -ENOMEM ; + kvm->memslots =kzalloc (sizeof (struct kvm_memslots ),GFP_KERNEL ); +if (!kvm->memslots) + goto out_err; +#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET page =alloc_page (GFP_KERNEL | __GFP_ZERO); -if (!page) { - r = -ENOMEM ; +if (!page) goto out_err; - } + kvm->coalesced_mmio_ring = (struct kvm_coalesced_mmio_ring *)page_address (page);#endif
@@ -416,6 +420,7 @@ out: out_err:hardware_disable_all (); out_err_nodisable: +kfree (kvm->memslots);kfree (kvm);return ERR_PTR (r); }
@@ -450,9 +455,12 @@ static void kvm_free_physmem_slot(structvoid kvm_free_physmem (struct kvm *kvm) {int i; +struct kvm_memslots *slots = kvm->memslots; + +for (i =0 ; i < slots->nmemslots; ++i) +kvm_free_physmem_slot (&slots->memslots[i],NULL ); -for (i =0 ; i < kvm->nmemslots; ++i) -kvm_free_physmem_slot (&kvm->memslots[i],NULL ); +kfree (kvm->memslots); }static void kvm_destroy_vm (struct kvm *kvm)
@@ -533,7 +541,7 @@ int __kvm_set_memory_region(struct kvm *if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr) goto out; - memslot = &kvm->memslots[mem->slot]; + memslot = &kvm->memslots->memslots[mem->slot]; base_gfn = mem->guest_phys_addr >>PAGE_SHIFT ; npages = mem->memory_size >>PAGE_SHIFT ;
@@ -554,7 +562,7 @@ int __kvm_set_memory_region(struct kvm */* Check for overlaps */ r = -EEXIST ;for (i =0 ; i <KVM_MEMORY_SLOTS ; ++i) { -struct kvm_memory_slot *s = &kvm->memslots[i]; +struct kvm_memory_slot *s = &kvm->memslots->memslots[i];if (s == memslot || !s->npages)continue ;
@@ -656,8 +664,8 @@ skip_lpage:kvm_arch_flush_shadow (kvm);spin_lock (&kvm->mmu_lock); -if (mem->slot >= kvm->nmemslots) - kvm->nmemslots = mem->slot +1 ; +if (mem->slot >= kvm->memslots->nmemslots) + kvm->memslots->nmemslots = mem->slot +1 ; *memslot = new;spin_unlock (&kvm->mmu_lock);
@@ -727,7 +735,7 @@ int kvm_get_dirty_log(struct kvm *kvm,if (log->slot >=KVM_MEMORY_SLOTS ) goto out; - memslot = &kvm->memslots[log->slot]; + memslot = &kvm->memslots->memslots[log->slot]; r = -ENOENT ;if (!memslot->dirty_bitmap) goto out;
@@ -781,9 +789,10 @@ EXPORT_SYMBOL_GPL(kvm_is_error_hva);struct kvm_memory_slot *gfn_to_memslot_unaliased (struct kvm *kvm,gfn_t gfn) {int i; +struct kvm_memslots *slots = kvm->memslots; -for (i =0 ; i < kvm->nmemslots; ++i) { -struct kvm_memory_slot *memslot = &kvm->memslots[i]; +for (i =0 ; i < slots->nmemslots; ++i) { +struct kvm_memory_slot *memslot = &slots->memslots[i];if (gfn >= memslot->base_gfn && gfn < memslot->base_gfn + memslot->npages)
@@ -802,10 +811,11 @@ struct kvm_memory_slot *gfn_to_memslot(sint kvm_is_visible_gfn (struct kvm *kvm,gfn_t gfn) {int i; +struct kvm_memslots *slots = kvm->memslots; gfn =unalias_gfn (kvm, gfn);for (i =0 ; i <KVM_MEMORY_SLOTS ; ++i) { -struct kvm_memory_slot *memslot = &kvm->memslots[i]; +struct kvm_memory_slot *memslot = &slots->memslots[i];if (gfn >= memslot->base_gfn && gfn < memslot->base_gfn + memslot->npages)
PATCH 2/11 KVM: modify alias layout in x86s struct kvm_arch
In reply to Marcelo TosattiHave a pointer to an allocated region inside x86's kvm_arch.
arch/x86/include/asm/kvm_host.h +6 -2
@@ -370,9 +370,13 @@ struct kvm_mem_alias {gfn_t target_gfn; }; -struct kvm_arch { -int naliases; +struct kvm_mem_aliases {struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS ]; +int naliases; +}; + +struct kvm_arch { +struct kvm_mem_aliases *aliases;unsigned int n_free_mmu_pages;unsigned int n_requested_mmu_pages;
arch/x86/kvm/x86.c +16 -5
@@ -2228,9 +2228,10 @@ gfn_t unalias_gfn(struct kvm *kvm, gfn_t {int i;struct kvm_mem_alias *alias; +struct kvm_mem_aliases *aliases = kvm->arch.aliases; -for (i =0 ; i < kvm->arch.naliases; ++i) { - alias = &kvm->arch.aliases[i]; +for (i =0 ; i < aliases->naliases; ++i) { + alias = &aliases->aliases[i];if (gfn >= alias->base_gfn && gfn < alias->base_gfn + alias->npages)return alias->target_gfn + gfn - alias->base_gfn;
@@ -2248,6 +2249,7 @@ static int kvm_vm_ioctl_set_memory_alias {int r, n;struct kvm_mem_alias *p; +struct kvm_mem_aliases *aliases; r = -EINVAL ;/* General sanity checks */
@@ -2267,15 +2269,17 @@ static int kvm_vm_ioctl_set_memory_aliasdown_write (&kvm->slots_lock);spin_lock (&kvm->mmu_lock); - p = &kvm->arch.aliases[alias->slot]; + aliases = kvm->arch.aliases; + + p = &aliases->aliases[alias->slot]; p->base_gfn = alias->guest_phys_addr >>PAGE_SHIFT ; p->npages = alias->memory_size >>PAGE_SHIFT ; p->target_gfn = alias->target_phys_addr >>PAGE_SHIFT ;for (n =KVM_ALIAS_SLOTS ; n >0 ; --n) -if (kvm->arch.aliases[n -1 ].npages) +if (aliases->aliases[n -1 ].npages)break ; - kvm->arch.naliases = n; + aliases->naliases = n;spin_unlock (&kvm->mmu_lock);kvm_mmu_zap_all (kvm);
@@ -5157,6 +5161,12 @@ struct kvm *kvm_arch_create_vm(void)if (!kvm)return ERR_PTR (-ENOMEM ); + kvm->arch.aliases =kzalloc (sizeof (struct kvm_mem_aliases ),GFP_KERNEL ); +if (!kvm->arch.aliases) { +kfree (kvm); +return ERR_PTR (-ENOMEM ); + } +INIT_LIST_HEAD (&kvm->arch.active_mmu_pages);INIT_LIST_HEAD (&kvm->arch.assigned_dev_head);
@@ -5213,6 +5223,7 @@ void kvm_arch_destroy_vm(struct kvm *kvmput_page (kvm->arch.apic_access_page);if (kvm->arch.ept_identity_pagetable)put_page (kvm->arch.ept_identity_pagetable); +kfree (kvm->arch.aliases);kfree (kvm); }
PATCH 3/11 KVM: split kvm_arch_set_memory_region into prepare and commit
In reply to Marcelo TosattiRequired for SRCU convertion later.
arch/ia64/kvm/kvm-ia64.c +11 -4
@@ -1576,15 +1576,14 @@ out:return r; } -int kvm_arch_set_memory_region (struct kvm *kvm, -struct kvm_userspace_memory_region *mem, +int kvm_arch_prepare_memory_region (struct kvm *kvm, +struct kvm_memory_slot *memslot,struct kvm_memory_slot old,int user_alloc) {unsigned long i;unsigned long pfn; -int npages = mem->memory_size >>PAGE_SHIFT ; -struct kvm_memory_slot *memslot = &kvm->memslots[mem->slot]; +int npages = memslot->npages;unsigned long base_gfn = memslot->base_gfn;if (base_gfn + npages > (KVM_MAX_MEM_SIZE >>PAGE_SHIFT ))
@@ -1608,6 +1607,14 @@ int kvm_arch_set_memory_region(struct kvreturn 0 ; } +void kvm_arch_commit_memory_region (struct kvm *kvm, +struct kvm_userspace_memory_region *mem, +struct kvm_memory_slot old, +int user_alloc) +{ +return ; +} +void kvm_arch_flush_shadow (struct kvm *kvm) {kvm_flush_remote_tlbs (kvm);
arch/s390/kvm/kvm-s390.c +12 -6
@@ -689,10 +689,10 @@ long kvm_arch_vcpu_ioctl(struct file *fi }/* Section: memory related */ -int kvm_arch_set_memory_region (struct kvm *kvm, -struct kvm_userspace_memory_region *mem, -struct kvm_memory_slot old, -int user_alloc) +int kvm_arch_prepare_memory_region (struct kvm *kvm, +struct kvm_userspace_memory_region *mem, +struct kvm_memory_slot old, +int user_alloc) {int i;struct kvm_vcpu *vcpu;
@@ -719,14 +719,20 @@ int kvm_arch_set_memory_region(struct kvif (!user_alloc)return -EINVAL ; +return 0 ; +} + +int kvm_arch_commit_memory_region (struct kvm *kvm, +struct kvm_userspace_memory_region *mem, +struct kvm_memory_slot old, +int user_alloc) +{/* request update of sie control block for all available vcpus */ kvm_for_each_vcpu (i, vcpu, kvm) {if (test_and_set_bit (KVM_REQ_MMU_RELOAD , &vcpu->requests))continue ;kvm_s390_inject_sigp_stop (vcpu,ACTION_RELOADVCPU_ON_STOP ); } - -return 0 ; }void kvm_arch_flush_shadow (struct kvm *kvm)
arch/x86/kvm/x86.c +28 -22
75 lines not on this page · raw message
include/linux/kvm_host.h +5 -1
@@ -253,7 +253,11 @@ int kvm_set_memory_region(struct kvm *kvint __kvm_set_memory_region (struct kvm *kvm,struct kvm_userspace_memory_region *mem,int user_alloc); -int kvm_arch_set_memory_region (struct kvm *kvm, +int kvm_arch_prepare_memory_region (struct kvm *kvm, +struct kvm_memory_slot *memslot, +struct kvm_memory_slot old, +int user_alloc); +void kvm_arch_commit_memory_region (struct kvm *kvm,struct kvm_userspace_memory_region *mem,struct kvm_memory_slot old,int user_alloc);
virt/kvm/kvm_main.c +5 -7
@@ -663,6 +663,10 @@ skip_lpage:if (!npages)kvm_arch_flush_shadow (kvm); + r =kvm_arch_prepare_memory_region (kvm, &new, old, user_alloc); +if (r) + goto out_free; +spin_lock (&kvm->mmu_lock);if (mem->slot >= kvm->memslots->nmemslots) kvm->memslots->nmemslots = mem->slot +1 ;
@@ -670,13 +674,7 @@ skip_lpage: *memslot = new;spin_unlock (&kvm->mmu_lock); - r =kvm_arch_set_memory_region (kvm, mem, old, user_alloc); -if (r) { -spin_lock (&kvm->mmu_lock); - *memslot = old; -spin_unlock (&kvm->mmu_lock); - goto out_free; - } +kvm_arch_commit_memory_region (kvm, mem, old, user_alloc);kvm_free_physmem_slot (&old, npages ? &new :NULL );/* Slot deletion case: we have to update the current slot */
PATCH 4/11 KVM: introduce gfn_to_pfn_memslot
In reply to Marcelo TosattiWhich takes a memslot pointer instead of using kvm->memslots.
To be used by SRCU convertion later.
include/linux/kvm_host.h +2 -0
@@ -272,6 +272,8 @@ void kvm_set_page_dirty(struct page *pagvoid kvm_set_page_accessed (struct page *page);pfn_t gfn_to_pfn (struct kvm *kvm,gfn_t gfn); +pfn_t gfn_to_pfn_memslot (struct kvm *kvm, +struct kvm_memory_slot *slot,gfn_t gfn);void kvm_release_pfn_dirty (pfn_t );void kvm_release_pfn_clean (pfn_t pfn);void kvm_set_pfn_dirty (pfn_t pfn);
virt/kvm/kvm_main.c +25 -8
@@ -835,21 +835,14 @@ unsigned long gfn_to_hva(struct kvm *kvm }EXPORT_SYMBOL_GPL (gfn_to_hva); -pfn_t gfn_to_pfn (struct kvm *kvm,gfn_t gfn) +static pfn_t __gfn_to_pfn (struct kvm *kvm,unsigned long addr) {struct page *page[1 ]; -unsigned long addr;int npages;pfn_t pfn;might_sleep (); - addr =gfn_to_hva (kvm, gfn); -if (kvm_is_error_hva (addr)) { -get_page (bad_page); -return page_to_pfn (bad_page); - } - npages =get_user_pages_fast (addr,1 ,1 , page);if (unlikely (npages !=1 )) {
@@ -874,8 +867,32 @@ pfn_t gfn_to_pfn(struct kvm *kvm, gfn_treturn pfn; } +pfn_t gfn_to_pfn (struct kvm *kvm,gfn_t gfn) +{ +unsigned long addr; + + addr =gfn_to_hva (kvm, gfn); +if (kvm_is_error_hva (addr)) { +get_page (bad_page); +return page_to_pfn (bad_page); + } + +return __gfn_to_pfn (kvm, addr); +}EXPORT_SYMBOL_GPL (gfn_to_pfn); +static unsigned long gfn_to_hva_memslot (struct kvm_memory_slot *slot,gfn_t gfn) +{ +return (slot->userspace_addr + (gfn - slot->base_gfn) *PAGE_SIZE ); +} + +pfn_t gfn_to_pfn_memslot (struct kvm *kvm, +struct kvm_memory_slot *slot,gfn_t gfn) +{ +unsigned long addr =gfn_to_hva_memslot (slot, gfn); +return __gfn_to_pfn (kvm, addr); +} +struct page *gfn_to_page (struct kvm *kvm,gfn_t gfn) {pfn_t pfn;
Re: [patch 04/11] KVM: introduce gfn_to_pfn_memslot
Quoted 8 lines · Marcelo Tosatti
Which takes a memslot pointer instead of using
kvm->memslots.To be used by SRCU convertion later.
Signed-off-by Marcelo Tosatti<[email protected]>
virt/kvm/kvm_main.c unsigned long gfn_to_hva(struct kvm *kvm · line 840
Quoted 7 lines
virt/kvm/kvm_main.c +1
-1@@ -835,21 +835,14 @@ unsigned long gfn_to_hva(struct kvm *kvm }EXPORT_SYMBOL_GPL (gfn_to_hva); -pfn_t gfn_to_pfn (struct kvm *kvm,gfn_t gfn) +static pfn_t __gfn_to_pfn (struct kvm *kvm,unsigned long addr) {
That's an hva now, not a gfn; the function name should reflect this.
Signature · 1 line
error compiling committee.c: too many arguments to function
PATCH 5/11 KVM: use gfn_to_pfn_memslot in kvm_iommu_map_pages
In reply to Marcelo TosattiSo its possible to iommu map a memslot before making it visible to kvm.
include/linux/kvm_host.h +1 -2
@@ -439,8 +439,7 @@ void kvm_free_irq_source_id(struct kvm *#define KVM_IOMMU_CACHE_COHERENCY 0x1#ifdef CONFIG_IOMMU_API -int kvm_iommu_map_pages (struct kvm *kvm,gfn_t base_gfn, -unsigned long npages); +int kvm_iommu_map_pages (struct kvm *kvm,struct kvm_memory_slot *slot);int kvm_iommu_map_guest (struct kvm *kvm);int kvm_iommu_unmap_guest (struct kvm *kvm); int kvm_assign_device(struct kvm *kvm,
virt/kvm/iommu.c +6 -7
@@ -32,10 +32,10 @@ static int kvm_iommu_unmap_memslots(strustatic void kvm_iommu_put_pages (struct kvm *kvm,gfn_t base_gfn,unsigned long npages); -int kvm_iommu_map_pages (struct kvm *kvm, -gfn_t base_gfn,unsigned long npages) +int kvm_iommu_map_pages (struct kvm *kvm,struct kvm_memory_slot *slot) { -gfn_t gfn = base_gfn; +gfn_t gfn = slot->base_gfn; +unsigned long npages = slot->npages;pfn_t pfn;int i, r =0 ;struct iommu_domain *domain = kvm->arch.iommu_domain;
@@ -54,7 +54,7 @@ int kvm_iommu_map_pages(struct kvm *kvm,if (iommu_iova_to_phys (domain,gfn_to_gpa (gfn)))continue ; - pfn =gfn_to_pfn (kvm, gfn); + pfn =gfn_to_pfn_memslot (kvm, slot, gfn); r = iommu_map_range(domain, gfn_to_gpa(gfn), pfn_to_hpa(pfn),
@@ -69,7 +69,7 @@ int kvm_iommu_map_pages(struct kvm *kvm,return 0 ; unmap_pages: -kvm_iommu_put_pages (kvm, base_gfn, i); +kvm_iommu_put_pages (kvm, slot->base_gfn, i);return r; }
@@ -81,8 +81,7 @@ static int kvm_iommu_map_memslots(struct slots = kvm->memslots;for (i =0 ; i < slots->nmemslots; i++) { - r =kvm_iommu_map_pages (kvm, slots->memslots[i].base_gfn, - slots->memslots[i].npages); + r =kvm_iommu_map_pages (kvm, &slots->memslots[i]);if (r)break ; }
virt/kvm/kvm_main.c +1 -1
@@ -684,7 +684,7 @@ skip_lpage:spin_unlock (&kvm->mmu_lock);#ifdef CONFIG_DMAR /* map the pages in iommu page table */ - r =kvm_iommu_map_pages (kvm, base_gfn, npages); + r =kvm_iommu_map_pages (kvm, memslot);if (r) goto out;#endif
PATCH 6/11 KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update
In reply to Marcelo TosattiUse two steps for memslot deletion: mark the slot invalid (which stops instantiation of new shadow pages for that slot, but allows destruction), then instantiate the new empty slot.
Also simplifies kvm_handle_hva locking.
include/linux/kvm.h +1 -1
@@ -103,7 +103,7 @@ struct kvm_userspace_memory_region {/* for kvm_memory_region::flags */ #define KVM_MEM_LOG_DIRTY_PAGES 1UL - +#define KVM_MEMSLOT_INVALID (1UL << 1)/* for KVM_IRQ_LINE */ struct kvm_irq_level {
virt/kvm/kvm_main.c +90 -33
220 lines not on this page · raw message
arch/ia64/kvm/kvm-ia64.c +2 -0
@@ -1834,6 +1834,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvstruct kvm_memory_slot *memslot;int is_dirty =0 ; +down_write (&kvm->slots_lock);spin_lock (&kvm->arch.dirty_log_lock); r =kvm_ia64_sync_dirty_log (kvm, log);
@@ -1853,6 +1854,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kv } r =0 ; out: +up_write (&kvm->slots_lock);spin_unlock (&kvm->arch.dirty_log_lock);return r; }
arch/x86/kvm/mmu.c +20 -16
@@ -29,6 +29,7 @@#include <linux/swap.h> #include <linux/hugetlb.h> #include <linux/compiler.h> +#include <linux/srcu.h> #include <asm/page.h> #include <asm/cmpxchg.h>
@@ -807,23 +808,18 @@ static int kvm_handle_hva(struct kvm *kvint (*handler)(struct kvm *kvm,unsigned long *rmapp, unsigned long data)) { -int i, j; +int i, j, idx;int retval =0 ; -struct kvm_memslots *slots = kvm->memslots; +struct kvm_memslots *slots; + + idx =srcu_read_lock (&kvm->srcu); + slots =rcu_dereference (kvm->memslots); -/* -* If mmap_sem isn't taken, we can look the memslots with only -* the mmu_lock by skipping over the slots with userspace_addr == 0. -*/ for (i =0 ; i < slots->nmemslots; i++) {struct kvm_memory_slot *memslot = &slots->memslots[i];unsigned long start = memslot->userspace_addr;unsigned long end; -/* mmu_lock protects userspace_addr */ -if (!start) -continue ; - end = start + (memslot->npages <<PAGE_SHIFT );if (hva >= start && hva < end) {gfn_t gfn_offset = (hva - start) >>PAGE_SHIFT ;
@@ -840,6 +836,7 @@ static int kvm_handle_hva(struct kvm *kv } } } +srcu_read_unlock (&kvm->srcu, idx);return retval; }
@@ -1619,7 +1616,7 @@ static void mmu_unshadow(struct kvm *kvmstatic void page_header_update_slot (struct kvm *kvm,void *pte,gfn_t gfn) { -int slot =memslot_id (kvm,gfn_to_memslot (kvm, gfn)); +int slot =memslot_id (kvm, gfn);struct kvm_mmu_page *sp =page_header (__pa (pte));__set_bit (slot, sp->slot_bitmap);
@@ -3020,16 +3017,20 @@ nomem:*/ unsigned int kvm_mmu_calculate_mmu_pages (struct kvm *kvm) { -int i; +int i, idx;unsigned int nr_mmu_pages;unsigned int nr_pages =0 ; +struct kvm_memslots *slots; -for (i =0 ; i < kvm->memslots->nmemslots; i++) - nr_pages += kvm->memslots->memslots[i].npages; + idx =srcu_read_lock (&kvm->srcu); + slots =rcu_dereference (kvm->memslots); +for (i =0 ; i < slots->nmemslots; i++) + nr_pages += slots->memslots[i].npages; nr_mmu_pages = nr_pages *KVM_PERMILLE_MMU_PAGES /1000 ; nr_mmu_pages =max (nr_mmu_pages, (unsigned int )KVM_MIN_ALLOC_MMU_PAGES ); +srcu_read_unlock (&kvm->srcu, idx);return nr_mmu_pages; }
@@ -3295,10 +3296,12 @@ static void audit_mappings(struct kvm_vcstatic int count_rmaps (struct kvm_vcpu *vcpu) {int nmaps =0 ; -int i, j, k; +int i, j, k, idx; + idx =srcu_read_lock (&kvm->srcu); + slots =rcu_dereference (kvm->memslots);for (i =0 ; i <KVM_MEMORY_SLOTS ; ++i) { -struct kvm_memory_slot *m = &vcpu->kvm->memslots->memslots[i]; +struct kvm_memory_slot *m = &slots->memslots[i];struct kvm_rmap_desc *d;for (j =0 ; j < m->npages; ++j) {
@@ -3321,6 +3324,7 @@ static int count_rmaps(struct kvm_vcpu * } } } +srcu_read_unlock (&kvm->srcu, idx);return nmaps; }
arch/x86/kvm/vmx.c +11 -2
@@ -24,6 +24,7 @@#include <linux/mm.h> #include <linux/highmem.h> #include <linux/sched.h> +#include <linux/srcu.h> #include <linux/moduleparam.h> #include <linux/ftrace_event.h> #include "kvm_cache_regs.h"
@@ -1503,10 +1504,18 @@ static void enter_pmode(struct kvm_vcpustatic gva_t rmode_tss_base (struct kvm *kvm) {if (!kvm->arch.tss_addr) { -gfn_t base_gfn = kvm->memslots->memslots[0 ].base_gfn + - kvm->memslots->memslots[0 ].npages -3 ; +struct kvm_memslots *slots; +gfn_t base_gfn; +int idx; + + idx =srcu_read_lock (&kvm->srcu); + slots =rcu_dereference (kvm->memslots); + base_gfn = slots->memslots[0 ].base_gfn + + slots->memslots[0 ].npages -3 ; +srcu_read_unlock (&kvm->srcu, idx);return base_gfn <<PAGE_SHIFT ; } +return kvm->arch.tss_addr; }
include/linux/kvm_host.h +2 -5
@@ -162,6 +162,7 @@ struct kvm {struct rw_semaphore slots_lock;struct mm_struct *mm;/* userspace tied to this vm */ struct kvm_memslots *memslots; +struct srcu_struct srcu;#ifdef CONFIG_KVM_APIC_ARCHITECTURE u32 bsp_vcpu_id;struct kvm_vcpu *bsp_vcpu;
@@ -274,6 +275,7 @@ void kvm_set_page_accessed(struct page *pfn_t gfn_to_pfn (struct kvm *kvm,gfn_t gfn);pfn_t gfn_to_pfn_memslot (struct kvm *kvm,struct kvm_memory_slot *slot,gfn_t gfn); +int memslot_id (struct kvm *kvm,gfn_t gfn);void kvm_release_pfn_dirty (pfn_t );void kvm_release_pfn_clean (pfn_t pfn);void kvm_set_pfn_dirty (pfn_t pfn);
@@ -489,11 +491,6 @@ static inline void kvm_guest_exit(void) current->flags &= ~PF_VCPU ; } -static inline int memslot_id (struct kvm *kvm,struct kvm_memory_slot *slot) -{ -return slot - kvm->memslots->memslots; -} -static inline gpa_t gfn_to_gpa (gfn_t gfn) {return (gpa_t )gfn <<PAGE_SHIFT ;
virt/kvm/assigned-dev.c +4 -4
@@ -504,12 +504,12 @@ out:static int kvm_vm_ioctl_assign_device (struct kvm *kvm,struct kvm_assigned_pci_dev *assigned_dev) { -int r =0 ; +int r =0 , idx;struct kvm_assigned_dev_kernel *match;struct pci_dev *dev;mutex_lock (&kvm->lock); -down_read (&kvm->slots_lock); + idx =srcu_read_lock (&kvm->srcu); match =kvm_find_assigned_dev (&kvm->arch.assigned_dev_head, assigned_dev->assigned_dev_id);
@@ -573,7 +573,7 @@ static int kvm_vm_ioctl_assign_device(st } out: -up_read (&kvm->slots_lock); +srcu_read_unlock (&kvm->srcu, idx);mutex_unlock (&kvm->lock);return r; out_list_del:
@@ -585,7 +585,7 @@ out_put:pci_dev_put (dev); out_free:kfree (match); -up_read (&kvm->slots_lock); +srcu_read_unlock (&kvm->srcu, idx);mutex_unlock (&kvm->lock);return r; }
virt/kvm/iommu.c +2 -2
@@ -78,7 +78,7 @@ static int kvm_iommu_map_memslots(structint i, r =0 ;struct kvm_memslots *slots; - slots = kvm->memslots; + slots =rcu_dereference (kvm->memslots);for (i =0 ; i < slots->nmemslots; i++) { r =kvm_iommu_map_pages (kvm, &slots->memslots[i]);
@@ -214,7 +214,7 @@ static int kvm_iommu_unmap_memslots(struint i;struct kvm_memslots *slots; - slots = kvm->memslots; + slots =rcu_dereference (kvm->memslots);for (i =0 ; i < slots->nmemslots; i++) { kvm_iommu_put_pages(kvm, slots->memslots[i].base_gfn,
Re: [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update
Quoted 11 lines · Marcelo Tosatti
Use two steps for memslot deletion: mark the slot invalid (which stops instantiation of new shadow pages for that slot, but allows destruction), then instantiate the new empty slot.
Also simplifies
kvm_handle_hvalocking.r = kvm_arch_prepare_memory_region(kvm,&new, old, user_alloc); if (r) goto out_free;
r == 0
virt/kvm/kvm_main.c skip_lpage: · line 696
Quoted 11 lines
virt/kvm/kvm_main.c +6
-3-spin_lock (&kvm->mmu_lock); -if (mem->slot>= kvm->memslots->nmemslots) - kvm->memslots->nmemslots = mem->slot +1 ; +#ifdef CONFIG_DMAR +/* map the pages in iommu page table */ +if (npages) + r =kvm_iommu_map_pages (kvm,&new); +if (r) + goto out_free;
Bad indentation.
(still r == 0)
virt/kvm/kvm_main.c skip_lpage: · line 701
Quoted 8 lines
virt/kvm/kvm_main.c +4
-2+#endif - *memslot = new; -spin_unlock (&kvm->mmu_lock); + slots =kzalloc (sizeof (struct kvm_memslots ),GFP_KERNEL ); +if (!slots) + goto out_free;
goto out_free with r == 0.
Best to assign r = -ENOMEM each time, to avoid these headaches.
Quoted 3 lines
+int
memslot_id(struct kvm *kvm, gfn_t gfn)
Should be either static or kvm_memslot_id(). But the source is already like that, so leave it.
arch/x86/kvm/mmu.c static int kvm_handle_hva(struct kvm *kv · line 816
Quoted 12 lines
arch/x86/kvm/mmu.c +4
-2@@ -807,23 +808,18 @@ static int kvm_handle_hva(struct kvm *kvint (*handler)(struct kvm *kvm,unsigned long *rmapp, unsigned long data)) { -int i, j; +int i, j, idx;int retval =0 ; -struct kvm_memslots *slots = kvm->memslots; +struct kvm_memslots *slots; + + idx =srcu_read_lock (&kvm->srcu);
Maybe a better place is in the mmu notifiers, so the code is shared (once other archs start to use mmu notifiers).
Quoted 13 lines
arch/x86/kvm/mmu.c +3
-3@@ -3020,16 +3017,20 @@ nomem:*/ unsigned int kvm_mmu_calculate_mmu_pages (struct kvm *kvm) { -int i; +int i, idx;unsigned int nr_mmu_pages;unsigned int nr_pages =0 ; +struct kvm_memslots *slots; -for (i =0 ; i< kvm->memslots->nmemslots; i++) - nr_pages += kvm->memslots->memslots[i].npages; + idx =srcu_read_lock (&kvm->srcu);
arch/x86/kvm/mmu.c nomem: · line 3035
Quoted 10 lines
arch/x86/kvm/mmu.c +4
-0+ slots =rcu_dereference (kvm->memslots); +for (i =0 ; i< slots->nmemslots; i++) + nr_pages += slots->memslots[i].npages; nr_mmu_pages = nr_pages *KVM_PERMILLE_MMU_PAGES /1000 ; nr_mmu_pages =max (nr_mmu_pages, (unsigned int )KVM_MIN_ALLOC_MMU_PAGES ); +srcu_read_unlock (&kvm->srcu, idx);
Again, would like to move the srcu_locking to an outer scope.
Quoted 11 lines
arch/x86/kvm/vmx.c +5
-2@@ -1503,10 +1504,18 @@ static void enter_pmode(struct kvm_vcpustatic gva_t rmode_tss_base (struct kvm *kvm) {if (!kvm->arch.tss_addr) { -gfn_t base_gfn = kvm->memslots->memslots[0 ].base_gfn + - kvm->memslots->memslots[0 ].npages -3 ; +struct kvm_memslots *slots; +gfn_t base_gfn; +int idx; + + idx =srcu_read_lock (&kvm->srcu);
arch/x86/kvm/vmx.c static void enter_pmode(struct kvm_vcpu · line 1521
Quoted 10 lines
arch/x86/kvm/vmx.c +5
-0+ slots =rcu_dereference (kvm->memslots); + base_gfn = slots->memslots[0 ].base_gfn + + slots->memslots[0 ].npages -3 ; +srcu_read_unlock (&kvm->srcu, idx);return base_gfn<<PAGE_SHIFT ; } +return kvm->arch.tss_addr; }
Shouldn't we already hold the srcu_lock as part of normal guest exit (similar to down_read() we do today)?
Signature · 1 line
error compiling committee.c: too many arguments to function
Re: [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update
Quoted 8 lines · Avi Kivity
Quoted 7 lines · Marcelo Tosatti
Use two steps for memslot deletion: mark the slot invalid (which stops instantiation of new shadow pages for that slot, but allows destruction), then instantiate the new empty slot.
Also simplifies
kvm_handle_hvalocking.
Quoted 6 lines
Quoted 4 lines
r = kvm_arch_prepare_memory_region(kvm,&new, old, user_alloc); if (r) goto out_free;r == 0
Huh? kvm_arch_prepare_memory_region returns a suitable error code on failure, 0 on success.
Quoted 14 lines
virt/kvm/kvm_main.c skip_lpage: · line 696
Quoted 11 lines
virt/kvm/kvm_main.c +6
-3-spin_lock (&kvm->mmu_lock); -if (mem->slot>= kvm->memslots->nmemslots) - kvm->memslots->nmemslots = mem->slot +1 ; +#ifdef CONFIG_DMAR +/* map the pages in iommu page table */ +if (npages) + r =kvm_iommu_map_pages (kvm,&new); +if (r) + goto out_free;Bad indentation.
Quoted 1 line
(still r == 0)
kvm_iommu_map_pages returns 0 on success, error code otherwise? The error code of kvm_iommu_map_pages was returned before the patchset, BTW.
Quoted 11 lines
virt/kvm/kvm_main.c skip_lpage: · line 701
Quoted 8 lines
virt/kvm/kvm_main.c +4
-2+#endif - *memslot = new; -spin_unlock (&kvm->mmu_lock); + slots =kzalloc (sizeof (struct kvm_memslots ),GFP_KERNEL ); +if (!slots) + goto out_free;goto
out_freewith r == 0.
Quoted 1 line
Best to assign r =
-ENOMEMeach time, to avoid these headaches.
Fixed.
Quoted 5 lines
Quoted 2 lines
+int
memslot_id(struct kvm *kvm, gfn_t gfn)Should be either static or
kvm_memslot_id(). But the source is already like that, so leave it.
OK.
Quoted 7 lines
Quoted 7 lines
arch/x86/kvm/mmu.c +1
-1@@ -807,23 +808,18 @@ static int kvm_handle_hva(struct kvm *kvint (*handler)(struct kvm *kvm,unsigned long *rmapp, unsigned long data)) { -int i, j; +int i, j, idx;int retval =0 ;
Quoted 8 lines
arch/x86/kvm/mmu.c static int kvm_handle_hva(struct kvm *kv · line 817
Quoted 5 lines
arch/x86/kvm/mmu.c +3
-1-struct kvm_memslots *slots = kvm->memslots; +struct kvm_memslots *slots; + + idx =srcu_read_lock (&kvm->srcu);Maybe a better place is in the mmu notifiers, so the code is shared (once other archs start to use mmu notifiers).
Done.
Quoted 17 lines
Quoted 17 lines
arch/x86/kvm/mmu.c +6
-3@@ -3020,16 +3017,20 @@ nomem:*/ unsigned int kvm_mmu_calculate_mmu_pages (struct kvm *kvm) { -int i; +int i, idx;unsigned int nr_mmu_pages;unsigned int nr_pages =0 ; +struct kvm_memslots *slots; -for (i =0 ; i< kvm->memslots->nmemslots; i++) - nr_pages += kvm->memslots->memslots[i].npages; + idx =srcu_read_lock (&kvm->srcu); + slots =rcu_dereference (kvm->memslots); +for (i =0 ; i< slots->nmemslots; i++) + nr_pages += slots->memslots[i].npages;
Quoted 8 lines
arch/x86/kvm/mmu.c nomem:
Quoted 6 lines
arch/x86/kvm/mmu.c +1
-0nr_mmu_pages = nr_pages *KVM_PERMILLE_MMU_PAGES /1000 ; nr_mmu_pages =max (nr_mmu_pages, (unsigned int )KVM_MIN_ALLOC_MMU_PAGES ); +srcu_read_unlock (&kvm->srcu, idx);Again, would like to move the
srcu_lockingto an outer scope.
This one was for documentation purposes only, since kvm_mmu_calculate_mmu_pages is only called from commit_memory_region (which mutually excludes itself).
I can remove it if you'd prefer.
Quoted 16 lines
Quoted 16 lines
arch/x86/kvm/vmx.c +9
-2@@ -1503,10 +1504,18 @@ static void enter_pmode(struct kvm_vcpustatic gva_t rmode_tss_base (struct kvm *kvm) {if (!kvm->arch.tss_addr) { -gfn_t base_gfn = kvm->memslots->memslots[0 ].base_gfn + - kvm->memslots->memslots[0 ].npages -3 ; +struct kvm_memslots *slots; +gfn_t base_gfn; +int idx; + + idx =srcu_read_lock (&kvm->srcu); + slots =rcu_dereference (kvm->memslots); + base_gfn = slots->memslots[0 ].base_gfn + + slots->memslots[0 ].npages -3 ; +srcu_read_unlock (&kvm->srcu, idx);return base_gfn<<PAGE_SHIFT ;
Quoted 8 lines
arch/x86/kvm/vmx.c static void enter_pmode(struct kvm_vcpu · line 1521
Quoted 5 lines
arch/x86/kvm/vmx.c +1
-0} +return kvm->arch.tss_addr; }Shouldn't we already hold the
srcu_lockas part of normal guest exit (similar todown_read()we do today)?
Yes, but:
kvm_arch_vcpu_setup -> vmx_vcpu_reset -> vmx_set_cr0 -> enter_pmode
So its called outside guest context path (memslot info is used outside guest context in this case).
Re: [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update
Quoted 16 lines · Marcelo Tosatti
Quoted 14 lines · Avi Kivity
Quoted 12 lines · Marcelo Tosatti
Use two steps for memslot deletion: mark the slot invalid (which stops instantiation of new shadow pages for that slot, but allows destruction), then instantiate the new empty slot.
Also simplifies
kvm_handle_hvalocking.r = kvm_arch_prepare_memory_region(kvm,&new, old, user_alloc); if (r) goto out_free;
Quoted 5 lines
Quoted 2 lines
r == 0
Huh?
kvm_arch_prepare_memory_regionreturns a suitable error code on failure, 0 on success.
That's fine here, just pointing out you're inheriting this r == 0 later on.
Quoted 3 lines
kvm_iommu_map_pagesreturns 0 on success, error code otherwise? The error code ofkvm_iommu_map_pageswas returned before the patchset, BTW.
Ok, then please fix it separately for easier backporting.
Quoted 9 lines
Quoted 9 lines
Review
Quoted 7 lines
nr_mmu_pages = nr_pages * KVM_PERMILLE_MMU_PAGES / 1000; nr_mmu_pages = max(nr_mmu_pages, (unsigned int) KVM_MIN_ALLOC_MMU_PAGES);(quoted diff) +1
-0+ srcu_read_unlock(&kvm->srcu, idx);Again, would like to move the
srcu_lockingto an outer scope.
Quoted 6 lines
This one was for documentation purposes only, since
kvm_mmu_calculate_mmu_pagesis only called fromcommit_memory_region(which mutually excludes itself).I can remove it if you'd prefer.
A comment should be sufficient. Otherwise someone might read the code and point out it's unnecessary.
Quoted 11 lines
Quoted 3 lines
Shouldn't we already hold the
srcu_lockas part of normal guest exit (similar todown_read()we do today)?Yes, but:
kvm_arch_vcpu_setup->vmx_vcpu_reset->vmx_set_cr0->enter_pmodeSo its called outside guest context path (memslot info is used outside guest context in this case).
Didn't we take slots_lock previously? If so, that's a bug. We should probably make all vcpu ioctls take slots_lock at top level, since many vcpu ioctls can be caused to access memory.
Signature · 1 line
error compiling committee.c: too many arguments to function
Re: [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update
Quoted 23 lines · Avi Kivity
Quoted 16 lines · Marcelo Tosatti
Quoted 14 lines · Avi Kivity
Quoted 12 lines · Marcelo Tosatti
Use two steps for memslot deletion: mark the slot invalid (which stops instantiation of new shadow pages for that slot, but allows destruction), then instantiate the new empty slot.
Also simplifies
kvm_handle_hvalocking.r = kvm_arch_prepare_memory_region(kvm,&new, old, user_alloc); if (r) goto out_free;Quoted 5 lines
Quoted 2 lines
r == 0
Huh?
kvm_arch_prepare_memory_regionreturns a suitable error code on failure, 0 on success.
Quoted 7 lines
That's fine here, just pointing out you're inheriting this r == 0 later on.
Quoted 3 lines
kvm_iommu_map_pagesreturns 0 on success, error code otherwise? The error code ofkvm_iommu_map_pageswas returned before the patchset, BTW.Ok, then please fix it separately for easier backporting.
Its not a bug.
Quoted 28 lines
Quoted 9 lines
Quoted 9 lines
Review
Quoted 7 lines
nr_mmu_pages = nr_pages * KVM_PERMILLE_MMU_PAGES / 1000; nr_mmu_pages = max(nr_mmu_pages, (unsigned int) KVM_MIN_ALLOC_MMU_PAGES);(quoted diff) +1
-0+ srcu_read_unlock(&kvm->srcu, idx);Again, would like to move the
srcu_lockingto an outer scope.Quoted 6 lines
This one was for documentation purposes only, since
kvm_mmu_calculate_mmu_pagesis only called fromcommit_memory_region(which mutually excludes itself).I can remove it if you'd prefer.
A comment should be sufficient. Otherwise someone might read the code and point out it's unnecessary.
Quoted 7 lines
Quoted 3 lines
Shouldn't we already hold the
srcu_lockas part of normal guest exit (similar todown_read()we do today)?Yes, but:
kvm_arch_vcpu_setup->vmx_vcpu_reset->vmx_set_cr0->enter_pmode
Quoted 8 lines
Quoted 4 lines
So its called outside guest context path (memslot info is used outside guest context in this case).
Didn't we take
slots_lockpreviously? If so, that's a bug. We should probably make all vcpu ioctls takeslots_lockat top level, since many vcpu ioctls can be caused to access memory.
vmx_vcpu_reset takes it, so again, this is for documentation purposes (its easier to make sense of srcu_read_lock + rcu_dereference together).
I'll remove it, since rcu_dereference should be enough to document the locking.
PATCH 7/11 KVM: use SRCU for dirty log
In reply to Marcelo Tosattiarch/x86/kvm/x86.c +41 -8
@@ -2416,27 +2416,60 @@ static int kvm_vm_ioctl_reinject(structint kvm_vm_ioctl_get_dirty_log (struct kvm *kvm,struct kvm_dirty_log *log) { -int r; -int n; +int r, n, i;struct kvm_memory_slot *memslot; -int is_dirty =0 ; +unsigned long is_dirty =0 ; +unsigned long *dirty_bitmap =NULL ;down_write (&kvm->slots_lock); - r =kvm_get_dirty_log (kvm, log, &is_dirty); -if (r) + r = -EINVAL ; +if (log->slot >=KVM_MEMORY_SLOTS ) + goto out; + + memslot = &kvm->memslots->memslots[log->slot]; + r = -ENOENT ; +if (!memslot->dirty_bitmap) + goto out; + + n =ALIGN (memslot->npages,BITS_PER_LONG ) /8 ; + + r = -ENOMEM ; + dirty_bitmap =vmalloc (n); +if (!dirty_bitmap) goto out; +memset (dirty_bitmap,0 , n); + +for (i =0 ; !is_dirty && i < n/sizeof (long ); i++) + is_dirty = memslot->dirty_bitmap[i];/* If nothing is dirty, don't bother messing with page tables. */ if (is_dirty) { +struct kvm_memslots *slots, *old_slots; +spin_lock (&kvm->mmu_lock);kvm_mmu_slot_remove_write_access (kvm, log->slot);spin_unlock (&kvm->mmu_lock); - memslot = &kvm->memslots->memslots[log->slot]; - n =ALIGN (memslot->npages,BITS_PER_LONG ) /8 ; -memset (memslot->dirty_bitmap,0 , n); + + slots =kzalloc (sizeof (struct kvm_memslots ),GFP_KERNEL ); +if (!slots) + goto out_free; + +memcpy (slots, kvm->memslots,sizeof (struct kvm_memslots )); + slots->memslots[log->slot].dirty_bitmap = dirty_bitmap; + + old_slots = kvm->memslots; +rcu_assign_pointer (kvm->memslots, slots); +synchronize_srcu_expedited (&kvm->srcu); + dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap; +kfree (old_slots); } + r =0 ; +if (copy_to_user (log->dirty_bitmap, dirty_bitmap, n)) + r = -EFAULT ; +out_free: +vfree (dirty_bitmap); out:up_write (&kvm->slots_lock);return r;
PATCH 8/11 KVM: x86: switch kvm_set_memory_alias to SRCU update
In reply to Marcelo TosattiUsing a similar two-step procedure as for memslots.
arch/x86/include/asm/kvm_host.h +4 -0
@@ -368,8 +368,12 @@ struct kvm_mem_alias {gfn_t base_gfn;unsigned long npages;gfn_t target_gfn; +#define KVM_ALIAS_INVALID 1UL +unsigned long flags; }; +#define KVM_ARCH_HAS_UNALIAS_INSTANTIATION +struct kvm_mem_aliases {struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS ];int naliases;
arch/x86/kvm/x86.c +51 -9
103 lines not on this page · raw message
include/linux/kvm_host.h +6 -0
@@ -265,6 +265,8 @@ void kvm_arch_commit_memory_region(strucvoid kvm_disable_largepages (void );void kvm_arch_flush_shadow (struct kvm *kvm);gfn_t unalias_gfn (struct kvm *kvm,gfn_t gfn); +gfn_t unalias_gfn_instantiation (struct kvm *kvm,gfn_t gfn); +struct page *gfn_to_page (struct kvm *kvm,gfn_t gfn);unsigned long gfn_to_hva (struct kvm *kvm,gfn_t gfn);void kvm_release_page_clean (struct page *page);
@@ -538,6 +540,10 @@ static inline int mmu_notifier_retry(str }#endif +#ifndef KVM_ARCH_HAS_UNALIAS_INSTANTIATION +#define unalias_gfn_instantiation unalias_gfn +#endif +#ifdef CONFIG_HAVE_KVM_IRQCHIP #define KVM_MAX_IRQ_ROUTES 1024
virt/kvm/kvm_main.c +2 -2
@@ -847,7 +847,7 @@ int kvm_is_visible_gfn(struct kvm *kvm,int i;struct kvm_memslots *slots =rcu_dereference (kvm->memslots); - gfn =unalias_gfn (kvm, gfn); + gfn =unalias_gfn_instantiation (kvm, gfn);for (i =0 ; i <KVM_MEMORY_SLOTS ; ++i) {struct kvm_memory_slot *memslot = &slots->memslots[i];
@@ -884,7 +884,7 @@ unsigned long gfn_to_hva(struct kvm *kvm {struct kvm_memory_slot *slot; - gfn =unalias_gfn (kvm, gfn); + gfn =unalias_gfn_instantiation (kvm, gfn); slot =gfn_to_memslot_unaliased (kvm, gfn);if (!slot || slot->flags &KVM_MEMSLOT_INVALID )return bad_hva ();
PATCH 9/11 KVM: convert io_bus to SRCU
In reply to Marcelo Tosattiarch/x86/kvm/i8254.c +3 -3
@@ -642,13 +642,13 @@ struct kvm_pit *kvm_create_pit(struct kvkvm_register_irq_mask_notifier (kvm,0 , &pit->mask_notifier);kvm_iodevice_init (&pit->dev, &pit_dev_ops); - ret =__kvm_io_bus_register_dev (&kvm->pio_bus, &pit->dev); + ret =kvm_io_bus_register_dev (kvm,KVM_PIO_BUS , &pit->dev);if (ret <0 ) goto fail;if (flags &KVM_PIT_SPEAKER_DUMMY ) {kvm_iodevice_init (&pit->speaker_dev, &speaker_dev_ops); - ret =__kvm_io_bus_register_dev (&kvm->pio_bus, + ret =kvm_io_bus_register_dev (kvm,KVM_PIO_BUS , &pit->speaker_dev);if (ret <0 ) goto fail_unregister;
@@ -657,7 +657,7 @@ struct kvm_pit *kvm_create_pit(struct kvreturn pit; fail_unregister: -__kvm_io_bus_unregister_dev (&kvm->pio_bus, &pit->dev); +kvm_io_bus_unregister_dev (kvm,KVM_PIO_BUS , &pit->dev); fail:if (pit->irq_source_id >=0 )
arch/x86/kvm/i8259.c +3 -1
@@ -533,7 +533,9 @@ struct kvm_pic *kvm_create_pic(struct kv* Initialize PIO device */ kvm_iodevice_init (&s->dev, &picdev_ops); - ret =kvm_io_bus_register_dev (kvm, &kvm->pio_bus, &s->dev); +down_write (&kvm->slots_lock); + ret =kvm_io_bus_register_dev (kvm,KVM_PIO_BUS , &s->dev); +up_write (&kvm->slots_lock);if (ret <0 ) {kfree (s);return NULL ;
include/linux/kvm_host.h +13 -14
@@ -57,20 +57,20 @@ struct kvm_io_bus {struct kvm_io_device *devs[NR_IOBUS_DEVS ]; }; -void kvm_io_bus_init (struct kvm_io_bus *bus); -void kvm_io_bus_destroy (struct kvm_io_bus *bus); -int kvm_io_bus_write (struct kvm_io_bus *bus,gpa_t addr,int len, -const void *val); -int kvm_io_bus_read (struct kvm_io_bus *bus,gpa_t addr,int len, +enum kvm_bus { +KVM_MMIO_BUS , +KVM_PIO_BUS , +KVM_NR_BUSES +}; + +int kvm_io_bus_write (struct kvm *kvm,enum kvm_bus bus_idx,gpa_t addr, +int len,const void *val); +int kvm_io_bus_read (struct kvm *kvm,enum kvm_bus bus_idx,gpa_t addr,int len,void *val); -int __kvm_io_bus_register_dev (struct kvm_io_bus *bus, -struct kvm_io_device *dev); -int kvm_io_bus_register_dev (struct kvm *kvm,struct kvm_io_bus *bus, +int kvm_io_bus_register_dev (struct kvm *kvm,enum kvm_bus bus_idx,struct kvm_io_device *dev); -void __kvm_io_bus_unregister_dev (struct kvm_io_bus *bus, -struct kvm_io_device *dev); -void kvm_io_bus_unregister_dev (struct kvm *kvm,struct kvm_io_bus *bus, -struct kvm_io_device *dev); +int kvm_io_bus_unregister_dev (struct kvm *kvm,enum kvm_bus bus_idx, +struct kvm_io_device *dev);struct kvm_vcpu {struct kvm *kvm;
@@ -171,8 +171,7 @@ struct kvm {atomic_t online_vcpus;struct list_head vm_list;struct mutex lock; -struct kvm_io_bus mmio_bus; -struct kvm_io_bus pio_bus; +struct kvm_io_bus *buses[KVM_NR_BUSES ]; #ifdef CONFIG_HAVE_KVM_EVENTFD struct { spinlock_t lock;
virt/kvm/eventfd.c +4 -4
@@ -451,7 +451,7 @@ static int kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) { int pio = args->flags & KVM_IOEVENTFD_FLAG_PIO; -struct kvm_io_bus *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus; +enum kvm_bus bus_idx = pio ?KVM_PIO_BUS :KVM_MMIO_BUS ;struct _ioeventfd *p;struct eventfd_ctx *eventfd;int ret;
@@ -506,7 +506,7 @@ kvm_assign_ioeventfd(struct kvm *kvm, stkvm_iodevice_init (&p->dev, &ioeventfd_ops); - ret =__kvm_io_bus_register_dev (bus, &p->dev); + ret =kvm_io_bus_register_dev (kvm, bus_idx, &p->dev);if (ret <0 ) goto unlock_fail;
@@ -530,7 +530,7 @@ static int kvm_deassign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) { int pio = args->flags & KVM_IOEVENTFD_FLAG_PIO; -struct kvm_io_bus *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus; +enum kvm_bus bus_idx = pio ?KVM_PIO_BUS :KVM_MMIO_BUS ;struct _ioeventfd *p, *tmp;struct eventfd_ctx *eventfd;int ret = -ENOENT ;
@@ -553,7 +553,7 @@ kvm_deassign_ioeventfd(struct kvm *kvm,if (!p->wildcard && p->datamatch != args->datamatch)continue ; -__kvm_io_bus_unregister_dev (bus, &p->dev); +kvm_io_bus_unregister_dev (kvm, bus_idx, &p->dev);ioeventfd_release (p); ret =0 ;break ;
virt/kvm/ioapic.c +3 -1
@@ -372,7 +372,9 @@ int kvm_ioapic_init(struct kvm *kvm)kvm_ioapic_reset (ioapic);kvm_iodevice_init (&ioapic->dev, &ioapic_mmio_ops); ioapic->kvm = kvm; - ret =kvm_io_bus_register_dev (kvm, &kvm->mmio_bus, &ioapic->dev); +down_write (&kvm->slots_lock); + ret =kvm_io_bus_register_dev (kvm,KVM_MMIO_BUS , &ioapic->dev); +up_write (&kvm->slots_lock);if (ret <0 )kfree (ioapic);
virt/kvm/kvm_main.c +63 -43
197 lines not on this page · raw message
virt/kvm/coalesced_mmio.c +3 -1
@@ -110,7 +110,9 @@ int kvm_coalesced_mmio_init(struct kvm * dev->kvm = kvm; kvm->coalesced_mmio_dev = dev; - ret =kvm_io_bus_register_dev (kvm, &kvm->mmio_bus, &dev->dev); +down_write (&kvm->slots_lock); + ret =kvm_io_bus_register_dev (kvm,KVM_MMIO_BUS , &dev->dev); +up_write (&kvm->slots_lock);if (ret <0 ) goto out_free_dev;
arch/x86/kvm/x86.c +7 -6
@@ -2852,7 +2852,7 @@ static int vcpu_mmio_write(struct kvm_vc !kvm_iodevice_write(&vcpu->arch.apic->dev, addr, len, v))return 0 ; -return kvm_io_bus_write (&vcpu->kvm->mmio_bus, addr, len, v); +return kvm_io_bus_write (vcpu->kvm,KVM_MMIO_BUS , addr, len, v); }static int vcpu_mmio_read (struct kvm_vcpu *vcpu,gpa_t addr,int len,void *v)
@@ -2861,7 +2861,7 @@ static int vcpu_mmio_read(struct kvm_vcp !kvm_iodevice_read(&vcpu->arch.apic->dev, addr, len, v))return 0 ; -return kvm_io_bus_read (&vcpu->kvm->mmio_bus, addr, len, v); +return kvm_io_bus_read (vcpu->kvm,KVM_MMIO_BUS , addr, len, v); } static int kvm_read_guest_virt(gva_t addr, void *val, unsigned int bytes,
@@ -3346,11 +3346,12 @@ static int kernel_pio(struct kvm_vcpu *vint r;if (vcpu->arch.pio.in) - r =kvm_io_bus_read (&vcpu->kvm->pio_bus, vcpu->arch.pio.port, + r =kvm_io_bus_read (vcpu->kvm,KVM_PIO_BUS , vcpu->arch.pio.port, vcpu->arch.pio.size, pd);else - r =kvm_io_bus_write (&vcpu->kvm->pio_bus, vcpu->arch.pio.port, - vcpu->arch.pio.size, pd); + r =kvm_io_bus_write (vcpu->kvm,KVM_PIO_BUS , + vcpu->arch.pio.port, vcpu->arch.pio.size, + pd);return r; }
@@ -3361,7 +3362,7 @@ static int pio_string_write(struct kvm_vint i, r =0 ;for (i =0 ; i < io->cur_count; i++) { -if (kvm_io_bus_write (&vcpu->kvm->pio_bus, +if (kvm_io_bus_write (vcpu->kvm,KVM_PIO_BUS , io->port, io->size, pd)) { r = -EOPNOTSUPP ;break ;
arch/ia64/kvm/kvm-ia64.c +2 -2
@@ -241,10 +241,10 @@ static int handle_mmio(struct kvm_vcpu *return 0 ; mmio:if (p->dir) - r =kvm_io_bus_read (&vcpu->kvm->mmio_bus, p->addr, + r =kvm_io_bus_read (vcpu->kvm,KVM_MMIO_BUS , p->addr, p->size, &p->data);else - r =kvm_io_bus_write (&vcpu->kvm->mmio_bus, p->addr, + r =kvm_io_bus_write (vcpu->kvm,KVM_MMIO_BUS , p->addr, p->size, &p->data);if (r)printk (KERN_ERR "kvm: No iodevice found! addr:%lx\n" , p->addr);
PATCH 10/11 KVM: switch vcpu context to use SRCU
In reply to Marcelo Tosattiarch/x86/kvm/x86.c +24 -19
@@ -1307,15 +1307,15 @@ static int __msr_io(struct kvm_vcpu *vcpint (*do_msr)(struct kvm_vcpu *vcpu, unsigned index, u64 *data)) { -int i; +int i, idx;vcpu_load (vcpu); -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu);for (i =0 ; i < msrs->nmsrs; ++i)if (do_msr (vcpu, entries[i].index, &entries[i].data))break ; -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx);vcpu_put (vcpu);
@@ -3901,14 +3901,15 @@ static void vapic_enter(struct kvm_vcpustatic void vapic_exit (struct kvm_vcpu *vcpu) {struct kvm_lapic *apic = vcpu->arch.apic; +int idx;if (!apic || !apic->vapic_addr)return ; -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu);kvm_release_page_dirty (apic->vapic_page);mark_page_dirty (vcpu->kvm, apic->vapic_addr >>PAGE_SHIFT ); -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx); }static void update_cr8_intercept (struct kvm_vcpu *vcpu)
@@ -4037,7 +4038,7 @@ static int vcpu_enter_guest(struct kvm_vkvm_lapic_sync_to_vapic (vcpu); } -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, vcpu->srcu_idx);kvm_guest_enter ();
@@ -4079,7 +4080,7 @@ static int vcpu_enter_guest(struct kvm_vpreempt_enable (); -down_read (&vcpu->kvm->slots_lock); + vcpu->srcu_idx =srcu_read_lock (&vcpu->kvm->srcu);/* * Profile KVM exit RIPs:
@@ -4101,6 +4102,7 @@ out:static int __vcpu_run (struct kvm_vcpu *vcpu) {int r; +struct kvm *kvm = vcpu->kvm;if (unlikely (vcpu->arch.mp_state ==KVM_MP_STATE_SIPI_RECEIVED )) { pr_debug("vcpu %d received sipi with vector # %x\n",
@@ -4112,7 +4114,7 @@ static int __vcpu_run(struct kvm_vcpu *v vcpu->arch.mp_state =KVM_MP_STATE_RUNNABLE ; } -down_read (&vcpu->kvm->slots_lock); + vcpu->srcu_idx =srcu_read_lock (&kvm->srcu);vapic_enter (vcpu); r =1 ;
@@ -4120,9 +4122,9 @@ static int __vcpu_run(struct kvm_vcpu *vif (vcpu->arch.mp_state ==KVM_MP_STATE_RUNNABLE ) r =vcpu_enter_guest (vcpu);else { -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&kvm->srcu, vcpu->srcu_idx);kvm_vcpu_block (vcpu); -down_read (&vcpu->kvm->slots_lock); + vcpu->srcu_idx =srcu_read_lock (&kvm->srcu);if (test_and_clear_bit (KVM_REQ_UNHALT , &vcpu->requests)) {switch (vcpu->arch.mp_state) {
@@ -4157,13 +4159,13 @@ static int __vcpu_run(struct kvm_vcpu *v ++vcpu->stat.signal_exits; }if (need_resched ()) { -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&kvm->srcu, vcpu->srcu_idx);kvm_resched (vcpu); -down_read (&vcpu->kvm->slots_lock); + vcpu->srcu_idx =srcu_read_lock (&kvm->srcu); } } -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&kvm->srcu, vcpu->srcu_idx);post_kvm_run_save (vcpu);vapic_exit (vcpu);
@@ -4202,10 +4204,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_v vcpu->mmio_read_completed =1 ; vcpu->mmio_needed =0 ; -down_read (&vcpu->kvm->slots_lock); + vcpu->srcu_idx =srcu_read_lock (&vcpu->kvm->srcu); r =emulate_instruction (vcpu, vcpu->arch.mmio_fault_cr2,0 ,EMULTYPE_NO_DECODE ); -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, vcpu->srcu_idx);if (r ==EMULATE_DO_MMIO ) {/* * Read-modify-write. Back to userspace.
@@ -4968,11 +4970,12 @@ int kvm_arch_vcpu_ioctl_translate(struct {unsigned long vaddr = tr->linear_address;gpa_t gpa; +int idx;vcpu_load (vcpu); -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu); gpa = vcpu->arch.mmu.gva_to_gpa (vcpu, vaddr); -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx); tr->physical_address = gpa; tr->valid = gpa !=UNMAPPED_GVA ; tr->writeable =1 ;
@@ -5223,10 +5226,12 @@ fail:void kvm_arch_vcpu_uninit (struct kvm_vcpu *vcpu) { +int idx; +kvm_free_lapic (vcpu); -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu);kvm_mmu_destroy (vcpu); -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx);free_page ((unsigned long )vcpu->arch.pio_data); }
include/linux/kvm_host.h +2 -0
@@ -83,6 +83,8 @@ struct kvm_vcpu {struct kvm_run *run;unsigned long requests;unsigned long guest_debug; +int srcu_idx; +int fpu_active;int guest_fpu_loaded;wait_queue_head_t wq;
arch/x86/kvm/mmu.c +3 -4
@@ -2937,10 +2937,9 @@ static int mmu_shrink(int nr_to_scan, gfspin_lock (&kvm_lock);list_for_each_entry (kvm, &vm_list, vm_list) { -int npages; +int npages, idx; -if (!down_read_trylock (&kvm->slots_lock)) -continue ; + idx =srcu_read_lock (&kvm->srcu);spin_lock (&kvm->mmu_lock); npages = kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages;
@@ -2953,7 +2952,7 @@ static int mmu_shrink(int nr_to_scan, gf nr_to_scan--;spin_unlock (&kvm->mmu_lock); -up_read (&kvm->slots_lock); +srcu_read_unlock (&kvm->srcu, idx); }if (kvm_freed)list_move_tail (&kvm_freed->vm_list, &vm_list);
arch/x86/kvm/vmx.c +3 -3
@@ -2482,10 +2482,10 @@ static int vmx_vcpu_reset(struct kvm_vcp {struct vcpu_vmx *vmx =to_vmx (vcpu);u64 msr; -int ret; +int ret, idx; vcpu->arch.regs_avail = ~((1 <<VCPU_REGS_RIP ) | (1 <<VCPU_REGS_RSP )); -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu);if (!init_rmode (vmx->vcpu.kvm)) { ret = -ENOMEM ; goto out;
@@ -2593,7 +2593,7 @@ static int vmx_vcpu_reset(struct kvm_vcp vmx->emulation_required =0 ; out: -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx);return ret; }
arch/ia64/kvm/kvm-ia64.c +6 -9
@@ -636,12 +636,9 @@ static void kvm_vcpu_post_transition(strstatic int __vcpu_run (struct kvm_vcpu *vcpu,struct kvm_run *kvm_run) {union context *host_ctx, *guest_ctx; -int r; +int r, idx; -/* -* down_read() may sleep and return with interrupts enabled -*/ -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu); again:if (signal_pending (current)) {
@@ -663,7 +660,7 @@ again:if (r <0 ) goto vcpu_run_fail; -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx);kvm_guest_enter ();/*
@@ -687,7 +684,7 @@ again:kvm_guest_exit ();preempt_enable (); -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu); r =kvm_handle_exit (kvm_run, vcpu);
@@ -697,10 +694,10 @@ again: } out: -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx);if (r >0 ) {kvm_resched (vcpu); -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu); goto again; }
arch/s390/kvm/kvm-s390.h +7 -3
@@ -67,10 +67,14 @@ static inline long kvm_s390_vcpu_get_memstatic inline void kvm_s390_vcpu_set_mem (struct kvm_vcpu *vcpu) { +int idx;struct kvm_memory_slot *mem; +struct kvm_memory_slots *memslots; -down_read (&vcpu->kvm->slots_lock); - mem = &vcpu->kvm->memslots[0 ]; + idx =srcu_read_lock (&vcpu->kvm->srcu); + memslots =rcu_dereference (vcpu->kvm->memslots); + + mem = &memslots->memslots[0 ]; vcpu->arch.sie_block->gmsor = mem->userspace_addr; vcpu->arch.sie_block->gmslm =
@@ -78,7 +82,7 @@ static inline void kvm_s390_vcpu_set_mem (mem->npages <<PAGE_SHIFT ) +VIRTIODESCSPACE -1ul ; -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx); }/* implemented in priv.c */
PATCH 11/11 KVM: convert slots_lock to a mutex
In reply to Marcelo Tosattiarch/x86/kvm/vmx.c +4 -4
@@ -2227,7 +2227,7 @@ static int alloc_apic_access_page(structstruct kvm_userspace_memory_region kvm_userspace_mem;int r =0 ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);if (kvm->arch.apic_access_page) goto out; kvm_userspace_mem.slot =APIC_ACCESS_PAGE_PRIVATE_MEMSLOT ;
@@ -2240,7 +2240,7 @@ static int alloc_apic_access_page(struct kvm->arch.apic_access_page =gfn_to_page (kvm,0xfee00 ); out: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return r; }
@@ -2249,7 +2249,7 @@ static int alloc_identity_pagetable(strustruct kvm_userspace_memory_region kvm_userspace_mem;int r =0 ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);if (kvm->arch.ept_identity_pagetable) goto out; kvm_userspace_mem.slot =IDENTITY_PAGETABLE_PRIVATE_MEMSLOT ;
@@ -2264,7 +2264,7 @@ static int alloc_identity_pagetable(stru kvm->arch.ept_identity_pagetable =gfn_to_page (kvm, kvm->arch.ept_identity_map_addr >>PAGE_SHIFT ); out: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return r; }
arch/x86/kvm/x86.c +8 -8
@@ -2209,14 +2209,14 @@ static int kvm_vm_ioctl_set_nr_mmu_pagesif (kvm_nr_mmu_pages <KVM_MIN_ALLOC_MMU_PAGES )return -EINVAL ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);spin_lock (&kvm->mmu_lock);kvm_mmu_change_mmu_pages (kvm, kvm_nr_mmu_pages); kvm->arch.n_requested_mmu_pages = kvm_nr_mmu_pages;spin_unlock (&kvm->mmu_lock); -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return 0 ; }
@@ -2293,7 +2293,7 @@ static int kvm_vm_ioctl_set_memory_aliasif (!aliases) goto out; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);/* invalidate any gfn reference in case of deletion/shrinking */ memcpy (aliases, kvm->arch.aliases,sizeof (struct kvm_mem_aliases ));
@@ -2329,7 +2329,7 @@ static int kvm_vm_ioctl_set_memory_alias r =0 ; out_unlock: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock); out:return r; }
@@ -2463,7 +2463,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvunsigned long is_dirty =0 ;unsigned long *dirty_bitmap =NULL ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); r = -EINVAL ;if (log->slot >=KVM_MEMORY_SLOTS )
@@ -2513,7 +2513,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kv out_free:vfree (dirty_bitmap); out: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return r; }
@@ -2626,7 +2626,7 @@ long kvm_arch_vm_ioctl(struct file *filp sizeof(struct kvm_pit_config))) goto out; create_pit: -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); r = -EEXIST ;if (kvm->arch.vpit) goto create_pit_unlock;
@@ -2635,7 +2635,7 @@ long kvm_arch_vm_ioctl(struct file *filpif (kvm->arch.vpit) r =0 ; create_pit_unlock: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);break ;case KVM_IRQ_LINE_STATUS :case KVM_IRQ_LINE : {
include/linux/kvm_host.h +1 -1
@@ -161,7 +161,7 @@ struct kvm_memslots {struct kvm {spinlock_t mmu_lock;spinlock_t requests_lock; -struct rw_semaphore slots_lock; +struct mutex slots_lock;struct mm_struct *mm;/* userspace tied to this vm */ struct kvm_memslots *memslots;struct srcu_struct srcu;
virt/kvm/coalesced_mmio.c +7 -7
@@ -110,9 +110,9 @@ int kvm_coalesced_mmio_init(struct kvm * dev->kvm = kvm; kvm->coalesced_mmio_dev = dev; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); ret =kvm_io_bus_register_dev (kvm,KVM_MMIO_BUS , &dev->dev); -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);if (ret <0 ) goto out_free_dev;
@@ -140,16 +140,16 @@ int kvm_vm_ioctl_register_coalesced_mmioif (dev ==NULL )return -EINVAL ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);if (dev->nb_zones >=KVM_COALESCED_MMIO_ZONE_MAX ) { -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return -ENOBUFS ; } dev->zone[dev->nb_zones] = *zone; dev->nb_zones++; -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return 0 ; }
@@ -163,7 +163,7 @@ int kvm_vm_ioctl_unregister_coalesced_mmif (dev ==NULL )return -EINVAL ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); i = dev->nb_zones;while (i) {
@@ -181,7 +181,7 @@ int kvm_vm_ioctl_unregister_coalesced_mm i--; } -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return 0 ; }
virt/kvm/eventfd.c +5 -5
@@ -496,7 +496,7 @@ kvm_assign_ioeventfd(struct kvm *kvm, stelse p->wildcard = true; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);/* Verify that there isnt a match already */ if (ioeventfd_check_collision (kvm, p)) {
@@ -512,12 +512,12 @@ kvm_assign_ioeventfd(struct kvm *kvm, stlist_add_tail (&p->list, &kvm->ioeventfds); -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return 0 ; unlock_fail: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock); fail:kfree (p);
@@ -539,7 +539,7 @@ kvm_deassign_ioeventfd(struct kvm *kvm,if (IS_ERR (eventfd))return PTR_ERR (eventfd); -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);list_for_each_entry_safe (p, tmp, &kvm->ioeventfds, list) {bool wildcard = !(args->flags &KVM_IOEVENTFD_FLAG_DATAMATCH );
@@ -559,7 +559,7 @@ kvm_deassign_ioeventfd(struct kvm *kvm,break ; } -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);eventfd_ctx_put (eventfd);
virt/kvm/ioapic.c +2 -2
@@ -372,9 +372,9 @@ int kvm_ioapic_init(struct kvm *kvm)kvm_ioapic_reset (ioapic);kvm_iodevice_init (&ioapic->dev, &ioapic_mmio_ops); ioapic->kvm = kvm; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); ret =kvm_io_bus_register_dev (kvm,KVM_MMIO_BUS , &ioapic->dev); -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);if (ret <0 )kfree (ioapic);
virt/kvm/kvm_main.c +5 -5
@@ -420,7 +420,7 @@ static struct kvm *kvm_create_vm(void)kvm_eventfd_init (kvm);mutex_init (&kvm->lock);mutex_init (&kvm->irq_lock); -init_rwsem (&kvm->slots_lock); +mutex_init (&kvm->slots_lock);atomic_set (&kvm->users_count,1 );spin_lock (&kvm_lock);list_add (&kvm->vm_list, &vm_list);
@@ -751,9 +751,9 @@ int kvm_set_memory_region(struct kvm *kv {int r; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); r =__kvm_set_memory_region (kvm, mem, user_alloc); -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return r; }EXPORT_SYMBOL_GPL (kvm_set_memory_region);
@@ -1985,7 +1985,7 @@ int kvm_io_bus_read(struct kvm *kvm, enureturn -EOPNOTSUPP ; } -/* Caller must have write lock on slots_lock. */ +/* Caller must hold slots_lock. */ int kvm_io_bus_register_dev (struct kvm *kvm,enum kvm_bus bus_idx,struct kvm_io_device *dev) {
@@ -2007,7 +2007,7 @@ int kvm_io_bus_register_dev(struct kvm *return 0 ; } -/* Caller must have write lock on slots_lock. */ +/* Caller must hold slots_lock. */ int kvm_io_bus_unregister_dev (struct kvm *kvm,enum kvm_bus bus_idx,struct kvm_io_device *dev) {
arch/ia64/kvm/kvm-ia64.c +2 -2
@@ -1831,7 +1831,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvstruct kvm_memory_slot *memslot;int is_dirty =0 ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);spin_lock (&kvm->arch.dirty_log_lock); r =kvm_ia64_sync_dirty_log (kvm, log);
@@ -1851,7 +1851,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kv } r =0 ; out: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);spin_unlock (&kvm->arch.dirty_log_lock);return r; }
arch/x86/kvm/i8254.c +1 -1
@@ -602,7 +602,7 @@ static const struct kvm_io_device_ops sp .write = speaker_ioport_write, }; -/* Caller must have writers lock on slots_lock */ +/* Caller must hold slots_lock */ struct kvm_pit *kvm_create_pit (struct kvm *kvm,u32 flags) {struct kvm_pit *pit;
arch/x86/kvm/i8259.c +2 -2
@@ -533,9 +533,9 @@ struct kvm_pic *kvm_create_pic(struct kv* Initialize PIO device */ kvm_iodevice_init (&s->dev, &picdev_ops); -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); ret =kvm_io_bus_register_dev (kvm,KVM_PIO_BUS , &s->dev); -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);if (ret <0 ) {kfree (s);return NULL ;
Quoted 4 lines · Marcelo Tosatti
Now that
synchronize_srcu_expeditedis in the tree, we can continue the convertion ofslots_lockto SRCU.
Okay, looks pretty good. The only issue I see is where to put srcu_read_lock()s:
- outer scope (more reuse for archs, less places to forget)
- inner scope (tighter code)
There is now a mix of the two.
Quoted 10 lines
Results:
up:vmcall 6.1% improvement
smp 2:
vmcall 9.3% improvement
Pretty impressive, all this from removing an uncontended semaphore.
Signature · 1 line
error compiling committee.c: too many arguments to function
cover convert slotslock to SRCU v2
In reply to Marcelo TosattiAddressing comments.
PATCH 1/11 KVM: modify memslots layout in struct kvm
Have a pointer to an allocated region inside struct kvm.
arch/x86/kvm/mmu.c +6 -5
@@ -809,13 +809,14 @@ static int kvm_handle_hva(struct kvm *kv {int i, j;int retval =0 ; +struct kvm_memslots *slots = kvm->memslots;/* * If mmap_sem isn't taken, we can look the memslots with only * the mmu_lock by skipping over the slots with userspace_addr == 0. */ -for (i =0 ; i < kvm->nmemslots; i++) { -struct kvm_memory_slot *memslot = &kvm->memslots[i]; +for (i =0 ; i < slots->nmemslots; i++) { +struct kvm_memory_slot *memslot = &slots->memslots[i];unsigned long start = memslot->userspace_addr;unsigned long end;
@@ -3023,8 +3024,8 @@ unsigned int kvm_mmu_calculate_mmu_pagesunsigned int nr_mmu_pages;unsigned int nr_pages =0 ; -for (i =0 ; i < kvm->nmemslots; i++) - nr_pages += kvm->memslots[i].npages; +for (i =0 ; i < kvm->memslots->nmemslots; i++) + nr_pages += kvm->memslots->memslots[i].npages; nr_mmu_pages = nr_pages *KVM_PERMILLE_MMU_PAGES /1000 ; nr_mmu_pages = max(nr_mmu_pages,
@@ -3297,7 +3298,7 @@ static int count_rmaps(struct kvm_vcpu *int i, j, k;for (i =0 ; i <KVM_MEMORY_SLOTS ; ++i) { -struct kvm_memory_slot *m = &vcpu->kvm->memslots[i]; +struct kvm_memory_slot *m = &vcpu->kvm->memslots->memslots[i];struct kvm_rmap_desc *d;for (j =0 ; j < m->npages; ++j) {
arch/x86/kvm/vmx.c +2 -2
@@ -1503,8 +1503,8 @@ static void enter_pmode(struct kvm_vcpustatic gva_t rmode_tss_base (struct kvm *kvm) {if (!kvm->arch.tss_addr) { -gfn_t base_gfn = kvm->memslots[0 ].base_gfn + - kvm->memslots[0 ].npages -3 ; +gfn_t base_gfn = kvm->memslots->memslots[0 ].base_gfn + + kvm->memslots->memslots[0 ].npages -3 ;return base_gfn <<PAGE_SHIFT ; }return kvm->arch.tss_addr;
arch/x86/kvm/x86.c +2 -2
@@ -2428,7 +2428,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvspin_lock (&kvm->mmu_lock);kvm_mmu_slot_remove_write_access (kvm, log->slot);spin_unlock (&kvm->mmu_lock); - memslot = &kvm->memslots[log->slot]; + memslot = &kvm->memslots->memslots[log->slot]; n =ALIGN (memslot->npages,BITS_PER_LONG ) /8 ;memset (memslot->dirty_bitmap,0 , n); }
@@ -5222,7 +5222,7 @@ int kvm_arch_set_memory_region(struct kv int user_alloc) {int npages = mem->memory_size >>PAGE_SHIFT ; -struct kvm_memory_slot *memslot = &kvm->memslots[mem->slot]; +struct kvm_memory_slot *memslot = &kvm->memslots->memslots[mem->slot];/*To keep backward compatibility with older userspace, *x86 needs to hanlde !user_alloc case.
include/linux/kvm_host.h +8 -4
@@ -150,14 +150,18 @@ struct kvm_irq_routing_table {};#endif +struct kvm_memslots { +int nmemslots; +struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS + +KVM_PRIVATE_MEM_SLOTS ]; +}; +struct kvm {spinlock_t mmu_lock;spinlock_t requests_lock;struct rw_semaphore slots_lock;struct mm_struct *mm;/* userspace tied to this vm */ -int nmemslots; -struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS + -KVM_PRIVATE_MEM_SLOTS ]; +struct kvm_memslots *memslots;#ifdef CONFIG_KVM_APIC_ARCHITECTURE u32 bsp_vcpu_id;struct kvm_vcpu *bsp_vcpu;
@@ -482,7 +486,7 @@ static inline void kvm_guest_exit(void)static inline int memslot_id (struct kvm *kvm,struct kvm_memory_slot *slot) { -return slot - kvm->memslots; +return slot - kvm->memslots->memslots; }static inline gpa_t gfn_to_gpa (gfn_t gfn)
virt/kvm/iommu.c +12 -6
@@ -76,10 +76,13 @@ unmap_pages:static int kvm_iommu_map_memslots (struct kvm *kvm) {int i, r =0 ; +struct kvm_memslots *slots; -for (i =0 ; i < kvm->nmemslots; i++) { - r =kvm_iommu_map_pages (kvm, kvm->memslots[i].base_gfn, - kvm->memslots[i].npages); + slots = kvm->memslots; + +for (i =0 ; i < slots->nmemslots; i++) { + r =kvm_iommu_map_pages (kvm, slots->memslots[i].base_gfn, + slots->memslots[i].npages);if (r)break ; }
@@ -210,10 +213,13 @@ static void kvm_iommu_put_pages(struct kstatic int kvm_iommu_unmap_memslots (struct kvm *kvm) {int i; +struct kvm_memslots *slots; + + slots = kvm->memslots; -for (i =0 ; i < kvm->nmemslots; i++) { -kvm_iommu_put_pages (kvm, kvm->memslots[i].base_gfn, - kvm->memslots[i].npages); +for (i =0 ; i < slots->nmemslots; i++) { +kvm_iommu_put_pages (kvm, slots->memslots[i].base_gfn, + slots->memslots[i].npages); }return 0 ;
virt/kvm/kvm_main.c +23 -13
@@ -375,12 +375,16 @@ static struct kvm *kvm_create_vm(void)INIT_HLIST_HEAD (&kvm->irq_ack_notifier_list);#endif + r = -ENOMEM ; + kvm->memslots =kzalloc (sizeof (struct kvm_memslots ),GFP_KERNEL ); +if (!kvm->memslots) + goto out_err; +#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET page =alloc_page (GFP_KERNEL | __GFP_ZERO); -if (!page) { - r = -ENOMEM ; +if (!page) goto out_err; - } + kvm->coalesced_mmio_ring = (struct kvm_coalesced_mmio_ring *)page_address (page);#endif
@@ -416,6 +420,7 @@ out: out_err:hardware_disable_all (); out_err_nodisable: +kfree (kvm->memslots);kfree (kvm);return ERR_PTR (r); }
@@ -450,9 +455,12 @@ static void kvm_free_physmem_slot(structvoid kvm_free_physmem (struct kvm *kvm) {int i; +struct kvm_memslots *slots = kvm->memslots; + +for (i =0 ; i < slots->nmemslots; ++i) +kvm_free_physmem_slot (&slots->memslots[i],NULL ); -for (i =0 ; i < kvm->nmemslots; ++i) -kvm_free_physmem_slot (&kvm->memslots[i],NULL ); +kfree (kvm->memslots); }static void kvm_destroy_vm (struct kvm *kvm)
@@ -533,7 +541,7 @@ int __kvm_set_memory_region(struct kvm *if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr) goto out; - memslot = &kvm->memslots[mem->slot]; + memslot = &kvm->memslots->memslots[mem->slot]; base_gfn = mem->guest_phys_addr >>PAGE_SHIFT ; npages = mem->memory_size >>PAGE_SHIFT ;
@@ -554,7 +562,7 @@ int __kvm_set_memory_region(struct kvm */* Check for overlaps */ r = -EEXIST ;for (i =0 ; i <KVM_MEMORY_SLOTS ; ++i) { -struct kvm_memory_slot *s = &kvm->memslots[i]; +struct kvm_memory_slot *s = &kvm->memslots->memslots[i];if (s == memslot || !s->npages)continue ;
@@ -656,8 +664,8 @@ skip_lpage:kvm_arch_flush_shadow (kvm);spin_lock (&kvm->mmu_lock); -if (mem->slot >= kvm->nmemslots) - kvm->nmemslots = mem->slot +1 ; +if (mem->slot >= kvm->memslots->nmemslots) + kvm->memslots->nmemslots = mem->slot +1 ; *memslot = new;spin_unlock (&kvm->mmu_lock);
@@ -727,7 +735,7 @@ int kvm_get_dirty_log(struct kvm *kvm,if (log->slot >=KVM_MEMORY_SLOTS ) goto out; - memslot = &kvm->memslots[log->slot]; + memslot = &kvm->memslots->memslots[log->slot]; r = -ENOENT ;if (!memslot->dirty_bitmap) goto out;
@@ -781,9 +789,10 @@ EXPORT_SYMBOL_GPL(kvm_is_error_hva);struct kvm_memory_slot *gfn_to_memslot_unaliased (struct kvm *kvm,gfn_t gfn) {int i; +struct kvm_memslots *slots = kvm->memslots; -for (i =0 ; i < kvm->nmemslots; ++i) { -struct kvm_memory_slot *memslot = &kvm->memslots[i]; +for (i =0 ; i < slots->nmemslots; ++i) { +struct kvm_memory_slot *memslot = &slots->memslots[i];if (gfn >= memslot->base_gfn && gfn < memslot->base_gfn + memslot->npages)
@@ -802,10 +811,11 @@ struct kvm_memory_slot *gfn_to_memslot(sint kvm_is_visible_gfn (struct kvm *kvm,gfn_t gfn) {int i; +struct kvm_memslots *slots = kvm->memslots; gfn =unalias_gfn (kvm, gfn);for (i =0 ; i <KVM_MEMORY_SLOTS ; ++i) { -struct kvm_memory_slot *memslot = &kvm->memslots[i]; +struct kvm_memory_slot *memslot = &slots->memslots[i];if (gfn >= memslot->base_gfn && gfn < memslot->base_gfn + memslot->npages)
PATCH 2/11 KVM: modify alias layout in x86s struct kvm_arch
In reply to Marcelo TosattiHave a pointer to an allocated region inside x86's kvm_arch.
arch/x86/include/asm/kvm_host.h +6 -2
@@ -370,9 +370,13 @@ struct kvm_mem_alias {gfn_t target_gfn; }; -struct kvm_arch { -int naliases; +struct kvm_mem_aliases {struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS ]; +int naliases; +}; + +struct kvm_arch { +struct kvm_mem_aliases *aliases;unsigned int n_free_mmu_pages;unsigned int n_requested_mmu_pages;
arch/x86/kvm/x86.c +16 -5
@@ -2228,9 +2228,10 @@ gfn_t unalias_gfn(struct kvm *kvm, gfn_t {int i;struct kvm_mem_alias *alias; +struct kvm_mem_aliases *aliases = kvm->arch.aliases; -for (i =0 ; i < kvm->arch.naliases; ++i) { - alias = &kvm->arch.aliases[i]; +for (i =0 ; i < aliases->naliases; ++i) { + alias = &aliases->aliases[i];if (gfn >= alias->base_gfn && gfn < alias->base_gfn + alias->npages)return alias->target_gfn + gfn - alias->base_gfn;
@@ -2248,6 +2249,7 @@ static int kvm_vm_ioctl_set_memory_alias {int r, n;struct kvm_mem_alias *p; +struct kvm_mem_aliases *aliases; r = -EINVAL ;/* General sanity checks */
@@ -2267,15 +2269,17 @@ static int kvm_vm_ioctl_set_memory_aliasdown_write (&kvm->slots_lock);spin_lock (&kvm->mmu_lock); - p = &kvm->arch.aliases[alias->slot]; + aliases = kvm->arch.aliases; + + p = &aliases->aliases[alias->slot]; p->base_gfn = alias->guest_phys_addr >>PAGE_SHIFT ; p->npages = alias->memory_size >>PAGE_SHIFT ; p->target_gfn = alias->target_phys_addr >>PAGE_SHIFT ;for (n =KVM_ALIAS_SLOTS ; n >0 ; --n) -if (kvm->arch.aliases[n -1 ].npages) +if (aliases->aliases[n -1 ].npages)break ; - kvm->arch.naliases = n; + aliases->naliases = n;spin_unlock (&kvm->mmu_lock);kvm_mmu_zap_all (kvm);
@@ -5157,6 +5161,12 @@ struct kvm *kvm_arch_create_vm(void)if (!kvm)return ERR_PTR (-ENOMEM ); + kvm->arch.aliases =kzalloc (sizeof (struct kvm_mem_aliases ),GFP_KERNEL ); +if (!kvm->arch.aliases) { +kfree (kvm); +return ERR_PTR (-ENOMEM ); + } +INIT_LIST_HEAD (&kvm->arch.active_mmu_pages);INIT_LIST_HEAD (&kvm->arch.assigned_dev_head);
@@ -5213,6 +5223,7 @@ void kvm_arch_destroy_vm(struct kvm *kvmput_page (kvm->arch.apic_access_page);if (kvm->arch.ept_identity_pagetable)put_page (kvm->arch.ept_identity_pagetable); +kfree (kvm->arch.aliases);kfree (kvm); }
PATCH 3/11 KVM: split kvm_arch_set_memory_region into prepare and commit
In reply to Marcelo TosattiRequired for SRCU convertion later.
arch/ia64/kvm/kvm-ia64.c +11 -4
@@ -1576,15 +1576,14 @@ out:return r; } -int kvm_arch_set_memory_region (struct kvm *kvm, -struct kvm_userspace_memory_region *mem, +int kvm_arch_prepare_memory_region (struct kvm *kvm, +struct kvm_memory_slot *memslot,struct kvm_memory_slot old,int user_alloc) {unsigned long i;unsigned long pfn; -int npages = mem->memory_size >>PAGE_SHIFT ; -struct kvm_memory_slot *memslot = &kvm->memslots[mem->slot]; +int npages = memslot->npages;unsigned long base_gfn = memslot->base_gfn;if (base_gfn + npages > (KVM_MAX_MEM_SIZE >>PAGE_SHIFT ))
@@ -1608,6 +1607,14 @@ int kvm_arch_set_memory_region(struct kvreturn 0 ; } +void kvm_arch_commit_memory_region (struct kvm *kvm, +struct kvm_userspace_memory_region *mem, +struct kvm_memory_slot old, +int user_alloc) +{ +return ; +} +void kvm_arch_flush_shadow (struct kvm *kvm) {kvm_flush_remote_tlbs (kvm);
arch/s390/kvm/kvm-s390.c +12 -6
@@ -689,10 +689,10 @@ long kvm_arch_vcpu_ioctl(struct file *fi }/* Section: memory related */ -int kvm_arch_set_memory_region (struct kvm *kvm, -struct kvm_userspace_memory_region *mem, -struct kvm_memory_slot old, -int user_alloc) +int kvm_arch_prepare_memory_region (struct kvm *kvm, +struct kvm_userspace_memory_region *mem, +struct kvm_memory_slot old, +int user_alloc) {int i;struct kvm_vcpu *vcpu;
@@ -719,14 +719,20 @@ int kvm_arch_set_memory_region(struct kvif (!user_alloc)return -EINVAL ; +return 0 ; +} + +int kvm_arch_commit_memory_region (struct kvm *kvm, +struct kvm_userspace_memory_region *mem, +struct kvm_memory_slot old, +int user_alloc) +{/* request update of sie control block for all available vcpus */ kvm_for_each_vcpu (i, vcpu, kvm) {if (test_and_set_bit (KVM_REQ_MMU_RELOAD , &vcpu->requests))continue ;kvm_s390_inject_sigp_stop (vcpu,ACTION_RELOADVCPU_ON_STOP ); } - -return 0 ; }void kvm_arch_flush_shadow (struct kvm *kvm)
arch/x86/kvm/x86.c +28 -22
75 lines not on this page · raw message
include/linux/kvm_host.h +5 -1
@@ -253,7 +253,11 @@ int kvm_set_memory_region(struct kvm *kvint __kvm_set_memory_region (struct kvm *kvm,struct kvm_userspace_memory_region *mem,int user_alloc); -int kvm_arch_set_memory_region (struct kvm *kvm, +int kvm_arch_prepare_memory_region (struct kvm *kvm, +struct kvm_memory_slot *memslot, +struct kvm_memory_slot old, +int user_alloc); +void kvm_arch_commit_memory_region (struct kvm *kvm,struct kvm_userspace_memory_region *mem,struct kvm_memory_slot old,int user_alloc);
virt/kvm/kvm_main.c +5 -7
@@ -663,6 +663,10 @@ skip_lpage:if (!npages)kvm_arch_flush_shadow (kvm); + r =kvm_arch_prepare_memory_region (kvm, &new, old, user_alloc); +if (r) + goto out_free; +spin_lock (&kvm->mmu_lock);if (mem->slot >= kvm->memslots->nmemslots) kvm->memslots->nmemslots = mem->slot +1 ;
@@ -670,13 +674,7 @@ skip_lpage: *memslot = new;spin_unlock (&kvm->mmu_lock); - r =kvm_arch_set_memory_region (kvm, mem, old, user_alloc); -if (r) { -spin_lock (&kvm->mmu_lock); - *memslot = old; -spin_unlock (&kvm->mmu_lock); - goto out_free; - } +kvm_arch_commit_memory_region (kvm, mem, old, user_alloc);kvm_free_physmem_slot (&old, npages ? &new :NULL );/* Slot deletion case: we have to update the current slot */
PATCH 4/11 KVM: introduce gfn_to_pfn_memslot
In reply to Marcelo TosattiWhich takes a memslot pointer instead of using kvm->memslots.
To be used by SRCU convertion later.
include/linux/kvm_host.h +2 -0
@@ -272,6 +272,8 @@ void kvm_set_page_dirty(struct page *pagvoid kvm_set_page_accessed (struct page *page);pfn_t gfn_to_pfn (struct kvm *kvm,gfn_t gfn); +pfn_t gfn_to_pfn_memslot (struct kvm *kvm, +struct kvm_memory_slot *slot,gfn_t gfn);void kvm_release_pfn_dirty (pfn_t );void kvm_release_pfn_clean (pfn_t pfn);void kvm_set_pfn_dirty (pfn_t pfn);
virt/kvm/kvm_main.c +25 -8
@@ -835,21 +835,14 @@ unsigned long gfn_to_hva(struct kvm *kvm }EXPORT_SYMBOL_GPL (gfn_to_hva); -pfn_t gfn_to_pfn (struct kvm *kvm,gfn_t gfn) +static pfn_t hva_to_pfn (struct kvm *kvm,unsigned long addr) {struct page *page[1 ]; -unsigned long addr;int npages;pfn_t pfn;might_sleep (); - addr =gfn_to_hva (kvm, gfn); -if (kvm_is_error_hva (addr)) { -get_page (bad_page); -return page_to_pfn (bad_page); - } - npages =get_user_pages_fast (addr,1 ,1 , page);if (unlikely (npages !=1 )) {
@@ -874,8 +867,32 @@ pfn_t gfn_to_pfn(struct kvm *kvm, gfn_treturn pfn; } +pfn_t gfn_to_pfn (struct kvm *kvm,gfn_t gfn) +{ +unsigned long addr; + + addr =gfn_to_hva (kvm, gfn); +if (kvm_is_error_hva (addr)) { +get_page (bad_page); +return page_to_pfn (bad_page); + } + +return hva_to_pfn (kvm, addr); +}EXPORT_SYMBOL_GPL (gfn_to_pfn); +static unsigned long gfn_to_hva_memslot (struct kvm_memory_slot *slot,gfn_t gfn) +{ +return (slot->userspace_addr + (gfn - slot->base_gfn) *PAGE_SIZE ); +} + +pfn_t gfn_to_pfn_memslot (struct kvm *kvm, +struct kvm_memory_slot *slot,gfn_t gfn) +{ +unsigned long addr =gfn_to_hva_memslot (slot, gfn); +return hva_to_pfn (kvm, addr); +} +struct page *gfn_to_page (struct kvm *kvm,gfn_t gfn) {pfn_t pfn;
PATCH 5/11 KVM: use gfn_to_pfn_memslot in kvm_iommu_map_pages
In reply to Marcelo TosattiSo its possible to iommu map a memslot before making it visible to kvm.
include/linux/kvm_host.h +1 -2
@@ -439,8 +439,7 @@ void kvm_free_irq_source_id(struct kvm *#define KVM_IOMMU_CACHE_COHERENCY 0x1#ifdef CONFIG_IOMMU_API -int kvm_iommu_map_pages (struct kvm *kvm,gfn_t base_gfn, -unsigned long npages); +int kvm_iommu_map_pages (struct kvm *kvm,struct kvm_memory_slot *slot);int kvm_iommu_map_guest (struct kvm *kvm);int kvm_iommu_unmap_guest (struct kvm *kvm); int kvm_assign_device(struct kvm *kvm,
virt/kvm/iommu.c +6 -7
@@ -32,10 +32,10 @@ static int kvm_iommu_unmap_memslots(strustatic void kvm_iommu_put_pages (struct kvm *kvm,gfn_t base_gfn,unsigned long npages); -int kvm_iommu_map_pages (struct kvm *kvm, -gfn_t base_gfn,unsigned long npages) +int kvm_iommu_map_pages (struct kvm *kvm,struct kvm_memory_slot *slot) { -gfn_t gfn = base_gfn; +gfn_t gfn = slot->base_gfn; +unsigned long npages = slot->npages;pfn_t pfn;int i, r =0 ;struct iommu_domain *domain = kvm->arch.iommu_domain;
@@ -54,7 +54,7 @@ int kvm_iommu_map_pages(struct kvm *kvm,if (iommu_iova_to_phys (domain,gfn_to_gpa (gfn)))continue ; - pfn =gfn_to_pfn (kvm, gfn); + pfn =gfn_to_pfn_memslot (kvm, slot, gfn); r = iommu_map_range(domain, gfn_to_gpa(gfn), pfn_to_hpa(pfn),
@@ -69,7 +69,7 @@ int kvm_iommu_map_pages(struct kvm *kvm,return 0 ; unmap_pages: -kvm_iommu_put_pages (kvm, base_gfn, i); +kvm_iommu_put_pages (kvm, slot->base_gfn, i);return r; }
@@ -81,8 +81,7 @@ static int kvm_iommu_map_memslots(struct slots = kvm->memslots;for (i =0 ; i < slots->nmemslots; i++) { - r =kvm_iommu_map_pages (kvm, slots->memslots[i].base_gfn, - slots->memslots[i].npages); + r =kvm_iommu_map_pages (kvm, &slots->memslots[i]);if (r)break ; }
virt/kvm/kvm_main.c +1 -1
@@ -684,7 +684,7 @@ skip_lpage:spin_unlock (&kvm->mmu_lock);#ifdef CONFIG_DMAR /* map the pages in iommu page table */ - r =kvm_iommu_map_pages (kvm, base_gfn, npages); + r =kvm_iommu_map_pages (kvm, memslot);if (r) goto out;#endif
PATCH 6/11 KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update
In reply to Marcelo TosattiUse two steps for memslot deletion: mark the slot invalid (which stops instantiation of new shadow pages for that slot, but allows destruction), then instantiate the new empty slot.
Also simplifies kvm_handle_hva locking.
include/linux/kvm.h +1 -1
@@ -103,7 +103,7 @@ struct kvm_userspace_memory_region {/* for kvm_memory_region::flags */ #define KVM_MEM_LOG_DIRTY_PAGES 1UL - +#define KVM_MEMSLOT_INVALID (1UL << 1)/* for KVM_IRQ_LINE */ struct kvm_irq_level {
virt/kvm/kvm_main.c +105 -36
288 lines not on this page · raw message
arch/ia64/kvm/kvm-ia64.c +2 -0
@@ -1834,6 +1834,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvstruct kvm_memory_slot *memslot;int is_dirty =0 ; +down_write (&kvm->slots_lock);spin_lock (&kvm->arch.dirty_log_lock); r =kvm_ia64_sync_dirty_log (kvm, log);
@@ -1853,6 +1854,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kv } r =0 ; out: +up_write (&kvm->slots_lock);spin_unlock (&kvm->arch.dirty_log_lock);return r; }
arch/x86/kvm/mmu.c +14 -14
@@ -29,6 +29,7 @@#include <linux/swap.h> #include <linux/hugetlb.h> #include <linux/compiler.h> +#include <linux/srcu.h> #include <asm/page.h> #include <asm/cmpxchg.h>
@@ -809,21 +810,15 @@ static int kvm_handle_hva(struct kvm *kv {int i, j;int retval =0 ; -struct kvm_memslots *slots = kvm->memslots; +struct kvm_memslots *slots; + + slots =rcu_dereference (kvm->memslots); -/* -* If mmap_sem isn't taken, we can look the memslots with only -* the mmu_lock by skipping over the slots with userspace_addr == 0. -*/ for (i =0 ; i < slots->nmemslots; i++) {struct kvm_memory_slot *memslot = &slots->memslots[i];unsigned long start = memslot->userspace_addr;unsigned long end; -/* mmu_lock protects userspace_addr */ -if (!start) -continue ; - end = start + (memslot->npages <<PAGE_SHIFT );if (hva >= start && hva < end) {gfn_t gfn_offset = (hva - start) >>PAGE_SHIFT ;
@@ -1619,7 +1614,7 @@ static void mmu_unshadow(struct kvm *kvmstatic void page_header_update_slot (struct kvm *kvm,void *pte,gfn_t gfn) { -int slot =memslot_id (kvm,gfn_to_memslot (kvm, gfn)); +int slot =memslot_id (kvm, gfn);struct kvm_mmu_page *sp =page_header (__pa (pte));__set_bit (slot, sp->slot_bitmap);
@@ -3023,9 +3018,11 @@ unsigned int kvm_mmu_calculate_mmu_pagesint i;unsigned int nr_mmu_pages;unsigned int nr_pages =0 ; +struct kvm_memslots *slots; -for (i =0 ; i < kvm->memslots->nmemslots; i++) - nr_pages += kvm->memslots->memslots[i].npages; + slots =rcu_dereference (kvm->memslots); +for (i =0 ; i < slots->nmemslots; i++) + nr_pages += slots->memslots[i].npages; nr_mmu_pages = nr_pages *KVM_PERMILLE_MMU_PAGES /1000 ; nr_mmu_pages = max(nr_mmu_pages,
@@ -3295,10 +3292,12 @@ static void audit_mappings(struct kvm_vcstatic int count_rmaps (struct kvm_vcpu *vcpu) {int nmaps =0 ; -int i, j, k; +int i, j, k, idx; + idx =srcu_read_lock (&kvm->srcu); + slots =rcu_dereference (kvm->memslots);for (i =0 ; i <KVM_MEMORY_SLOTS ; ++i) { -struct kvm_memory_slot *m = &vcpu->kvm->memslots->memslots[i]; +struct kvm_memory_slot *m = &slots->memslots[i];struct kvm_rmap_desc *d;for (j =0 ; j < m->npages; ++j) {
@@ -3321,6 +3320,7 @@ static int count_rmaps(struct kvm_vcpu * } } } +srcu_read_unlock (&kvm->srcu, idx);return nmaps; }
arch/x86/kvm/vmx.c +5 -1
@@ -1503,7 +1503,11 @@ static void enter_pmode(struct kvm_vcpustatic gva_t rmode_tss_base (struct kvm *kvm) {if (!kvm->arch.tss_addr) { -gfn_t base_gfn = kvm->memslots->memslots[0 ].base_gfn + +struct kvm_memslots *slots; +gfn_t base_gfn; + + slots =rcu_dereference (kvm->memslots); + base_gfn = kvm->memslots->memslots[0 ].base_gfn + kvm->memslots->memslots[0 ].npages -3 ;return base_gfn <<PAGE_SHIFT ; }
include/linux/kvm_host.h +2 -5
@@ -162,6 +162,7 @@ struct kvm {struct rw_semaphore slots_lock;struct mm_struct *mm;/* userspace tied to this vm */ struct kvm_memslots *memslots; +struct srcu_struct srcu;#ifdef CONFIG_KVM_APIC_ARCHITECTURE u32 bsp_vcpu_id;struct kvm_vcpu *bsp_vcpu;
@@ -274,6 +275,7 @@ void kvm_set_page_accessed(struct page *pfn_t gfn_to_pfn (struct kvm *kvm,gfn_t gfn);pfn_t gfn_to_pfn_memslot (struct kvm *kvm,struct kvm_memory_slot *slot,gfn_t gfn); +int memslot_id (struct kvm *kvm,gfn_t gfn);void kvm_release_pfn_dirty (pfn_t );void kvm_release_pfn_clean (pfn_t pfn);void kvm_set_pfn_dirty (pfn_t pfn);
@@ -489,11 +491,6 @@ static inline void kvm_guest_exit(void) current->flags &= ~PF_VCPU ; } -static inline int memslot_id (struct kvm *kvm,struct kvm_memory_slot *slot) -{ -return slot - kvm->memslots->memslots; -} -static inline gpa_t gfn_to_gpa (gfn_t gfn) {return (gpa_t )gfn <<PAGE_SHIFT ;
virt/kvm/assigned-dev.c +4 -4
@@ -504,12 +504,12 @@ out:static int kvm_vm_ioctl_assign_device (struct kvm *kvm,struct kvm_assigned_pci_dev *assigned_dev) { -int r =0 ; +int r =0 , idx;struct kvm_assigned_dev_kernel *match;struct pci_dev *dev;mutex_lock (&kvm->lock); -down_read (&kvm->slots_lock); + idx =srcu_read_lock (&kvm->srcu); match =kvm_find_assigned_dev (&kvm->arch.assigned_dev_head, assigned_dev->assigned_dev_id);
@@ -573,7 +573,7 @@ static int kvm_vm_ioctl_assign_device(st } out: -up_read (&kvm->slots_lock); +srcu_read_unlock (&kvm->srcu, idx);mutex_unlock (&kvm->lock);return r; out_list_del:
@@ -585,7 +585,7 @@ out_put:pci_dev_put (dev); out_free:kfree (match); -up_read (&kvm->slots_lock); +srcu_read_unlock (&kvm->srcu, idx);mutex_unlock (&kvm->lock);return r; }
virt/kvm/iommu.c +2 -2
@@ -78,7 +78,7 @@ static int kvm_iommu_map_memslots(structint i, r =0 ;struct kvm_memslots *slots; - slots = kvm->memslots; + slots =rcu_dereference (kvm->memslots);for (i =0 ; i < slots->nmemslots; i++) { r =kvm_iommu_map_pages (kvm, &slots->memslots[i]);
@@ -214,7 +214,7 @@ static int kvm_iommu_unmap_memslots(struint i;struct kvm_memslots *slots; - slots = kvm->memslots; + slots =rcu_dereference (kvm->memslots);for (i =0 ; i < slots->nmemslots; i++) { kvm_iommu_put_pages(kvm, slots->memslots[i].base_gfn,
PATCH 7/11 KVM: use SRCU for dirty log
In reply to Marcelo Tosattiarch/x86/kvm/x86.c +41 -8
@@ -2416,27 +2416,60 @@ static int kvm_vm_ioctl_reinject(structint kvm_vm_ioctl_get_dirty_log (struct kvm *kvm,struct kvm_dirty_log *log) { -int r; -int n; +int r, n, i;struct kvm_memory_slot *memslot; -int is_dirty =0 ; +unsigned long is_dirty =0 ; +unsigned long *dirty_bitmap =NULL ;down_write (&kvm->slots_lock); - r =kvm_get_dirty_log (kvm, log, &is_dirty); -if (r) + r = -EINVAL ; +if (log->slot >=KVM_MEMORY_SLOTS ) + goto out; + + memslot = &kvm->memslots->memslots[log->slot]; + r = -ENOENT ; +if (!memslot->dirty_bitmap) + goto out; + + n =ALIGN (memslot->npages,BITS_PER_LONG ) /8 ; + + r = -ENOMEM ; + dirty_bitmap =vmalloc (n); +if (!dirty_bitmap) goto out; +memset (dirty_bitmap,0 , n); + +for (i =0 ; !is_dirty && i < n/sizeof (long ); i++) + is_dirty = memslot->dirty_bitmap[i];/* If nothing is dirty, don't bother messing with page tables. */ if (is_dirty) { +struct kvm_memslots *slots, *old_slots; +spin_lock (&kvm->mmu_lock);kvm_mmu_slot_remove_write_access (kvm, log->slot);spin_unlock (&kvm->mmu_lock); - memslot = &kvm->memslots->memslots[log->slot]; - n =ALIGN (memslot->npages,BITS_PER_LONG ) /8 ; -memset (memslot->dirty_bitmap,0 , n); + + slots =kzalloc (sizeof (struct kvm_memslots ),GFP_KERNEL ); +if (!slots) + goto out_free; + +memcpy (slots, kvm->memslots,sizeof (struct kvm_memslots )); + slots->memslots[log->slot].dirty_bitmap = dirty_bitmap; + + old_slots = kvm->memslots; +rcu_assign_pointer (kvm->memslots, slots); +synchronize_srcu_expedited (&kvm->srcu); + dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap; +kfree (old_slots); } + r =0 ; +if (copy_to_user (log->dirty_bitmap, dirty_bitmap, n)) + r = -EFAULT ; +out_free: +vfree (dirty_bitmap); out:up_write (&kvm->slots_lock);return r;
PATCH 8/11 KVM: x86: switch kvm_set_memory_alias to SRCU update
In reply to Marcelo TosattiUsing a similar two-step procedure as for memslots.
arch/x86/include/asm/kvm_host.h +4 -0
@@ -368,8 +368,12 @@ struct kvm_mem_alias {gfn_t base_gfn;unsigned long npages;gfn_t target_gfn; +#define KVM_ALIAS_INVALID 1UL +unsigned long flags; }; +#define KVM_ARCH_HAS_UNALIAS_INSTANTIATION +struct kvm_mem_aliases {struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS ];int naliases;
arch/x86/kvm/x86.c +51 -9
103 lines not on this page · raw message
include/linux/kvm_host.h +6 -0
@@ -265,6 +265,8 @@ void kvm_arch_commit_memory_region(strucvoid kvm_disable_largepages (void );void kvm_arch_flush_shadow (struct kvm *kvm);gfn_t unalias_gfn (struct kvm *kvm,gfn_t gfn); +gfn_t unalias_gfn_instantiation (struct kvm *kvm,gfn_t gfn); +struct page *gfn_to_page (struct kvm *kvm,gfn_t gfn);unsigned long gfn_to_hva (struct kvm *kvm,gfn_t gfn);void kvm_release_page_clean (struct page *page);
@@ -538,6 +540,10 @@ static inline int mmu_notifier_retry(str }#endif +#ifndef KVM_ARCH_HAS_UNALIAS_INSTANTIATION +#define unalias_gfn_instantiation unalias_gfn +#endif +#ifdef CONFIG_HAVE_KVM_IRQCHIP #define KVM_MAX_IRQ_ROUTES 1024
virt/kvm/kvm_main.c +2 -2
@@ -859,7 +859,7 @@ int kvm_is_visible_gfn(struct kvm *kvm,int i;struct kvm_memslots *slots =rcu_dereference (kvm->memslots); - gfn =unalias_gfn (kvm, gfn); + gfn =unalias_gfn_instantiation (kvm, gfn);for (i =0 ; i <KVM_MEMORY_SLOTS ; ++i) {struct kvm_memory_slot *memslot = &slots->memslots[i];
@@ -896,7 +896,7 @@ unsigned long gfn_to_hva(struct kvm *kvm {struct kvm_memory_slot *slot; - gfn =unalias_gfn (kvm, gfn); + gfn =unalias_gfn_instantiation (kvm, gfn); slot =gfn_to_memslot_unaliased (kvm, gfn);if (!slot || slot->flags &KVM_MEMSLOT_INVALID )return bad_hva ();
PATCH 9/11 KVM: convert io_bus to SRCU
In reply to Marcelo Tosattiarch/x86/kvm/i8254.c +3 -3
@@ -642,13 +642,13 @@ struct kvm_pit *kvm_create_pit(struct kvkvm_register_irq_mask_notifier (kvm,0 , &pit->mask_notifier);kvm_iodevice_init (&pit->dev, &pit_dev_ops); - ret =__kvm_io_bus_register_dev (&kvm->pio_bus, &pit->dev); + ret =kvm_io_bus_register_dev (kvm,KVM_PIO_BUS , &pit->dev);if (ret <0 ) goto fail;if (flags &KVM_PIT_SPEAKER_DUMMY ) {kvm_iodevice_init (&pit->speaker_dev, &speaker_dev_ops); - ret =__kvm_io_bus_register_dev (&kvm->pio_bus, + ret =kvm_io_bus_register_dev (kvm,KVM_PIO_BUS , &pit->speaker_dev);if (ret <0 ) goto fail_unregister;
@@ -657,7 +657,7 @@ struct kvm_pit *kvm_create_pit(struct kvreturn pit; fail_unregister: -__kvm_io_bus_unregister_dev (&kvm->pio_bus, &pit->dev); +kvm_io_bus_unregister_dev (kvm,KVM_PIO_BUS , &pit->dev); fail:if (pit->irq_source_id >=0 )
arch/x86/kvm/i8259.c +3 -1
@@ -533,7 +533,9 @@ struct kvm_pic *kvm_create_pic(struct kv* Initialize PIO device */ kvm_iodevice_init (&s->dev, &picdev_ops); - ret =kvm_io_bus_register_dev (kvm, &kvm->pio_bus, &s->dev); +down_write (&kvm->slots_lock); + ret =kvm_io_bus_register_dev (kvm,KVM_PIO_BUS , &s->dev); +up_write (&kvm->slots_lock);if (ret <0 ) {kfree (s);return NULL ;
include/linux/kvm_host.h +13 -14
@@ -57,20 +57,20 @@ struct kvm_io_bus {struct kvm_io_device *devs[NR_IOBUS_DEVS ]; }; -void kvm_io_bus_init (struct kvm_io_bus *bus); -void kvm_io_bus_destroy (struct kvm_io_bus *bus); -int kvm_io_bus_write (struct kvm_io_bus *bus,gpa_t addr,int len, -const void *val); -int kvm_io_bus_read (struct kvm_io_bus *bus,gpa_t addr,int len, +enum kvm_bus { +KVM_MMIO_BUS , +KVM_PIO_BUS , +KVM_NR_BUSES +}; + +int kvm_io_bus_write (struct kvm *kvm,enum kvm_bus bus_idx,gpa_t addr, +int len,const void *val); +int kvm_io_bus_read (struct kvm *kvm,enum kvm_bus bus_idx,gpa_t addr,int len,void *val); -int __kvm_io_bus_register_dev (struct kvm_io_bus *bus, -struct kvm_io_device *dev); -int kvm_io_bus_register_dev (struct kvm *kvm,struct kvm_io_bus *bus, +int kvm_io_bus_register_dev (struct kvm *kvm,enum kvm_bus bus_idx,struct kvm_io_device *dev); -void __kvm_io_bus_unregister_dev (struct kvm_io_bus *bus, -struct kvm_io_device *dev); -void kvm_io_bus_unregister_dev (struct kvm *kvm,struct kvm_io_bus *bus, -struct kvm_io_device *dev); +int kvm_io_bus_unregister_dev (struct kvm *kvm,enum kvm_bus bus_idx, +struct kvm_io_device *dev);struct kvm_vcpu {struct kvm *kvm;
@@ -171,8 +171,7 @@ struct kvm {atomic_t online_vcpus;struct list_head vm_list;struct mutex lock; -struct kvm_io_bus mmio_bus; -struct kvm_io_bus pio_bus; +struct kvm_io_bus *buses[KVM_NR_BUSES ]; #ifdef CONFIG_HAVE_KVM_EVENTFD struct { spinlock_t lock;
virt/kvm/eventfd.c +4 -4
@@ -451,7 +451,7 @@ static int kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) { int pio = args->flags & KVM_IOEVENTFD_FLAG_PIO; -struct kvm_io_bus *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus; +enum kvm_bus bus_idx = pio ?KVM_PIO_BUS :KVM_MMIO_BUS ;struct _ioeventfd *p;struct eventfd_ctx *eventfd;int ret;
@@ -506,7 +506,7 @@ kvm_assign_ioeventfd(struct kvm *kvm, stkvm_iodevice_init (&p->dev, &ioeventfd_ops); - ret =__kvm_io_bus_register_dev (bus, &p->dev); + ret =kvm_io_bus_register_dev (kvm, bus_idx, &p->dev);if (ret <0 ) goto unlock_fail;
@@ -530,7 +530,7 @@ static int kvm_deassign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) { int pio = args->flags & KVM_IOEVENTFD_FLAG_PIO; -struct kvm_io_bus *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus; +enum kvm_bus bus_idx = pio ?KVM_PIO_BUS :KVM_MMIO_BUS ;struct _ioeventfd *p, *tmp;struct eventfd_ctx *eventfd;int ret = -ENOENT ;
@@ -553,7 +553,7 @@ kvm_deassign_ioeventfd(struct kvm *kvm,if (!p->wildcard && p->datamatch != args->datamatch)continue ; -__kvm_io_bus_unregister_dev (bus, &p->dev); +kvm_io_bus_unregister_dev (kvm, bus_idx, &p->dev);ioeventfd_release (p); ret =0 ;break ;
virt/kvm/ioapic.c +3 -1
@@ -372,7 +372,9 @@ int kvm_ioapic_init(struct kvm *kvm)kvm_ioapic_reset (ioapic);kvm_iodevice_init (&ioapic->dev, &ioapic_mmio_ops); ioapic->kvm = kvm; - ret =kvm_io_bus_register_dev (kvm, &kvm->mmio_bus, &ioapic->dev); +down_write (&kvm->slots_lock); + ret =kvm_io_bus_register_dev (kvm,KVM_MMIO_BUS , &ioapic->dev); +up_write (&kvm->slots_lock);if (ret <0 )kfree (ioapic);
virt/kvm/kvm_main.c +63 -43
197 lines not on this page · raw message
virt/kvm/coalesced_mmio.c +3 -1
@@ -110,7 +110,9 @@ int kvm_coalesced_mmio_init(struct kvm * dev->kvm = kvm; kvm->coalesced_mmio_dev = dev; - ret =kvm_io_bus_register_dev (kvm, &kvm->mmio_bus, &dev->dev); +down_write (&kvm->slots_lock); + ret =kvm_io_bus_register_dev (kvm,KVM_MMIO_BUS , &dev->dev); +up_write (&kvm->slots_lock);if (ret <0 ) goto out_free_dev;
arch/x86/kvm/x86.c +7 -6
@@ -2852,7 +2852,7 @@ static int vcpu_mmio_write(struct kvm_vc !kvm_iodevice_write(&vcpu->arch.apic->dev, addr, len, v))return 0 ; -return kvm_io_bus_write (&vcpu->kvm->mmio_bus, addr, len, v); +return kvm_io_bus_write (vcpu->kvm,KVM_MMIO_BUS , addr, len, v); }static int vcpu_mmio_read (struct kvm_vcpu *vcpu,gpa_t addr,int len,void *v)
@@ -2861,7 +2861,7 @@ static int vcpu_mmio_read(struct kvm_vcp !kvm_iodevice_read(&vcpu->arch.apic->dev, addr, len, v))return 0 ; -return kvm_io_bus_read (&vcpu->kvm->mmio_bus, addr, len, v); +return kvm_io_bus_read (vcpu->kvm,KVM_MMIO_BUS , addr, len, v); } static int kvm_read_guest_virt(gva_t addr, void *val, unsigned int bytes,
@@ -3346,11 +3346,12 @@ static int kernel_pio(struct kvm_vcpu *vint r;if (vcpu->arch.pio.in) - r =kvm_io_bus_read (&vcpu->kvm->pio_bus, vcpu->arch.pio.port, + r =kvm_io_bus_read (vcpu->kvm,KVM_PIO_BUS , vcpu->arch.pio.port, vcpu->arch.pio.size, pd);else - r =kvm_io_bus_write (&vcpu->kvm->pio_bus, vcpu->arch.pio.port, - vcpu->arch.pio.size, pd); + r =kvm_io_bus_write (vcpu->kvm,KVM_PIO_BUS , + vcpu->arch.pio.port, vcpu->arch.pio.size, + pd);return r; }
@@ -3361,7 +3362,7 @@ static int pio_string_write(struct kvm_vint i, r =0 ;for (i =0 ; i < io->cur_count; i++) { -if (kvm_io_bus_write (&vcpu->kvm->pio_bus, +if (kvm_io_bus_write (vcpu->kvm,KVM_PIO_BUS , io->port, io->size, pd)) { r = -EOPNOTSUPP ;break ;
arch/ia64/kvm/kvm-ia64.c +2 -2
@@ -241,10 +241,10 @@ static int handle_mmio(struct kvm_vcpu *return 0 ; mmio:if (p->dir) - r =kvm_io_bus_read (&vcpu->kvm->mmio_bus, p->addr, + r =kvm_io_bus_read (vcpu->kvm,KVM_MMIO_BUS , p->addr, p->size, &p->data);else - r =kvm_io_bus_write (&vcpu->kvm->mmio_bus, p->addr, + r =kvm_io_bus_write (vcpu->kvm,KVM_MMIO_BUS , p->addr, p->size, &p->data);if (r)printk (KERN_ERR "kvm: No iodevice found! addr:%lx\n" , p->addr);
PATCH 10/11 KVM: switch vcpu context to use SRCU
In reply to Marcelo Tosattiarch/x86/kvm/x86.c +24 -19
@@ -1307,15 +1307,15 @@ static int __msr_io(struct kvm_vcpu *vcpint (*do_msr)(struct kvm_vcpu *vcpu, unsigned index, u64 *data)) { -int i; +int i, idx;vcpu_load (vcpu); -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu);for (i =0 ; i < msrs->nmsrs; ++i)if (do_msr (vcpu, entries[i].index, &entries[i].data))break ; -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx);vcpu_put (vcpu);
@@ -3901,14 +3901,15 @@ static void vapic_enter(struct kvm_vcpustatic void vapic_exit (struct kvm_vcpu *vcpu) {struct kvm_lapic *apic = vcpu->arch.apic; +int idx;if (!apic || !apic->vapic_addr)return ; -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu);kvm_release_page_dirty (apic->vapic_page);mark_page_dirty (vcpu->kvm, apic->vapic_addr >>PAGE_SHIFT ); -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx); }static void update_cr8_intercept (struct kvm_vcpu *vcpu)
@@ -4037,7 +4038,7 @@ static int vcpu_enter_guest(struct kvm_vkvm_lapic_sync_to_vapic (vcpu); } -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, vcpu->srcu_idx);kvm_guest_enter ();
@@ -4079,7 +4080,7 @@ static int vcpu_enter_guest(struct kvm_vpreempt_enable (); -down_read (&vcpu->kvm->slots_lock); + vcpu->srcu_idx =srcu_read_lock (&vcpu->kvm->srcu);/* * Profile KVM exit RIPs:
@@ -4101,6 +4102,7 @@ out:static int __vcpu_run (struct kvm_vcpu *vcpu) {int r; +struct kvm *kvm = vcpu->kvm;if (unlikely (vcpu->arch.mp_state ==KVM_MP_STATE_SIPI_RECEIVED )) { pr_debug("vcpu %d received sipi with vector # %x\n",
@@ -4112,7 +4114,7 @@ static int __vcpu_run(struct kvm_vcpu *v vcpu->arch.mp_state =KVM_MP_STATE_RUNNABLE ; } -down_read (&vcpu->kvm->slots_lock); + vcpu->srcu_idx =srcu_read_lock (&kvm->srcu);vapic_enter (vcpu); r =1 ;
@@ -4120,9 +4122,9 @@ static int __vcpu_run(struct kvm_vcpu *vif (vcpu->arch.mp_state ==KVM_MP_STATE_RUNNABLE ) r =vcpu_enter_guest (vcpu);else { -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&kvm->srcu, vcpu->srcu_idx);kvm_vcpu_block (vcpu); -down_read (&vcpu->kvm->slots_lock); + vcpu->srcu_idx =srcu_read_lock (&kvm->srcu);if (test_and_clear_bit (KVM_REQ_UNHALT , &vcpu->requests)) {switch (vcpu->arch.mp_state) {
@@ -4157,13 +4159,13 @@ static int __vcpu_run(struct kvm_vcpu *v ++vcpu->stat.signal_exits; }if (need_resched ()) { -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&kvm->srcu, vcpu->srcu_idx);kvm_resched (vcpu); -down_read (&vcpu->kvm->slots_lock); + vcpu->srcu_idx =srcu_read_lock (&kvm->srcu); } } -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&kvm->srcu, vcpu->srcu_idx);post_kvm_run_save (vcpu);vapic_exit (vcpu);
@@ -4202,10 +4204,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_v vcpu->mmio_read_completed =1 ; vcpu->mmio_needed =0 ; -down_read (&vcpu->kvm->slots_lock); + vcpu->srcu_idx =srcu_read_lock (&vcpu->kvm->srcu); r =emulate_instruction (vcpu, vcpu->arch.mmio_fault_cr2,0 ,EMULTYPE_NO_DECODE ); -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, vcpu->srcu_idx);if (r ==EMULATE_DO_MMIO ) {/* * Read-modify-write. Back to userspace.
@@ -4968,11 +4970,12 @@ int kvm_arch_vcpu_ioctl_translate(struct {unsigned long vaddr = tr->linear_address;gpa_t gpa; +int idx;vcpu_load (vcpu); -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu); gpa = vcpu->arch.mmu.gva_to_gpa (vcpu, vaddr); -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx); tr->physical_address = gpa; tr->valid = gpa !=UNMAPPED_GVA ; tr->writeable =1 ;
@@ -5223,10 +5226,12 @@ fail:void kvm_arch_vcpu_uninit (struct kvm_vcpu *vcpu) { +int idx; +kvm_free_lapic (vcpu); -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu);kvm_mmu_destroy (vcpu); -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx);free_page ((unsigned long )vcpu->arch.pio_data); }
include/linux/kvm_host.h +2 -0
@@ -83,6 +83,8 @@ struct kvm_vcpu {struct kvm_run *run;unsigned long requests;unsigned long guest_debug; +int srcu_idx; +int fpu_active;int guest_fpu_loaded;wait_queue_head_t wq;
arch/x86/kvm/mmu.c +3 -4
@@ -2935,10 +2935,9 @@ static int mmu_shrink(int nr_to_scan, gfspin_lock (&kvm_lock);list_for_each_entry (kvm, &vm_list, vm_list) { -int npages; +int npages, idx; -if (!down_read_trylock (&kvm->slots_lock)) -continue ; + idx =srcu_read_lock (&kvm->srcu);spin_lock (&kvm->mmu_lock); npages = kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages;
@@ -2951,7 +2950,7 @@ static int mmu_shrink(int nr_to_scan, gf nr_to_scan--;spin_unlock (&kvm->mmu_lock); -up_read (&kvm->slots_lock); +srcu_read_unlock (&kvm->srcu, idx); }if (kvm_freed)list_move_tail (&kvm_freed->vm_list, &vm_list);
arch/x86/kvm/vmx.c +3 -3
@@ -2477,10 +2477,10 @@ static int vmx_vcpu_reset(struct kvm_vcp {struct vcpu_vmx *vmx =to_vmx (vcpu);u64 msr; -int ret; +int ret, idx; vcpu->arch.regs_avail = ~((1 <<VCPU_REGS_RIP ) | (1 <<VCPU_REGS_RSP )); -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu);if (!init_rmode (vmx->vcpu.kvm)) { ret = -ENOMEM ; goto out;
@@ -2588,7 +2588,7 @@ static int vmx_vcpu_reset(struct kvm_vcp vmx->emulation_required =0 ; out: -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx);return ret; }
arch/ia64/kvm/kvm-ia64.c +6 -9
@@ -636,12 +636,9 @@ static void kvm_vcpu_post_transition(strstatic int __vcpu_run (struct kvm_vcpu *vcpu,struct kvm_run *kvm_run) {union context *host_ctx, *guest_ctx; -int r; +int r, idx; -/* -* down_read() may sleep and return with interrupts enabled -*/ -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu); again:if (signal_pending (current)) {
@@ -663,7 +660,7 @@ again:if (r <0 ) goto vcpu_run_fail; -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx);kvm_guest_enter ();/*
@@ -687,7 +684,7 @@ again:kvm_guest_exit ();preempt_enable (); -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu); r =kvm_handle_exit (kvm_run, vcpu);
@@ -697,10 +694,10 @@ again: } out: -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx);if (r >0 ) {kvm_resched (vcpu); -down_read (&vcpu->kvm->slots_lock); + idx =srcu_read_lock (&vcpu->kvm->srcu); goto again; }
arch/s390/kvm/kvm-s390.h +7 -3
@@ -67,10 +67,14 @@ static inline long kvm_s390_vcpu_get_memstatic inline void kvm_s390_vcpu_set_mem (struct kvm_vcpu *vcpu) { +int idx;struct kvm_memory_slot *mem; +struct kvm_memory_slots *memslots; -down_read (&vcpu->kvm->slots_lock); - mem = &vcpu->kvm->memslots[0 ]; + idx =srcu_read_lock (&vcpu->kvm->srcu); + memslots =rcu_dereference (vcpu->kvm->memslots); + + mem = &memslots->memslots[0 ]; vcpu->arch.sie_block->gmsor = mem->userspace_addr; vcpu->arch.sie_block->gmslm =
@@ -78,7 +82,7 @@ static inline void kvm_s390_vcpu_set_mem (mem->npages <<PAGE_SHIFT ) +VIRTIODESCSPACE -1ul ; -up_read (&vcpu->kvm->slots_lock); +srcu_read_unlock (&vcpu->kvm->srcu, idx); }/* implemented in priv.c */
PATCH 11/11 KVM: convert slots_lock to a mutex
In reply to Marcelo Tosattiarch/x86/kvm/vmx.c +4 -4
@@ -2222,7 +2222,7 @@ static int alloc_apic_access_page(structstruct kvm_userspace_memory_region kvm_userspace_mem;int r =0 ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);if (kvm->arch.apic_access_page) goto out; kvm_userspace_mem.slot =APIC_ACCESS_PAGE_PRIVATE_MEMSLOT ;
@@ -2235,7 +2235,7 @@ static int alloc_apic_access_page(struct kvm->arch.apic_access_page =gfn_to_page (kvm,0xfee00 ); out: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return r; }
@@ -2244,7 +2244,7 @@ static int alloc_identity_pagetable(strustruct kvm_userspace_memory_region kvm_userspace_mem;int r =0 ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);if (kvm->arch.ept_identity_pagetable) goto out; kvm_userspace_mem.slot =IDENTITY_PAGETABLE_PRIVATE_MEMSLOT ;
@@ -2259,7 +2259,7 @@ static int alloc_identity_pagetable(stru kvm->arch.ept_identity_pagetable =gfn_to_page (kvm, kvm->arch.ept_identity_map_addr >>PAGE_SHIFT ); out: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return r; }
arch/x86/kvm/x86.c +8 -8
@@ -2209,14 +2209,14 @@ static int kvm_vm_ioctl_set_nr_mmu_pagesif (kvm_nr_mmu_pages <KVM_MIN_ALLOC_MMU_PAGES )return -EINVAL ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);spin_lock (&kvm->mmu_lock);kvm_mmu_change_mmu_pages (kvm, kvm_nr_mmu_pages); kvm->arch.n_requested_mmu_pages = kvm_nr_mmu_pages;spin_unlock (&kvm->mmu_lock); -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return 0 ; }
@@ -2293,7 +2293,7 @@ static int kvm_vm_ioctl_set_memory_aliasif (!aliases) goto out; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);/* invalidate any gfn reference in case of deletion/shrinking */ memcpy (aliases, kvm->arch.aliases,sizeof (struct kvm_mem_aliases ));
@@ -2329,7 +2329,7 @@ static int kvm_vm_ioctl_set_memory_alias r =0 ; out_unlock: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock); out:return r; }
@@ -2463,7 +2463,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvunsigned long is_dirty =0 ;unsigned long *dirty_bitmap =NULL ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); r = -EINVAL ;if (log->slot >=KVM_MEMORY_SLOTS )
@@ -2513,7 +2513,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kv out_free:vfree (dirty_bitmap); out: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return r; }
@@ -2626,7 +2626,7 @@ long kvm_arch_vm_ioctl(struct file *filp sizeof(struct kvm_pit_config))) goto out; create_pit: -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); r = -EEXIST ;if (kvm->arch.vpit) goto create_pit_unlock;
@@ -2635,7 +2635,7 @@ long kvm_arch_vm_ioctl(struct file *filpif (kvm->arch.vpit) r =0 ; create_pit_unlock: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);break ;case KVM_IRQ_LINE_STATUS :case KVM_IRQ_LINE : {
include/linux/kvm_host.h +1 -1
@@ -161,7 +161,7 @@ struct kvm_memslots {struct kvm {spinlock_t mmu_lock;spinlock_t requests_lock; -struct rw_semaphore slots_lock; +struct mutex slots_lock;struct mm_struct *mm;/* userspace tied to this vm */ struct kvm_memslots *memslots;struct srcu_struct srcu;
virt/kvm/coalesced_mmio.c +7 -7
@@ -110,9 +110,9 @@ int kvm_coalesced_mmio_init(struct kvm * dev->kvm = kvm; kvm->coalesced_mmio_dev = dev; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); ret =kvm_io_bus_register_dev (kvm,KVM_MMIO_BUS , &dev->dev); -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);if (ret <0 ) goto out_free_dev;
@@ -140,16 +140,16 @@ int kvm_vm_ioctl_register_coalesced_mmioif (dev ==NULL )return -EINVAL ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);if (dev->nb_zones >=KVM_COALESCED_MMIO_ZONE_MAX ) { -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return -ENOBUFS ; } dev->zone[dev->nb_zones] = *zone; dev->nb_zones++; -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return 0 ; }
@@ -163,7 +163,7 @@ int kvm_vm_ioctl_unregister_coalesced_mmif (dev ==NULL )return -EINVAL ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); i = dev->nb_zones;while (i) {
@@ -181,7 +181,7 @@ int kvm_vm_ioctl_unregister_coalesced_mm i--; } -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return 0 ; }
virt/kvm/eventfd.c +5 -5
@@ -496,7 +496,7 @@ kvm_assign_ioeventfd(struct kvm *kvm, stelse p->wildcard = true; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);/* Verify that there isnt a match already */ if (ioeventfd_check_collision (kvm, p)) {
@@ -512,12 +512,12 @@ kvm_assign_ioeventfd(struct kvm *kvm, stlist_add_tail (&p->list, &kvm->ioeventfds); -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return 0 ; unlock_fail: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock); fail:kfree (p);
@@ -539,7 +539,7 @@ kvm_deassign_ioeventfd(struct kvm *kvm,if (IS_ERR (eventfd))return PTR_ERR (eventfd); -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);list_for_each_entry_safe (p, tmp, &kvm->ioeventfds, list) {bool wildcard = !(args->flags &KVM_IOEVENTFD_FLAG_DATAMATCH );
@@ -559,7 +559,7 @@ kvm_deassign_ioeventfd(struct kvm *kvm,break ; } -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);eventfd_ctx_put (eventfd);
virt/kvm/ioapic.c +2 -2
@@ -372,9 +372,9 @@ int kvm_ioapic_init(struct kvm *kvm)kvm_ioapic_reset (ioapic);kvm_iodevice_init (&ioapic->dev, &ioapic_mmio_ops); ioapic->kvm = kvm; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); ret =kvm_io_bus_register_dev (kvm,KVM_MMIO_BUS , &ioapic->dev); -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);if (ret <0 )kfree (ioapic);
virt/kvm/kvm_main.c +5 -5
@@ -429,7 +429,7 @@ static struct kvm *kvm_create_vm(void)kvm_eventfd_init (kvm);mutex_init (&kvm->lock);mutex_init (&kvm->irq_lock); -init_rwsem (&kvm->slots_lock); +mutex_init (&kvm->slots_lock);atomic_set (&kvm->users_count,1 );spin_lock (&kvm_lock);list_add (&kvm->vm_list, &vm_list);
@@ -763,9 +763,9 @@ int kvm_set_memory_region(struct kvm *kv {int r; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); r =__kvm_set_memory_region (kvm, mem, user_alloc); -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);return r; }EXPORT_SYMBOL_GPL (kvm_set_memory_region);
@@ -1997,7 +1997,7 @@ int kvm_io_bus_read(struct kvm *kvm, enureturn -EOPNOTSUPP ; } -/* Caller must have write lock on slots_lock. */ +/* Caller must hold slots_lock. */ int kvm_io_bus_register_dev (struct kvm *kvm,enum kvm_bus bus_idx,struct kvm_io_device *dev) {
@@ -2019,7 +2019,7 @@ int kvm_io_bus_register_dev(struct kvm *return 0 ; } -/* Caller must have write lock on slots_lock. */ +/* Caller must hold slots_lock. */ int kvm_io_bus_unregister_dev (struct kvm *kvm,enum kvm_bus bus_idx,struct kvm_io_device *dev) {
arch/ia64/kvm/kvm-ia64.c +2 -2
@@ -1831,7 +1831,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvstruct kvm_memory_slot *memslot;int is_dirty =0 ; -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock);spin_lock (&kvm->arch.dirty_log_lock); r =kvm_ia64_sync_dirty_log (kvm, log);
@@ -1851,7 +1851,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kv } r =0 ; out: -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);spin_unlock (&kvm->arch.dirty_log_lock);return r; }
arch/x86/kvm/i8254.c +1 -1
@@ -602,7 +602,7 @@ static const struct kvm_io_device_ops sp .write = speaker_ioport_write, }; -/* Caller must have writers lock on slots_lock */ +/* Caller must hold slots_lock */ struct kvm_pit *kvm_create_pit (struct kvm *kvm,u32 flags) {struct kvm_pit *pit;
arch/x86/kvm/i8259.c +2 -2
@@ -533,9 +533,9 @@ struct kvm_pic *kvm_create_pic(struct kv* Initialize PIO device */ kvm_iodevice_init (&s->dev, &picdev_ops); -down_write (&kvm->slots_lock); +mutex_lock (&kvm->slots_lock); ret =kvm_io_bus_register_dev (kvm,KVM_PIO_BUS , &s->dev); -up_write (&kvm->slots_lock); +mutex_unlock (&kvm->slots_lock);if (ret <0 ) {kfree (s);return NULL ;
Re: [patch 00/11] convert slotslock to SRCU v2
In reply to Marcelo TosattiQuoted 2 lines · Marcelo Tosatti
Addressing comments.
Looks good.
Signature · 1 line
error compiling committee.c: too many arguments to function
Re: [patch 00/11] convert slotslock to SRCU v2
Quoted 6 lines · Avi Kivity
Quoted 1 line · Marcelo Tosatti
Addressing comments.
Looks good.
Looks good to me too.
--
Gleb.
Re: [patch 00/11] convert slotslock to SRCU v2
Quoted 7 lines · On Thursday 24 December 2009 22:56:38 Gleb Natapov wrote:
Quoted 4 lines · Avi Kivity
Quoted 1 line · Marcelo Tosatti
Addressing comments.
Looks good.
Looks good to me too.
One small comment on the naming:
kvm->memslots->memslots[i]
kvm->aliases->aliases[i]
Doesn't look good...
Signature · 2 lines
regards Yang, Sheng
Re: [patch 00/11] convert slotslock to SRCU v2
Quoted 7 lines · Sheng Yang
Quoted 6 lines · On Thursday 24 December 2009 22:56:38 Gleb Natapov wrote:
Quoted 4 lines · Avi Kivity
Quoted 1 line · Marcelo Tosatti
Addressing comments.
Looks good.
Quoted 8 lines
Quoted 1 line
Looks good to me too.
One small comment on the naming:
kvm->memslots->memslots[i]
kvm->aliases->aliases[i]Doesn't look good...
Hi Sheng,
Yes its somewhat confusing but i could not come up with anything better. Suggestions?
Re: [patch 00/11] convert slotslock to SRCU v2
Quoted 6 lines · Marcelo Tosatti
Quoted 6 lines
One small comment on the naming:
kvm->memslots->memslots[i]
kvm->aliases->aliases[i]
Quoted 7 lines
Quoted 2 lines
Doesn't look good...
Hi Sheng,
Yes its somewhat confusing but i could not come up with anything better. Suggestions?
Could all it 'mem', and put both ->memslots and ->aliases as members. This might simplify things a bit.
However, I don't recommend doing so now, it's just churn. We can always to it later.
Signature · 2 lines
I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain.
Re: [patch 00/11] convert slotslock to SRCU v2
Quoted 10 lines · On Saturday 26 December 2009 00:27:11 Avi Kivity wrote:
Quoted 9 lines · Marcelo Tosatti
Quoted 6 lines
One small comment on the naming:
kvm->memslots->memslots[i]
kvm->aliases->aliases[i]Doesn't look good...
Hi Sheng,
Quoted 8 lines
Quoted 2 lines
Yes its somewhat confusing but i could not come up with anything better. Suggestions?
Could all it 'mem', and put both ->memslots and ->aliases as members. This might simplify things a bit.
However, I don't recommend doing so now, it's just churn. We can always to it later.
Yes. Just happen to see it, and feel a little uneasy... :)
Signature · 2 lines
regards Yang, Sheng
Quoted 7 lines · Marcelo Tosatti
Now that
synchronize_srcu_expeditedis in the tree, we can continue the convertion ofslots_lockto SRCU.Results:
up:
Without this patchset, -smp 64 is simply unusable. An _idle_ Linux guest generates enough interrupts that the system is unable to make any progress:
[root@monster01 ~]# perf report -g
# Samples: 14214748264314
#
# Overhead Command Shared Object Symbol
# ........ ............... ................................. ......
#
40.81% qemu-system-x86 [kernel] [k]
_raw_spin_lock_irq
|
--- _raw_spin_lock_irq
|
|--99.94%-- __down_read
| down_read
| |
| |--99.82%-- 0xffffffffa00479c4
| | 0xffffffffa003a6c9
| | vfs_ioctl
| | do_vfs_ioctl
| | sys_ioctl
| | system_call
| | __GI_ioctl
| --0.18%-- [...]
--0.06%-- [...] 40.57% qemu-system-x86 [kernel] [k]_raw_spin_lock_irqsave
|
--- _raw_spin_lock_irqsave
|
|--99.88%-- __up_read
| up_read
| |
| |--99.82%-- 0xffffffffa0047897
| | 0xffffffffa003a6c9
| | vfs_ioctl
| | do_vfs_ioctl
| | sys_ioctl
| | system_call
| | __GI_ioctl
| --0.18%-- [...]
--0.12%-- [...]With this patchset, -smp 64 flies. Patch to follow. Amazing work!
(and surprising how easy it is to saturate a large system)
Signature · 1 line
error compiling committee.c: too many arguments to function