* [patch 00/11] convert slotslock to SRCU
@ 2009-12-23 11:38 Marcelo Tosatti
2009-12-23 11:38 ` [patch 01/11] KVM: modify memslots layout in struct kvm Marcelo Tosatti
` (13 more replies)
0 siblings, 14 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 11:38 UTC (permalink / raw)
To: kvm; +Cc: avi
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 1992
mov_from_cr8 11
mov_to_cr8 17
inl_from_pmtimer 11226
ipi (skipped)
ipi+halt (skipped)
stock:
cpuid 2272
vmcall 2114
mov_from_cr8 11
mov_to_cr8 17
inl_from_pmtimer 11521
ipi (skipped)
ipi+halt (skipped)
vmcall 6.1% improvement
smp 2:
srcu-memslot:
cpuid 2333
vmcall 2165
mov_from_cr8 11
mov_to_cr8 18
inl_from_pmtimer 12233
ipi 40734
ipi+halt 41675
stock:
cpuid 2512
vmcall 2367
mov_from_cr8 11
mov_to_cr8 18
inl_from_pmtimer 12821
ipi 42941
ipi+halt 43146
vmcall 9.3% improvement
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 01/11] KVM: modify memslots layout in struct kvm
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
@ 2009-12-23 11:38 ` Marcelo Tosatti
2009-12-23 11:38 ` [patch 02/11] KVM: modify alias layout in x86s struct kvm_arch Marcelo Tosatti
` (12 subsequent siblings)
13 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 11:38 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: modify-memslot-layout --]
[-- Type: text/plain, Size: 8417 bytes --]
Have a pointer to an allocated region inside struct kvm.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/kvm/mmu.c
===================================================================
--- kvm.orig/arch/x86/kvm/mmu.c
+++ kvm/arch/x86/kvm/mmu.c
@@ -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_pages
unsigned 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) {
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
--- kvm.orig/arch/x86/kvm/vmx.c
+++ kvm/arch/x86/kvm/vmx.c
@@ -1503,8 +1503,8 @@ static void enter_pmode(struct kvm_vcpu
static 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;
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -2428,7 +2428,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kv
spin_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.
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -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)
Index: kvm/virt/kvm/iommu.c
===================================================================
--- kvm.orig/virt/kvm/iommu.c
+++ kvm/virt/kvm/iommu.c
@@ -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 k
static 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;
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -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(struct
void 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(s
int 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)
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 02/11] KVM: modify alias layout in x86s struct kvm_arch
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
2009-12-23 11:38 ` [patch 01/11] KVM: modify memslots layout in struct kvm Marcelo Tosatti
@ 2009-12-23 11:38 ` Marcelo Tosatti
2009-12-23 11:38 ` [patch 03/11] KVM: split kvm_arch_set_memory_region into prepare and commit Marcelo Tosatti
` (11 subsequent siblings)
13 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 11:38 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: modify-alias-layout --]
[-- Type: text/plain, Size: 2666 bytes --]
Have a pointer to an allocated region inside x86's kvm_arch.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/include/asm/kvm_host.h
===================================================================
--- kvm.orig/arch/x86/include/asm/kvm_host.h
+++ kvm/arch/x86/include/asm/kvm_host.h
@@ -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;
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -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_alias
down_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 *kvm
put_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);
}
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 03/11] KVM: split kvm_arch_set_memory_region into prepare and commit
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
2009-12-23 11:38 ` [patch 01/11] KVM: modify memslots layout in struct kvm Marcelo Tosatti
2009-12-23 11:38 ` [patch 02/11] KVM: modify alias layout in x86s struct kvm_arch Marcelo Tosatti
@ 2009-12-23 11:38 ` Marcelo Tosatti
2009-12-23 11:38 ` [patch 04/11] KVM: introduce gfn_to_pfn_memslot Marcelo Tosatti
` (10 subsequent siblings)
13 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 11:38 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: prepare-commit-memory-region --]
[-- Type: text/plain, Size: 6354 bytes --]
Required for SRCU convertion later.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/ia64/kvm/kvm-ia64.c
===================================================================
--- kvm.orig/arch/ia64/kvm/kvm-ia64.c
+++ kvm/arch/ia64/kvm/kvm-ia64.c
@@ -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 kv
return 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);
Index: kvm/arch/s390/kvm/kvm-s390.c
===================================================================
--- kvm.orig/arch/s390/kvm/kvm-s390.c
+++ kvm/arch/s390/kvm/kvm-s390.c
@@ -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 kv
if (!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)
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -5227,13 +5227,12 @@ void kvm_arch_destroy_vm(struct kvm *kvm
kfree(kvm);
}
-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)
{
- int npages = mem->memory_size >> PAGE_SHIFT;
- struct kvm_memory_slot *memslot = &kvm->memslots->memslots[mem->slot];
+ int npages = memslot->npages;
/*To keep backward compatibility with older userspace,
*x86 needs to hanlde !user_alloc case.
@@ -5253,26 +5252,35 @@ int kvm_arch_set_memory_region(struct kv
if (IS_ERR((void *)userspace_addr))
return PTR_ERR((void *)userspace_addr);
- /* set userspace_addr atomically for kvm_hva_to_rmapp */
- spin_lock(&kvm->mmu_lock);
memslot->userspace_addr = userspace_addr;
- spin_unlock(&kvm->mmu_lock);
- } else {
- if (!old.user_alloc && old.rmap) {
- int ret;
-
- down_write(¤t->mm->mmap_sem);
- ret = do_munmap(current->mm, old.userspace_addr,
- old.npages * PAGE_SIZE);
- up_write(¤t->mm->mmap_sem);
- if (ret < 0)
- printk(KERN_WARNING
- "kvm_vm_ioctl_set_memory_region: "
- "failed to munmap memory\n");
- }
}
}
+
+ return 0;
+}
+
+void kvm_arch_commit_memory_region(struct kvm *kvm,
+ struct kvm_userspace_memory_region *mem,
+ struct kvm_memory_slot old,
+ int user_alloc)
+{
+
+ int npages = mem->memory_size >> PAGE_SHIFT;
+
+ if (!user_alloc && !old.user_alloc && old.rmap && !npages) {
+ int ret;
+
+ down_write(¤t->mm->mmap_sem);
+ ret = do_munmap(current->mm, old.userspace_addr,
+ old.npages * PAGE_SIZE);
+ up_write(¤t->mm->mmap_sem);
+ if (ret < 0)
+ printk(KERN_WARNING
+ "kvm_vm_ioctl_set_memory_region: "
+ "failed to munmap memory\n");
+ }
+
spin_lock(&kvm->mmu_lock);
if (!kvm->arch.n_requested_mmu_pages) {
unsigned int nr_mmu_pages = kvm_mmu_calculate_mmu_pages(kvm);
@@ -5281,8 +5289,6 @@ int kvm_arch_set_memory_region(struct kv
kvm_mmu_slot_remove_write_access(kvm, mem->slot);
spin_unlock(&kvm->mmu_lock);
-
- return 0;
}
void kvm_arch_flush_shadow(struct kvm *kvm)
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -253,7 +253,11 @@ int kvm_set_memory_region(struct kvm *kv
int __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);
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -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 */
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 04/11] KVM: introduce gfn_to_pfn_memslot
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
` (2 preceding siblings ...)
2009-12-23 11:38 ` [patch 03/11] KVM: split kvm_arch_set_memory_region into prepare and commit Marcelo Tosatti
@ 2009-12-23 11:38 ` Marcelo Tosatti
2009-12-23 12:09 ` Avi Kivity
2009-12-23 11:38 ` [patch 05/11] KVM: use gfn_to_pfn_memslot in kvm_iommu_map_pages Marcelo Tosatti
` (9 subsequent siblings)
13 siblings, 1 reply; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 11:38 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: introduce-gfn_to_pfn_memslot --]
[-- Type: text/plain, Size: 2132 bytes --]
Which takes a memslot pointer instead of using kvm->memslots.
To be used by SRCU convertion later.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -272,6 +272,8 @@ void kvm_set_page_dirty(struct page *pag
void 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);
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -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_t
return 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;
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 05/11] KVM: use gfn_to_pfn_memslot in kvm_iommu_map_pages
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
` (3 preceding siblings ...)
2009-12-23 11:38 ` [patch 04/11] KVM: introduce gfn_to_pfn_memslot Marcelo Tosatti
@ 2009-12-23 11:38 ` Marcelo Tosatti
2009-12-23 11:38 ` [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update Marcelo Tosatti
` (8 subsequent siblings)
13 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 11:38 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: pass-memslot-to-kvm_iommu_map_pages --]
[-- Type: text/plain, Size: 2550 bytes --]
So its possible to iommu map a memslot before making it visible to
kvm.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -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,
Index: kvm/virt/kvm/iommu.c
===================================================================
--- kvm.orig/virt/kvm/iommu.c
+++ kvm/virt/kvm/iommu.c
@@ -32,10 +32,10 @@ static int kvm_iommu_unmap_memslots(stru
static 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;
}
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -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
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
` (4 preceding siblings ...)
2009-12-23 11:38 ` [patch 05/11] KVM: use gfn_to_pfn_memslot in kvm_iommu_map_pages Marcelo Tosatti
@ 2009-12-23 11:38 ` Marcelo Tosatti
2009-12-23 12:32 ` Avi Kivity
2009-12-23 11:38 ` [patch 07/11] KVM: use SRCU for dirty log Marcelo Tosatti
` (7 subsequent siblings)
13 siblings, 1 reply; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 11:38 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: introduce-srcu-and-use-for-slots --]
[-- Type: text/plain, Size: 14621 bytes --]
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_hva locking.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/include/linux/kvm.h
===================================================================
--- kvm.orig/include/linux/kvm.h
+++ kvm/include/linux/kvm.h
@@ -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 {
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -44,6 +44,7 @@
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/compat.h>
+#include <linux/srcu.h>
#include <asm/processor.h>
#include <asm/io.h>
@@ -379,11 +380,15 @@ static struct kvm *kvm_create_vm(void)
kvm->memslots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
if (!kvm->memslots)
goto out_err;
+ if (init_srcu_struct(&kvm->srcu))
+ goto out_err;
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- if (!page)
+ if (!page) {
+ cleanup_srcu_struct(&kvm->srcu);
goto out_err;
+ }
kvm->coalesced_mmio_ring =
(struct kvm_coalesced_mmio_ring *)page_address(page);
@@ -391,6 +396,7 @@ static struct kvm *kvm_create_vm(void)
r = kvm_init_mmu_notifier(kvm);
if (r) {
+ cleanup_srcu_struct(&kvm->srcu);
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
put_page(page);
#endif
@@ -481,6 +487,7 @@ static void kvm_destroy_vm(struct kvm *k
kvm_arch_flush_shadow(kvm);
#endif
kvm_arch_destroy_vm(kvm);
+ cleanup_srcu_struct(&kvm->srcu);
hardware_disable_all();
mmdrop(mm);
}
@@ -521,12 +528,13 @@ int __kvm_set_memory_region(struct kvm *
struct kvm_userspace_memory_region *mem,
int user_alloc)
{
- int r;
+ int r, flush_shadow = 0;
gfn_t base_gfn;
unsigned long npages;
unsigned long i;
struct kvm_memory_slot *memslot;
struct kvm_memory_slot old, new;
+ struct kvm_memslots *slots, *old_memslots;
r = -EINVAL;
/* General sanity checks */
@@ -588,15 +596,7 @@ int __kvm_set_memory_region(struct kvm *
memset(new.rmap, 0, npages * sizeof(*new.rmap));
new.user_alloc = user_alloc;
- /*
- * hva_to_rmmap() serialzies with the mmu_lock and to be
- * safe it has to ignore memslots with !user_alloc &&
- * !userspace_addr.
- */
- if (user_alloc)
- new.userspace_addr = mem->userspace_addr;
- else
- new.userspace_addr = 0;
+ new.userspace_addr = mem->userspace_addr;
}
if (!npages)
goto skip_lpage;
@@ -651,8 +651,9 @@ skip_lpage:
if (!new.dirty_bitmap)
goto out_free;
memset(new.dirty_bitmap, 0, dirty_bytes);
+ /* destroy any largepage mappings for dirty tracking */
if (old.npages)
- kvm_arch_flush_shadow(kvm);
+ flush_shadow = 1;
}
#else /* not defined CONFIG_S390 */
new.user_alloc = user_alloc;
@@ -660,34 +661,69 @@ skip_lpage:
new.userspace_addr = mem->userspace_addr;
#endif /* not defined CONFIG_S390 */
- if (!npages)
+ if (!npages) {
+ slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
+ if (!slots)
+ goto out_free;
+ memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots));
+ if (mem->slot >= slots->nmemslots)
+ slots->nmemslots = mem->slot + 1;
+ slots->memslots[mem->slot].flags |= KVM_MEMSLOT_INVALID;
+
+ old_memslots = kvm->memslots;
+ rcu_assign_pointer(kvm->memslots, slots);
+ synchronize_srcu_expedited(&kvm->srcu);
+ /* From this point no new shadow pages pointing to a deleted
+ * memslot will be created.
+ *
+ * validation of sp->gfn happens in:
+ * - gfn_to_hva (kvm_read_guest, gfn_to_pfn)
+ * - kvm_is_visible_gfn (mmu_check_roots)
+ */
kvm_arch_flush_shadow(kvm);
+ kfree(old_memslots);
+ }
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;
+#ifdef CONFIG_DMAR
+ /* map the pages in iommu page table */
+ if (npages)
+ r = kvm_iommu_map_pages(kvm, &new);
+ if (r)
+ goto out_free;
+#endif
- *memslot = new;
- spin_unlock(&kvm->mmu_lock);
+ slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
+ if (!slots)
+ goto out_free;
+ memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots));
+ if (mem->slot >= slots->nmemslots)
+ slots->nmemslots = mem->slot + 1;
+
+ /* actual memory is freed via old in kvm_free_physmem_slot below */
+ if (!npages) {
+ new.rmap = NULL;
+ new.dirty_bitmap = NULL;
+ for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i)
+ new.lpage_info[i] = NULL;
+ }
+
+ slots->memslots[mem->slot] = new;
+ old_memslots = kvm->memslots;
+ rcu_assign_pointer(kvm->memslots, slots);
+ synchronize_srcu_expedited(&kvm->srcu);
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 */
- spin_lock(&kvm->mmu_lock);
- if (!npages)
- *memslot = old;
- spin_unlock(&kvm->mmu_lock);
-#ifdef CONFIG_DMAR
- /* map the pages in iommu page table */
- r = kvm_iommu_map_pages(kvm, memslot);
- if (r)
- goto out;
-#endif
+ kvm_free_physmem_slot(&old, &new);
+ kfree(old_memslots);
+
+ if (flush_shadow)
+ kvm_arch_flush_shadow(kvm);
+
return 0;
out_free:
@@ -787,7 +823,7 @@ 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;
+ struct kvm_memslots *slots = rcu_dereference(kvm->memslots);
for (i = 0; i < slots->nmemslots; ++i) {
struct kvm_memory_slot *memslot = &slots->memslots[i];
@@ -809,12 +845,15 @@ struct kvm_memory_slot *gfn_to_memslot(s
int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
{
int i;
- struct kvm_memslots *slots = kvm->memslots;
+ struct kvm_memslots *slots = rcu_dereference(kvm->memslots);
gfn = unalias_gfn(kvm, gfn);
for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
struct kvm_memory_slot *memslot = &slots->memslots[i];
+ if (memslot->flags & KVM_MEMSLOT_INVALID)
+ continue;
+
if (gfn >= memslot->base_gfn
&& gfn < memslot->base_gfn + memslot->npages)
return 1;
@@ -823,13 +862,31 @@ int kvm_is_visible_gfn(struct kvm *kvm,
}
EXPORT_SYMBOL_GPL(kvm_is_visible_gfn);
+int memslot_id(struct kvm *kvm, gfn_t gfn)
+{
+ int i;
+ struct kvm_memslots *slots = rcu_dereference(kvm->memslots);
+ struct kvm_memory_slot *memslot = NULL;
+
+ gfn = unalias_gfn(kvm, gfn);
+ for (i = 0; i < slots->nmemslots; ++i) {
+ memslot = &slots->memslots[i];
+
+ if (gfn >= memslot->base_gfn
+ && gfn < memslot->base_gfn + memslot->npages)
+ break;
+ }
+
+ return memslot - slots->memslots;
+}
+
unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
{
struct kvm_memory_slot *slot;
gfn = unalias_gfn(kvm, gfn);
slot = gfn_to_memslot_unaliased(kvm, gfn);
- if (!slot)
+ if (!slot || slot->flags & KVM_MEMSLOT_INVALID)
return bad_hva();
return (slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE);
}
Index: kvm/arch/ia64/kvm/kvm-ia64.c
===================================================================
--- kvm.orig/arch/ia64/kvm/kvm-ia64.c
+++ kvm/arch/ia64/kvm/kvm-ia64.c
@@ -1834,6 +1834,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kv
struct 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;
}
Index: kvm/arch/x86/kvm/mmu.c
===================================================================
--- kvm.orig/arch/x86/kvm/mmu.c
+++ kvm/arch/x86/kvm/mmu.c
@@ -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 *kv
int (*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 *kvm
static 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_vc
static 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;
}
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
--- kvm.orig/arch/x86/kvm/vmx.c
+++ kvm/arch/x86/kvm/vmx.c
@@ -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_vcpu
static 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;
}
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -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;
Index: kvm/virt/kvm/assigned-dev.c
===================================================================
--- kvm.orig/virt/kvm/assigned-dev.c
+++ kvm/virt/kvm/assigned-dev.c
@@ -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;
}
Index: kvm/virt/kvm/iommu.c
===================================================================
--- kvm.orig/virt/kvm/iommu.c
+++ kvm/virt/kvm/iommu.c
@@ -78,7 +78,7 @@ static int kvm_iommu_map_memslots(struct
int 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(stru
int 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,
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 07/11] KVM: use SRCU for dirty log
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
` (5 preceding siblings ...)
2009-12-23 11:38 ` [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update Marcelo Tosatti
@ 2009-12-23 11:38 ` Marcelo Tosatti
2009-12-23 11:38 ` [patch 08/11] KVM: x86: switch kvm_set_memory_alias to SRCU update Marcelo Tosatti
` (6 subsequent siblings)
13 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 11:38 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: use-srcu-for-dirty-log --]
[-- Type: text/plain, Size: 2025 bytes --]
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -2416,27 +2416,60 @@ static int kvm_vm_ioctl_reinject(struct
int 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;
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 08/11] KVM: x86: switch kvm_set_memory_alias to SRCU update
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
` (6 preceding siblings ...)
2009-12-23 11:38 ` [patch 07/11] KVM: use SRCU for dirty log Marcelo Tosatti
@ 2009-12-23 11:38 ` Marcelo Tosatti
2009-12-23 11:38 ` [patch 09/11] KVM: convert io_bus to SRCU Marcelo Tosatti
` (5 subsequent siblings)
13 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 11:38 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: srcu-alias-update --]
[-- Type: text/plain, Size: 5255 bytes --]
Using a similar two-step procedure as for memslots.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/include/asm/kvm_host.h
===================================================================
--- kvm.orig/arch/x86/include/asm/kvm_host.h
+++ kvm/arch/x86/include/asm/kvm_host.h
@@ -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;
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -38,6 +38,7 @@
#include <linux/intel-iommu.h>
#include <linux/cpufreq.h>
#include <linux/user-return-notifier.h>
+#include <linux/srcu.h>
#include <trace/events/kvm.h>
#undef TRACE_INCLUDE_FILE
#define CREATE_TRACE_POINTS
@@ -2224,11 +2225,32 @@ static int kvm_vm_ioctl_get_nr_mmu_pages
return kvm->arch.n_alloc_mmu_pages;
}
+gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn)
+{
+ int i;
+ struct kvm_mem_alias *alias;
+ struct kvm_mem_aliases *aliases;
+
+ aliases = rcu_dereference(kvm->arch.aliases);
+
+ for (i = 0; i < aliases->naliases; ++i) {
+ alias = &aliases->aliases[i];
+ if (alias->flags & KVM_ALIAS_INVALID)
+ continue;
+ if (gfn >= alias->base_gfn
+ && gfn < alias->base_gfn + alias->npages)
+ return alias->target_gfn + gfn - alias->base_gfn;
+ }
+ return gfn;
+}
+
gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
{
int i;
struct kvm_mem_alias *alias;
- struct kvm_mem_aliases *aliases = kvm->arch.aliases;
+ struct kvm_mem_aliases *aliases;
+
+ aliases = rcu_dereference(kvm->arch.aliases);
for (i = 0; i < aliases->naliases; ++i) {
alias = &aliases->aliases[i];
@@ -2249,7 +2271,7 @@ static int kvm_vm_ioctl_set_memory_alias
{
int r, n;
struct kvm_mem_alias *p;
- struct kvm_mem_aliases *aliases;
+ struct kvm_mem_aliases *aliases, *old_aliases;
r = -EINVAL;
/* General sanity checks */
@@ -2266,28 +2288,48 @@ static int kvm_vm_ioctl_set_memory_alias
< alias->target_phys_addr)
goto out;
+ r = -ENOMEM;
+ aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
+ if (!aliases)
+ goto out;
+
down_write(&kvm->slots_lock);
- spin_lock(&kvm->mmu_lock);
- aliases = kvm->arch.aliases;
+ /* invalidate any gfn reference in case of deletion/shrinking */
+ memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases));
+ aliases->aliases[alias->slot].flags |= KVM_ALIAS_INVALID;
+ old_aliases = kvm->arch.aliases;
+ rcu_assign_pointer(kvm->arch.aliases, aliases);
+ synchronize_srcu_expedited(&kvm->srcu);
+ kvm_mmu_zap_all(kvm);
+ kfree(old_aliases);
+
+ r = -ENOMEM;
+ aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
+ if (!aliases)
+ goto out_unlock;
+
+ memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_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;
+ p->flags &= ~(KVM_ALIAS_INVALID);
for (n = KVM_ALIAS_SLOTS; n > 0; --n)
if (aliases->aliases[n - 1].npages)
break;
aliases->naliases = n;
- spin_unlock(&kvm->mmu_lock);
- kvm_mmu_zap_all(kvm);
+ old_aliases = kvm->arch.aliases;
+ rcu_assign_pointer(kvm->arch.aliases, aliases);
+ synchronize_srcu_expedited(&kvm->srcu);
+ kfree(old_aliases);
+ r = 0;
+out_unlock:
up_write(&kvm->slots_lock);
-
- return 0;
-
out:
return r;
}
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -265,6 +265,8 @@ void kvm_arch_commit_memory_region(struc
void 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
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -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();
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 09/11] KVM: convert io_bus to SRCU
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
` (7 preceding siblings ...)
2009-12-23 11:38 ` [patch 08/11] KVM: x86: switch kvm_set_memory_alias to SRCU update Marcelo Tosatti
@ 2009-12-23 11:38 ` Marcelo Tosatti
2009-12-23 11:38 ` [patch 10/11] KVM: switch vcpu context to use SRCU Marcelo Tosatti
` (4 subsequent siblings)
13 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 11:38 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: srcu-iobus-update --]
[-- Type: text/plain, Size: 14236 bytes --]
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/kvm/i8254.c
===================================================================
--- kvm.orig/arch/x86/kvm/i8254.c
+++ kvm/arch/x86/kvm/i8254.c
@@ -642,13 +642,13 @@ struct kvm_pit *kvm_create_pit(struct kv
kvm_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 kv
return 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)
Index: kvm/arch/x86/kvm/i8259.c
===================================================================
--- kvm.orig/arch/x86/kvm/i8259.c
+++ kvm/arch/x86/kvm/i8259.c
@@ -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;
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -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;
Index: kvm/virt/kvm/eventfd.c
===================================================================
--- kvm.orig/virt/kvm/eventfd.c
+++ kvm/virt/kvm/eventfd.c
@@ -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, st
kvm_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;
Index: kvm/virt/kvm/ioapic.c
===================================================================
--- kvm.orig/virt/kvm/ioapic.c
+++ kvm/virt/kvm/ioapic.c
@@ -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);
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -85,6 +85,8 @@ static long kvm_vcpu_ioctl(struct file *
static int hardware_enable_all(void);
static void hardware_disable_all(void);
+static void kvm_io_bus_destroy(struct kvm_io_bus *bus);
+
static bool kvm_rebooting;
static bool largepages_enabled = true;
@@ -358,7 +360,7 @@ static int kvm_init_mmu_notifier(struct
static struct kvm *kvm_create_vm(void)
{
- int r = 0;
+ int r = 0, i;
struct kvm *kvm = kvm_arch_create_vm();
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
struct page *page;
@@ -382,6 +384,14 @@ static struct kvm *kvm_create_vm(void)
goto out_err;
if (init_srcu_struct(&kvm->srcu))
goto out_err;
+ for (i = 0; i < KVM_NR_BUSES; i++) {
+ kvm->buses[i] = kzalloc(sizeof(struct kvm_io_bus),
+ GFP_KERNEL);
+ if (!kvm->buses[i]) {
+ cleanup_srcu_struct(&kvm->srcu);
+ goto out_err;
+ }
+ }
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
@@ -407,11 +417,9 @@ static struct kvm *kvm_create_vm(void)
atomic_inc(&kvm->mm->mm_count);
spin_lock_init(&kvm->mmu_lock);
spin_lock_init(&kvm->requests_lock);
- kvm_io_bus_init(&kvm->pio_bus);
kvm_eventfd_init(kvm);
mutex_init(&kvm->lock);
mutex_init(&kvm->irq_lock);
- kvm_io_bus_init(&kvm->mmio_bus);
init_rwsem(&kvm->slots_lock);
atomic_set(&kvm->users_count, 1);
spin_lock(&kvm_lock);
@@ -426,6 +434,8 @@ out:
out_err:
hardware_disable_all();
out_err_nodisable:
+ for (i = 0; i < KVM_NR_BUSES; i++)
+ kfree(kvm->buses[i]);
kfree(kvm->memslots);
kfree(kvm);
return ERR_PTR(r);
@@ -471,6 +481,7 @@ void kvm_free_physmem(struct kvm *kvm)
static void kvm_destroy_vm(struct kvm *kvm)
{
+ int i;
struct mm_struct *mm = kvm->mm;
kvm_arch_sync_events(kvm);
@@ -478,8 +489,8 @@ static void kvm_destroy_vm(struct kvm *k
list_del(&kvm->vm_list);
spin_unlock(&kvm_lock);
kvm_free_irq_routing(kvm);
- kvm_io_bus_destroy(&kvm->pio_bus);
- kvm_io_bus_destroy(&kvm->mmio_bus);
+ for (i = 0; i < KVM_NR_BUSES; i++)
+ kvm_io_bus_destroy(kvm->buses[i]);
kvm_coalesced_mmio_free(kvm);
#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm);
@@ -1937,12 +1948,7 @@ static struct notifier_block kvm_reboot_
.priority = 0,
};
-void kvm_io_bus_init(struct kvm_io_bus *bus)
-{
- memset(bus, 0, sizeof(*bus));
-}
-
-void kvm_io_bus_destroy(struct kvm_io_bus *bus)
+static void kvm_io_bus_destroy(struct kvm_io_bus *bus)
{
int i;
@@ -1951,13 +1957,15 @@ void kvm_io_bus_destroy(struct kvm_io_bu
kvm_iodevice_destructor(pos);
}
+ kfree(bus);
}
/* kvm_io_bus_write - called under kvm->slots_lock */
-int kvm_io_bus_write(struct kvm_io_bus *bus, gpa_t addr,
+int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
int len, const void *val)
{
int i;
+ struct kvm_io_bus *bus = rcu_dereference(kvm->buses[bus_idx]);
for (i = 0; i < bus->dev_count; i++)
if (!kvm_iodevice_write(bus->devs[i], addr, len, val))
return 0;
@@ -1965,59 +1973,71 @@ int kvm_io_bus_write(struct kvm_io_bus *
}
/* kvm_io_bus_read - called under kvm->slots_lock */
-int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val)
+int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
+ int len, void *val)
{
int i;
+ struct kvm_io_bus *bus = rcu_dereference(kvm->buses[bus_idx]);
+
for (i = 0; i < bus->dev_count; i++)
if (!kvm_iodevice_read(bus->devs[i], addr, len, val))
return 0;
return -EOPNOTSUPP;
}
-int kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
- struct kvm_io_device *dev)
+/* Caller must have write lock on slots_lock. */
+int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx,
+ struct kvm_io_device *dev)
{
- int ret;
+ struct kvm_io_bus *new_bus, *bus;
- down_write(&kvm->slots_lock);
- ret = __kvm_io_bus_register_dev(bus, dev);
- up_write(&kvm->slots_lock);
-
- return ret;
-}
-
-/* An unlocked version. Caller must have write lock on slots_lock. */
-int __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
- struct kvm_io_device *dev)
-{
+ bus = kvm->buses[bus_idx];
if (bus->dev_count > NR_IOBUS_DEVS-1)
return -ENOSPC;
- bus->devs[bus->dev_count++] = dev;
+ new_bus = kzalloc(sizeof(struct kvm_io_bus), GFP_KERNEL);
+ if (!new_bus)
+ return -ENOMEM;
+ memcpy(new_bus, bus, sizeof(struct kvm_io_bus));
+ new_bus->devs[new_bus->dev_count++] = dev;
+ rcu_assign_pointer(kvm->buses[bus_idx], new_bus);
+ synchronize_srcu_expedited(&kvm->srcu);
+ kfree(bus);
return 0;
}
-void kvm_io_bus_unregister_dev(struct kvm *kvm,
- struct kvm_io_bus *bus,
- struct kvm_io_device *dev)
+/* Caller must have write lock on slots_lock. */
+int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
+ struct kvm_io_device *dev)
{
- down_write(&kvm->slots_lock);
- __kvm_io_bus_unregister_dev(bus, dev);
- up_write(&kvm->slots_lock);
-}
+ int i, r;
+ struct kvm_io_bus *new_bus, *bus;
-/* An unlocked version. Caller must have write lock on slots_lock. */
-void __kvm_io_bus_unregister_dev(struct kvm_io_bus *bus,
- struct kvm_io_device *dev)
-{
- int i;
+ new_bus = kzalloc(sizeof(struct kvm_io_bus), GFP_KERNEL);
+ if (!new_bus)
+ return -ENOMEM;
- for (i = 0; i < bus->dev_count; i++)
- if (bus->devs[i] == dev) {
- bus->devs[i] = bus->devs[--bus->dev_count];
+ bus = kvm->buses[bus_idx];
+ memcpy(new_bus, bus, sizeof(struct kvm_io_bus));
+
+ r = -ENOENT;
+ for (i = 0; i < new_bus->dev_count; i++)
+ if (new_bus->devs[i] == dev) {
+ r = 0;
+ new_bus->devs[i] = new_bus->devs[--new_bus->dev_count];
break;
}
+
+ if (r) {
+ kfree(new_bus);
+ return r;
+ }
+
+ rcu_assign_pointer(kvm->buses[bus_idx], new_bus);
+ synchronize_srcu_expedited(&kvm->srcu);
+ kfree(bus);
+ return r;
}
static struct notifier_block kvm_cpu_notifier = {
Index: kvm/virt/kvm/coalesced_mmio.c
===================================================================
--- kvm.orig/virt/kvm/coalesced_mmio.c
+++ kvm/virt/kvm/coalesced_mmio.c
@@ -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;
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -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 *v
int 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_v
int 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;
Index: kvm/arch/ia64/kvm/kvm-ia64.c
===================================================================
--- kvm.orig/arch/ia64/kvm/kvm-ia64.c
+++ kvm/arch/ia64/kvm/kvm-ia64.c
@@ -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);
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 10/11] KVM: switch vcpu context to use SRCU
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
` (8 preceding siblings ...)
2009-12-23 11:38 ` [patch 09/11] KVM: convert io_bus to SRCU Marcelo Tosatti
@ 2009-12-23 11:38 ` Marcelo Tosatti
2009-12-23 11:38 ` [patch 11/11] KVM: convert slots_lock to a mutex Marcelo Tosatti
` (3 subsequent siblings)
13 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 11:38 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: switch-to-memslot-srcu --]
[-- Type: text/plain, Size: 8330 bytes --]
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -1307,15 +1307,15 @@ static int __msr_io(struct kvm_vcpu *vcp
int (*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_vcpu
static 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_v
kvm_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_v
preempt_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 *v
if (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);
}
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -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;
Index: kvm/arch/x86/kvm/mmu.c
===================================================================
--- kvm.orig/arch/x86/kvm/mmu.c
+++ kvm/arch/x86/kvm/mmu.c
@@ -2937,10 +2937,9 @@ static int mmu_shrink(int nr_to_scan, gf
spin_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);
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
--- kvm.orig/arch/x86/kvm/vmx.c
+++ kvm/arch/x86/kvm/vmx.c
@@ -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;
}
Index: kvm/arch/ia64/kvm/kvm-ia64.c
===================================================================
--- kvm.orig/arch/ia64/kvm/kvm-ia64.c
+++ kvm/arch/ia64/kvm/kvm-ia64.c
@@ -636,12 +636,9 @@ static void kvm_vcpu_post_transition(str
static 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;
}
Index: kvm/arch/s390/kvm/kvm-s390.h
===================================================================
--- kvm.orig/arch/s390/kvm/kvm-s390.h
+++ kvm/arch/s390/kvm/kvm-s390.h
@@ -67,10 +67,14 @@ static inline long kvm_s390_vcpu_get_mem
static 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 */
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 11/11] KVM: convert slots_lock to a mutex
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
` (9 preceding siblings ...)
2009-12-23 11:38 ` [patch 10/11] KVM: switch vcpu context to use SRCU Marcelo Tosatti
@ 2009-12-23 11:38 ` Marcelo Tosatti
2009-12-23 12:37 ` [patch 00/11] convert slotslock to SRCU Avi Kivity
` (2 subsequent siblings)
13 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 11:38 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: convert-slotslock-to-mutex --]
[-- Type: text/plain, Size: 9777 bytes --]
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
--- kvm.orig/arch/x86/kvm/vmx.c
+++ kvm/arch/x86/kvm/vmx.c
@@ -2227,7 +2227,7 @@ static int alloc_apic_access_page(struct
struct 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(stru
struct 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;
}
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -2209,14 +2209,14 @@ static int kvm_vm_ioctl_set_nr_mmu_pages
if (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_alias
if (!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 kv
unsigned 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 *filp
if (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: {
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -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;
Index: kvm/virt/kvm/coalesced_mmio.c
===================================================================
--- kvm.orig/virt/kvm/coalesced_mmio.c
+++ kvm/virt/kvm/coalesced_mmio.c
@@ -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_mmio
if (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_mm
if (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;
}
Index: kvm/virt/kvm/eventfd.c
===================================================================
--- kvm.orig/virt/kvm/eventfd.c
+++ kvm/virt/kvm/eventfd.c
@@ -496,7 +496,7 @@ kvm_assign_ioeventfd(struct kvm *kvm, st
else
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, st
list_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);
Index: kvm/virt/kvm/ioapic.c
===================================================================
--- kvm.orig/virt/kvm/ioapic.c
+++ kvm/virt/kvm/ioapic.c
@@ -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);
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -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, enu
return -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)
{
Index: kvm/arch/ia64/kvm/kvm-ia64.c
===================================================================
--- kvm.orig/arch/ia64/kvm/kvm-ia64.c
+++ kvm/arch/ia64/kvm/kvm-ia64.c
@@ -1831,7 +1831,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kv
struct 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;
}
Index: kvm/arch/x86/kvm/i8254.c
===================================================================
--- kvm.orig/arch/x86/kvm/i8254.c
+++ kvm/arch/x86/kvm/i8254.c
@@ -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;
Index: kvm/arch/x86/kvm/i8259.c
===================================================================
--- kvm.orig/arch/x86/kvm/i8259.c
+++ kvm/arch/x86/kvm/i8259.c
@@ -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;
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch 04/11] KVM: introduce gfn_to_pfn_memslot
2009-12-23 11:38 ` [patch 04/11] KVM: introduce gfn_to_pfn_memslot Marcelo Tosatti
@ 2009-12-23 12:09 ` Avi Kivity
0 siblings, 0 replies; 37+ messages in thread
From: Avi Kivity @ 2009-12-23 12:09 UTC (permalink / raw)
To: Marcelo Tosatti; +Cc: kvm
On 12/23/2009 01:38 PM, Marcelo Tosatti wrote:
> Which takes a memslot pointer instead of using kvm->memslots.
>
> To be used by SRCU convertion later.
>
> Signed-off-by: Marcelo Tosatti<mtosatti@redhat.com>
>
>
> @@ -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.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update
2009-12-23 11:38 ` [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update Marcelo Tosatti
@ 2009-12-23 12:32 ` Avi Kivity
2009-12-23 14:19 ` Marcelo Tosatti
0 siblings, 1 reply; 37+ messages in thread
From: Avi Kivity @ 2009-12-23 12:32 UTC (permalink / raw)
To: Marcelo Tosatti; +Cc: kvm
On 12/23/2009 01:38 PM, Marcelo Tosatti wrote:
> 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_hva locking.
>
>
> r = kvm_arch_prepare_memory_region(kvm,&new, old, user_alloc);
> if (r)
> goto out_free;
>
r == 0
>
> - 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)
> +#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.
>
> +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.
> @@ -807,23 +808,18 @@ static int kvm_handle_hva(struct kvm *kv
> int (*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).
> @@ -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);
>
>
Again, would like to move the srcu_locking to an outer scope.
> @@ -1503,10 +1504,18 @@ static void enter_pmode(struct kvm_vcpu
> static 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;
> }
>
Shouldn't we already hold the srcu_lock as part of normal guest exit
(similar to down_read() we do today)?
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch 00/11] convert slotslock to SRCU
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
` (10 preceding siblings ...)
2009-12-23 11:38 ` [patch 11/11] KVM: convert slots_lock to a mutex Marcelo Tosatti
@ 2009-12-23 12:37 ` Avi Kivity
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
2009-12-27 13:16 ` [patch 00/11] convert slotslock to SRCU Avi Kivity
13 siblings, 0 replies; 37+ messages in thread
From: Avi Kivity @ 2009-12-23 12:37 UTC (permalink / raw)
To: Marcelo Tosatti; +Cc: kvm
On 12/23/2009 01:38 PM, Marcelo Tosatti wrote:
> Now that synchronize_srcu_expedited is in the tree, we can continue the
> convertion of slots_lock to 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.
> Results:
> up:
>
> vmcall 6.1% improvement
>
> smp 2:
>
>
> vmcall 9.3% improvement
>
Pretty impressive, all this from removing an uncontended semaphore.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update
2009-12-23 12:32 ` Avi Kivity
@ 2009-12-23 14:19 ` Marcelo Tosatti
2009-12-23 14:33 ` Avi Kivity
0 siblings, 1 reply; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 14:19 UTC (permalink / raw)
To: Avi Kivity; +Cc: kvm
On Wed, Dec 23, 2009 at 02:32:55PM +0200, Avi Kivity wrote:
> On 12/23/2009 01:38 PM, Marcelo Tosatti wrote:
>> 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_hva locking.
>>
>>
>> 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.
>>
>> - 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)
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.
>> +#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.
Fixed.
>> +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.
>> @@ -807,23 +808,18 @@ static int kvm_handle_hva(struct kvm *kv
>> int (*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).
Done.
>> @@ -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);
>>
>>
>
> Again, would like to move the srcu_locking to 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.
>> @@ -1503,10 +1504,18 @@ static void enter_pmode(struct kvm_vcpu
>> static 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;
>> }
>>
>
> Shouldn't we already hold the srcu_lock as part of normal guest exit
> (similar to down_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).
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update
2009-12-23 14:19 ` Marcelo Tosatti
@ 2009-12-23 14:33 ` Avi Kivity
2009-12-23 15:13 ` Marcelo Tosatti
0 siblings, 1 reply; 37+ messages in thread
From: Avi Kivity @ 2009-12-23 14:33 UTC (permalink / raw)
To: Marcelo Tosatti; +Cc: kvm
On 12/23/2009 04:19 PM, Marcelo Tosatti wrote:
> On Wed, Dec 23, 2009 at 02:32:55PM +0200, Avi Kivity wrote:
>
>> On 12/23/2009 01:38 PM, Marcelo Tosatti wrote:
>>
>>> 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_hva locking.
>>>
>>>
>>> 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.
>
That's fine here, just pointing out you're inheriting this r == 0 later on.
> 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.
>
Ok, then please fix it separately for easier backporting.
>>> 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.
>>
> 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.
>
A comment should be sufficient. Otherwise someone might read the code
and point out it's unnecessary.
>> Shouldn't we already hold the srcu_lock as part of normal guest exit
>> (similar to down_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).
>
>
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.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update
2009-12-23 14:33 ` Avi Kivity
@ 2009-12-23 15:13 ` Marcelo Tosatti
0 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 15:13 UTC (permalink / raw)
To: Avi Kivity; +Cc: kvm
On Wed, Dec 23, 2009 at 04:33:06PM +0200, Avi Kivity wrote:
> On 12/23/2009 04:19 PM, Marcelo Tosatti wrote:
>> On Wed, Dec 23, 2009 at 02:32:55PM +0200, Avi Kivity wrote:
>>
>>> On 12/23/2009 01:38 PM, Marcelo Tosatti wrote:
>>>
>>>> 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_hva locking.
>>>>
>>>>
>>>> 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.
>>
>
> That's fine here, just pointing out you're inheriting this r == 0 later on.
>
>> 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.
>>
>
> Ok, then please fix it separately for easier backporting.
Its not a bug.
>>>> 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.
>>>
>> 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.
>>
>
> A comment should be sufficient. Otherwise someone might read the code
> and point out it's unnecessary.
>
>
>
>>> Shouldn't we already hold the srcu_lock as part of normal guest exit
>>> (similar to down_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).
>>
>>
>
> 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.
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.
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 00/11] convert slotslock to SRCU v2
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
` (11 preceding siblings ...)
2009-12-23 12:37 ` [patch 00/11] convert slotslock to SRCU Avi Kivity
@ 2009-12-23 16:35 ` Marcelo Tosatti
2009-12-23 16:35 ` [patch 01/11] KVM: modify memslots layout in struct kvm Marcelo Tosatti
` (11 more replies)
2009-12-27 13:16 ` [patch 00/11] convert slotslock to SRCU Avi Kivity
13 siblings, 12 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 16:35 UTC (permalink / raw)
To: kvm; +Cc: avi
Addressing comments.
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 01/11] KVM: modify memslots layout in struct kvm
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
@ 2009-12-23 16:35 ` Marcelo Tosatti
2009-12-23 16:35 ` [patch 02/11] KVM: modify alias layout in x86s struct kvm_arch Marcelo Tosatti
` (10 subsequent siblings)
11 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 16:35 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: modify-memslot-layout --]
[-- Type: text/plain, Size: 8417 bytes --]
Have a pointer to an allocated region inside struct kvm.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/kvm/mmu.c
===================================================================
--- kvm.orig/arch/x86/kvm/mmu.c
+++ kvm/arch/x86/kvm/mmu.c
@@ -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_pages
unsigned 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) {
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
--- kvm.orig/arch/x86/kvm/vmx.c
+++ kvm/arch/x86/kvm/vmx.c
@@ -1503,8 +1503,8 @@ static void enter_pmode(struct kvm_vcpu
static 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;
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -2428,7 +2428,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kv
spin_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.
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -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)
Index: kvm/virt/kvm/iommu.c
===================================================================
--- kvm.orig/virt/kvm/iommu.c
+++ kvm/virt/kvm/iommu.c
@@ -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 k
static 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;
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -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(struct
void 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(s
int 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)
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 02/11] KVM: modify alias layout in x86s struct kvm_arch
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
2009-12-23 16:35 ` [patch 01/11] KVM: modify memslots layout in struct kvm Marcelo Tosatti
@ 2009-12-23 16:35 ` Marcelo Tosatti
2009-12-23 16:35 ` [patch 03/11] KVM: split kvm_arch_set_memory_region into prepare and commit Marcelo Tosatti
` (9 subsequent siblings)
11 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 16:35 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: modify-alias-layout --]
[-- Type: text/plain, Size: 2666 bytes --]
Have a pointer to an allocated region inside x86's kvm_arch.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/include/asm/kvm_host.h
===================================================================
--- kvm.orig/arch/x86/include/asm/kvm_host.h
+++ kvm/arch/x86/include/asm/kvm_host.h
@@ -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;
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -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_alias
down_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 *kvm
put_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);
}
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 03/11] KVM: split kvm_arch_set_memory_region into prepare and commit
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
2009-12-23 16:35 ` [patch 01/11] KVM: modify memslots layout in struct kvm Marcelo Tosatti
2009-12-23 16:35 ` [patch 02/11] KVM: modify alias layout in x86s struct kvm_arch Marcelo Tosatti
@ 2009-12-23 16:35 ` Marcelo Tosatti
2009-12-23 16:35 ` [patch 04/11] KVM: introduce gfn_to_pfn_memslot Marcelo Tosatti
` (8 subsequent siblings)
11 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 16:35 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: prepare-commit-memory-region --]
[-- Type: text/plain, Size: 6354 bytes --]
Required for SRCU convertion later.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/ia64/kvm/kvm-ia64.c
===================================================================
--- kvm.orig/arch/ia64/kvm/kvm-ia64.c
+++ kvm/arch/ia64/kvm/kvm-ia64.c
@@ -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 kv
return 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);
Index: kvm/arch/s390/kvm/kvm-s390.c
===================================================================
--- kvm.orig/arch/s390/kvm/kvm-s390.c
+++ kvm/arch/s390/kvm/kvm-s390.c
@@ -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 kv
if (!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)
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -5227,13 +5227,12 @@ void kvm_arch_destroy_vm(struct kvm *kvm
kfree(kvm);
}
-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)
{
- int npages = mem->memory_size >> PAGE_SHIFT;
- struct kvm_memory_slot *memslot = &kvm->memslots->memslots[mem->slot];
+ int npages = memslot->npages;
/*To keep backward compatibility with older userspace,
*x86 needs to hanlde !user_alloc case.
@@ -5253,26 +5252,35 @@ int kvm_arch_set_memory_region(struct kv
if (IS_ERR((void *)userspace_addr))
return PTR_ERR((void *)userspace_addr);
- /* set userspace_addr atomically for kvm_hva_to_rmapp */
- spin_lock(&kvm->mmu_lock);
memslot->userspace_addr = userspace_addr;
- spin_unlock(&kvm->mmu_lock);
- } else {
- if (!old.user_alloc && old.rmap) {
- int ret;
-
- down_write(¤t->mm->mmap_sem);
- ret = do_munmap(current->mm, old.userspace_addr,
- old.npages * PAGE_SIZE);
- up_write(¤t->mm->mmap_sem);
- if (ret < 0)
- printk(KERN_WARNING
- "kvm_vm_ioctl_set_memory_region: "
- "failed to munmap memory\n");
- }
}
}
+
+ return 0;
+}
+
+void kvm_arch_commit_memory_region(struct kvm *kvm,
+ struct kvm_userspace_memory_region *mem,
+ struct kvm_memory_slot old,
+ int user_alloc)
+{
+
+ int npages = mem->memory_size >> PAGE_SHIFT;
+
+ if (!user_alloc && !old.user_alloc && old.rmap && !npages) {
+ int ret;
+
+ down_write(¤t->mm->mmap_sem);
+ ret = do_munmap(current->mm, old.userspace_addr,
+ old.npages * PAGE_SIZE);
+ up_write(¤t->mm->mmap_sem);
+ if (ret < 0)
+ printk(KERN_WARNING
+ "kvm_vm_ioctl_set_memory_region: "
+ "failed to munmap memory\n");
+ }
+
spin_lock(&kvm->mmu_lock);
if (!kvm->arch.n_requested_mmu_pages) {
unsigned int nr_mmu_pages = kvm_mmu_calculate_mmu_pages(kvm);
@@ -5281,8 +5289,6 @@ int kvm_arch_set_memory_region(struct kv
kvm_mmu_slot_remove_write_access(kvm, mem->slot);
spin_unlock(&kvm->mmu_lock);
-
- return 0;
}
void kvm_arch_flush_shadow(struct kvm *kvm)
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -253,7 +253,11 @@ int kvm_set_memory_region(struct kvm *kv
int __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);
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -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 */
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 04/11] KVM: introduce gfn_to_pfn_memslot
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
` (2 preceding siblings ...)
2009-12-23 16:35 ` [patch 03/11] KVM: split kvm_arch_set_memory_region into prepare and commit Marcelo Tosatti
@ 2009-12-23 16:35 ` Marcelo Tosatti
2009-12-23 16:35 ` [patch 05/11] KVM: use gfn_to_pfn_memslot in kvm_iommu_map_pages Marcelo Tosatti
` (7 subsequent siblings)
11 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 16:35 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: introduce-gfn_to_pfn_memslot --]
[-- Type: text/plain, Size: 2126 bytes --]
Which takes a memslot pointer instead of using kvm->memslots.
To be used by SRCU convertion later.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -272,6 +272,8 @@ void kvm_set_page_dirty(struct page *pag
void 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);
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -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_t
return 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;
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 05/11] KVM: use gfn_to_pfn_memslot in kvm_iommu_map_pages
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
` (3 preceding siblings ...)
2009-12-23 16:35 ` [patch 04/11] KVM: introduce gfn_to_pfn_memslot Marcelo Tosatti
@ 2009-12-23 16:35 ` Marcelo Tosatti
2009-12-23 16:35 ` [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update Marcelo Tosatti
` (6 subsequent siblings)
11 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 16:35 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: pass-memslot-to-kvm_iommu_map_pages --]
[-- Type: text/plain, Size: 2550 bytes --]
So its possible to iommu map a memslot before making it visible to
kvm.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -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,
Index: kvm/virt/kvm/iommu.c
===================================================================
--- kvm.orig/virt/kvm/iommu.c
+++ kvm/virt/kvm/iommu.c
@@ -32,10 +32,10 @@ static int kvm_iommu_unmap_memslots(stru
static 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;
}
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -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
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
` (4 preceding siblings ...)
2009-12-23 16:35 ` [patch 05/11] KVM: use gfn_to_pfn_memslot in kvm_iommu_map_pages Marcelo Tosatti
@ 2009-12-23 16:35 ` Marcelo Tosatti
2009-12-23 16:35 ` [patch 07/11] KVM: use SRCU for dirty log Marcelo Tosatti
` (5 subsequent siblings)
11 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 16:35 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: introduce-srcu-and-use-for-slots --]
[-- Type: text/plain, Size: 15992 bytes --]
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_hva locking.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/include/linux/kvm.h
===================================================================
--- kvm.orig/include/linux/kvm.h
+++ kvm/include/linux/kvm.h
@@ -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 {
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -44,6 +44,7 @@
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/compat.h>
+#include <linux/srcu.h>
#include <asm/processor.h>
#include <asm/io.h>
@@ -213,7 +214,7 @@ static void kvm_mmu_notifier_invalidate_
unsigned long address)
{
struct kvm *kvm = mmu_notifier_to_kvm(mn);
- int need_tlb_flush;
+ int need_tlb_flush, idx;
/*
* When ->invalidate_page runs, the linux pte has been zapped
@@ -233,10 +234,12 @@ static void kvm_mmu_notifier_invalidate_
* pte after kvm_unmap_hva returned, without noticing the page
* is going to be freed.
*/
+ idx = srcu_read_lock(&kvm->srcu);
spin_lock(&kvm->mmu_lock);
kvm->mmu_notifier_seq++;
need_tlb_flush = kvm_unmap_hva(kvm, address);
spin_unlock(&kvm->mmu_lock);
+ srcu_read_unlock(&kvm->srcu, idx);
/* we've to flush the tlb before the pages can be freed */
if (need_tlb_flush)
@@ -250,11 +253,14 @@ static void kvm_mmu_notifier_change_pte(
pte_t pte)
{
struct kvm *kvm = mmu_notifier_to_kvm(mn);
+ int idx;
+ idx = srcu_read_lock(&kvm->srcu);
spin_lock(&kvm->mmu_lock);
kvm->mmu_notifier_seq++;
kvm_set_spte_hva(kvm, address, pte);
spin_unlock(&kvm->mmu_lock);
+ srcu_read_unlock(&kvm->srcu, idx);
}
static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
@@ -263,8 +269,9 @@ static void kvm_mmu_notifier_invalidate_
unsigned long end)
{
struct kvm *kvm = mmu_notifier_to_kvm(mn);
- int need_tlb_flush = 0;
+ int need_tlb_flush = 0, idx;
+ idx = srcu_read_lock(&kvm->srcu);
spin_lock(&kvm->mmu_lock);
/*
* The count increase must become visible at unlock time as no
@@ -275,6 +282,7 @@ static void kvm_mmu_notifier_invalidate_
for (; start < end; start += PAGE_SIZE)
need_tlb_flush |= kvm_unmap_hva(kvm, start);
spin_unlock(&kvm->mmu_lock);
+ srcu_read_unlock(&kvm->srcu, idx);
/* we've to flush the tlb before the pages can be freed */
if (need_tlb_flush)
@@ -312,11 +320,13 @@ static int kvm_mmu_notifier_clear_flush_
unsigned long address)
{
struct kvm *kvm = mmu_notifier_to_kvm(mn);
- int young;
+ int young, idx;
+ idx = srcu_read_lock(&kvm->srcu);
spin_lock(&kvm->mmu_lock);
young = kvm_age_hva(kvm, address);
spin_unlock(&kvm->mmu_lock);
+ srcu_read_unlock(&kvm->srcu, idx);
if (young)
kvm_flush_remote_tlbs(kvm);
@@ -379,11 +389,15 @@ static struct kvm *kvm_create_vm(void)
kvm->memslots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
if (!kvm->memslots)
goto out_err;
+ if (init_srcu_struct(&kvm->srcu))
+ goto out_err;
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- if (!page)
+ if (!page) {
+ cleanup_srcu_struct(&kvm->srcu);
goto out_err;
+ }
kvm->coalesced_mmio_ring =
(struct kvm_coalesced_mmio_ring *)page_address(page);
@@ -391,6 +405,7 @@ static struct kvm *kvm_create_vm(void)
r = kvm_init_mmu_notifier(kvm);
if (r) {
+ cleanup_srcu_struct(&kvm->srcu);
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
put_page(page);
#endif
@@ -481,6 +496,7 @@ static void kvm_destroy_vm(struct kvm *k
kvm_arch_flush_shadow(kvm);
#endif
kvm_arch_destroy_vm(kvm);
+ cleanup_srcu_struct(&kvm->srcu);
hardware_disable_all();
mmdrop(mm);
}
@@ -521,12 +537,13 @@ int __kvm_set_memory_region(struct kvm *
struct kvm_userspace_memory_region *mem,
int user_alloc)
{
- int r;
+ int r, flush_shadow = 0;
gfn_t base_gfn;
unsigned long npages;
unsigned long i;
struct kvm_memory_slot *memslot;
struct kvm_memory_slot old, new;
+ struct kvm_memslots *slots, *old_memslots;
r = -EINVAL;
/* General sanity checks */
@@ -588,15 +605,7 @@ int __kvm_set_memory_region(struct kvm *
memset(new.rmap, 0, npages * sizeof(*new.rmap));
new.user_alloc = user_alloc;
- /*
- * hva_to_rmmap() serialzies with the mmu_lock and to be
- * safe it has to ignore memslots with !user_alloc &&
- * !userspace_addr.
- */
- if (user_alloc)
- new.userspace_addr = mem->userspace_addr;
- else
- new.userspace_addr = 0;
+ new.userspace_addr = mem->userspace_addr;
}
if (!npages)
goto skip_lpage;
@@ -651,8 +660,9 @@ skip_lpage:
if (!new.dirty_bitmap)
goto out_free;
memset(new.dirty_bitmap, 0, dirty_bytes);
+ /* destroy any largepage mappings for dirty tracking */
if (old.npages)
- kvm_arch_flush_shadow(kvm);
+ flush_shadow = 1;
}
#else /* not defined CONFIG_S390 */
new.user_alloc = user_alloc;
@@ -660,34 +670,72 @@ skip_lpage:
new.userspace_addr = mem->userspace_addr;
#endif /* not defined CONFIG_S390 */
- if (!npages)
+ if (!npages) {
+ r = -ENOMEM;
+ slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
+ if (!slots)
+ goto out_free;
+ memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots));
+ if (mem->slot >= slots->nmemslots)
+ slots->nmemslots = mem->slot + 1;
+ slots->memslots[mem->slot].flags |= KVM_MEMSLOT_INVALID;
+
+ old_memslots = kvm->memslots;
+ rcu_assign_pointer(kvm->memslots, slots);
+ synchronize_srcu_expedited(&kvm->srcu);
+ /* From this point no new shadow pages pointing to a deleted
+ * memslot will be created.
+ *
+ * validation of sp->gfn happens in:
+ * - gfn_to_hva (kvm_read_guest, gfn_to_pfn)
+ * - kvm_is_visible_gfn (mmu_check_roots)
+ */
kvm_arch_flush_shadow(kvm);
+ kfree(old_memslots);
+ }
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;
+#ifdef CONFIG_DMAR
+ /* map the pages in iommu page table */
+ if (npages) {
+ r = kvm_iommu_map_pages(kvm, &new);
+ if (r)
+ goto out_free;
+ }
+#endif
- *memslot = new;
- spin_unlock(&kvm->mmu_lock);
+ r = -ENOMEM;
+ slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
+ if (!slots)
+ goto out_free;
+ memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots));
+ if (mem->slot >= slots->nmemslots)
+ slots->nmemslots = mem->slot + 1;
+
+ /* actual memory is freed via old in kvm_free_physmem_slot below */
+ if (!npages) {
+ new.rmap = NULL;
+ new.dirty_bitmap = NULL;
+ for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i)
+ new.lpage_info[i] = NULL;
+ }
+
+ slots->memslots[mem->slot] = new;
+ old_memslots = kvm->memslots;
+ rcu_assign_pointer(kvm->memslots, slots);
+ synchronize_srcu_expedited(&kvm->srcu);
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 */
- spin_lock(&kvm->mmu_lock);
- if (!npages)
- *memslot = old;
- spin_unlock(&kvm->mmu_lock);
-#ifdef CONFIG_DMAR
- /* map the pages in iommu page table */
- r = kvm_iommu_map_pages(kvm, memslot);
- if (r)
- goto out;
-#endif
+ kvm_free_physmem_slot(&old, &new);
+ kfree(old_memslots);
+
+ if (flush_shadow)
+ kvm_arch_flush_shadow(kvm);
+
return 0;
out_free:
@@ -787,7 +835,7 @@ 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;
+ struct kvm_memslots *slots = rcu_dereference(kvm->memslots);
for (i = 0; i < slots->nmemslots; ++i) {
struct kvm_memory_slot *memslot = &slots->memslots[i];
@@ -809,12 +857,15 @@ struct kvm_memory_slot *gfn_to_memslot(s
int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
{
int i;
- struct kvm_memslots *slots = kvm->memslots;
+ struct kvm_memslots *slots = rcu_dereference(kvm->memslots);
gfn = unalias_gfn(kvm, gfn);
for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
struct kvm_memory_slot *memslot = &slots->memslots[i];
+ if (memslot->flags & KVM_MEMSLOT_INVALID)
+ continue;
+
if (gfn >= memslot->base_gfn
&& gfn < memslot->base_gfn + memslot->npages)
return 1;
@@ -823,13 +874,31 @@ int kvm_is_visible_gfn(struct kvm *kvm,
}
EXPORT_SYMBOL_GPL(kvm_is_visible_gfn);
+int memslot_id(struct kvm *kvm, gfn_t gfn)
+{
+ int i;
+ struct kvm_memslots *slots = rcu_dereference(kvm->memslots);
+ struct kvm_memory_slot *memslot = NULL;
+
+ gfn = unalias_gfn(kvm, gfn);
+ for (i = 0; i < slots->nmemslots; ++i) {
+ memslot = &slots->memslots[i];
+
+ if (gfn >= memslot->base_gfn
+ && gfn < memslot->base_gfn + memslot->npages)
+ break;
+ }
+
+ return memslot - slots->memslots;
+}
+
unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
{
struct kvm_memory_slot *slot;
gfn = unalias_gfn(kvm, gfn);
slot = gfn_to_memslot_unaliased(kvm, gfn);
- if (!slot)
+ if (!slot || slot->flags & KVM_MEMSLOT_INVALID)
return bad_hva();
return (slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE);
}
Index: kvm/arch/ia64/kvm/kvm-ia64.c
===================================================================
--- kvm.orig/arch/ia64/kvm/kvm-ia64.c
+++ kvm/arch/ia64/kvm/kvm-ia64.c
@@ -1834,6 +1834,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kv
struct 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;
}
Index: kvm/arch/x86/kvm/mmu.c
===================================================================
--- kvm.orig/arch/x86/kvm/mmu.c
+++ kvm/arch/x86/kvm/mmu.c
@@ -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 *kvm
static 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_pages
int 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_vc
static 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;
}
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
--- kvm.orig/arch/x86/kvm/vmx.c
+++ kvm/arch/x86/kvm/vmx.c
@@ -1503,7 +1503,11 @@ static void enter_pmode(struct kvm_vcpu
static 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;
}
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -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;
Index: kvm/virt/kvm/assigned-dev.c
===================================================================
--- kvm.orig/virt/kvm/assigned-dev.c
+++ kvm/virt/kvm/assigned-dev.c
@@ -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;
}
Index: kvm/virt/kvm/iommu.c
===================================================================
--- kvm.orig/virt/kvm/iommu.c
+++ kvm/virt/kvm/iommu.c
@@ -78,7 +78,7 @@ static int kvm_iommu_map_memslots(struct
int 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(stru
int 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,
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 07/11] KVM: use SRCU for dirty log
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
` (5 preceding siblings ...)
2009-12-23 16:35 ` [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update Marcelo Tosatti
@ 2009-12-23 16:35 ` Marcelo Tosatti
2009-12-23 16:35 ` [patch 08/11] KVM: x86: switch kvm_set_memory_alias to SRCU update Marcelo Tosatti
` (4 subsequent siblings)
11 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 16:35 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: use-srcu-for-dirty-log --]
[-- Type: text/plain, Size: 2025 bytes --]
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -2416,27 +2416,60 @@ static int kvm_vm_ioctl_reinject(struct
int 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;
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 08/11] KVM: x86: switch kvm_set_memory_alias to SRCU update
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
` (6 preceding siblings ...)
2009-12-23 16:35 ` [patch 07/11] KVM: use SRCU for dirty log Marcelo Tosatti
@ 2009-12-23 16:35 ` Marcelo Tosatti
2009-12-23 16:35 ` [patch 09/11] KVM: convert io_bus to SRCU Marcelo Tosatti
` (3 subsequent siblings)
11 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 16:35 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: srcu-alias-update --]
[-- Type: text/plain, Size: 5255 bytes --]
Using a similar two-step procedure as for memslots.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/include/asm/kvm_host.h
===================================================================
--- kvm.orig/arch/x86/include/asm/kvm_host.h
+++ kvm/arch/x86/include/asm/kvm_host.h
@@ -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;
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -38,6 +38,7 @@
#include <linux/intel-iommu.h>
#include <linux/cpufreq.h>
#include <linux/user-return-notifier.h>
+#include <linux/srcu.h>
#include <trace/events/kvm.h>
#undef TRACE_INCLUDE_FILE
#define CREATE_TRACE_POINTS
@@ -2224,11 +2225,32 @@ static int kvm_vm_ioctl_get_nr_mmu_pages
return kvm->arch.n_alloc_mmu_pages;
}
+gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn)
+{
+ int i;
+ struct kvm_mem_alias *alias;
+ struct kvm_mem_aliases *aliases;
+
+ aliases = rcu_dereference(kvm->arch.aliases);
+
+ for (i = 0; i < aliases->naliases; ++i) {
+ alias = &aliases->aliases[i];
+ if (alias->flags & KVM_ALIAS_INVALID)
+ continue;
+ if (gfn >= alias->base_gfn
+ && gfn < alias->base_gfn + alias->npages)
+ return alias->target_gfn + gfn - alias->base_gfn;
+ }
+ return gfn;
+}
+
gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
{
int i;
struct kvm_mem_alias *alias;
- struct kvm_mem_aliases *aliases = kvm->arch.aliases;
+ struct kvm_mem_aliases *aliases;
+
+ aliases = rcu_dereference(kvm->arch.aliases);
for (i = 0; i < aliases->naliases; ++i) {
alias = &aliases->aliases[i];
@@ -2249,7 +2271,7 @@ static int kvm_vm_ioctl_set_memory_alias
{
int r, n;
struct kvm_mem_alias *p;
- struct kvm_mem_aliases *aliases;
+ struct kvm_mem_aliases *aliases, *old_aliases;
r = -EINVAL;
/* General sanity checks */
@@ -2266,28 +2288,48 @@ static int kvm_vm_ioctl_set_memory_alias
< alias->target_phys_addr)
goto out;
+ r = -ENOMEM;
+ aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
+ if (!aliases)
+ goto out;
+
down_write(&kvm->slots_lock);
- spin_lock(&kvm->mmu_lock);
- aliases = kvm->arch.aliases;
+ /* invalidate any gfn reference in case of deletion/shrinking */
+ memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases));
+ aliases->aliases[alias->slot].flags |= KVM_ALIAS_INVALID;
+ old_aliases = kvm->arch.aliases;
+ rcu_assign_pointer(kvm->arch.aliases, aliases);
+ synchronize_srcu_expedited(&kvm->srcu);
+ kvm_mmu_zap_all(kvm);
+ kfree(old_aliases);
+
+ r = -ENOMEM;
+ aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
+ if (!aliases)
+ goto out_unlock;
+
+ memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_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;
+ p->flags &= ~(KVM_ALIAS_INVALID);
for (n = KVM_ALIAS_SLOTS; n > 0; --n)
if (aliases->aliases[n - 1].npages)
break;
aliases->naliases = n;
- spin_unlock(&kvm->mmu_lock);
- kvm_mmu_zap_all(kvm);
+ old_aliases = kvm->arch.aliases;
+ rcu_assign_pointer(kvm->arch.aliases, aliases);
+ synchronize_srcu_expedited(&kvm->srcu);
+ kfree(old_aliases);
+ r = 0;
+out_unlock:
up_write(&kvm->slots_lock);
-
- return 0;
-
out:
return r;
}
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -265,6 +265,8 @@ void kvm_arch_commit_memory_region(struc
void 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
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -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();
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 09/11] KVM: convert io_bus to SRCU
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
` (7 preceding siblings ...)
2009-12-23 16:35 ` [patch 08/11] KVM: x86: switch kvm_set_memory_alias to SRCU update Marcelo Tosatti
@ 2009-12-23 16:35 ` Marcelo Tosatti
2009-12-23 16:35 ` [patch 10/11] KVM: switch vcpu context to use SRCU Marcelo Tosatti
` (2 subsequent siblings)
11 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 16:35 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: srcu-iobus-update --]
[-- Type: text/plain, Size: 14236 bytes --]
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/kvm/i8254.c
===================================================================
--- kvm.orig/arch/x86/kvm/i8254.c
+++ kvm/arch/x86/kvm/i8254.c
@@ -642,13 +642,13 @@ struct kvm_pit *kvm_create_pit(struct kv
kvm_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 kv
return 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)
Index: kvm/arch/x86/kvm/i8259.c
===================================================================
--- kvm.orig/arch/x86/kvm/i8259.c
+++ kvm/arch/x86/kvm/i8259.c
@@ -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;
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -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;
Index: kvm/virt/kvm/eventfd.c
===================================================================
--- kvm.orig/virt/kvm/eventfd.c
+++ kvm/virt/kvm/eventfd.c
@@ -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, st
kvm_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;
Index: kvm/virt/kvm/ioapic.c
===================================================================
--- kvm.orig/virt/kvm/ioapic.c
+++ kvm/virt/kvm/ioapic.c
@@ -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);
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -85,6 +85,8 @@ static long kvm_vcpu_ioctl(struct file *
static int hardware_enable_all(void);
static void hardware_disable_all(void);
+static void kvm_io_bus_destroy(struct kvm_io_bus *bus);
+
static bool kvm_rebooting;
static bool largepages_enabled = true;
@@ -367,7 +369,7 @@ static int kvm_init_mmu_notifier(struct
static struct kvm *kvm_create_vm(void)
{
- int r = 0;
+ int r = 0, i;
struct kvm *kvm = kvm_arch_create_vm();
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
struct page *page;
@@ -391,6 +393,14 @@ static struct kvm *kvm_create_vm(void)
goto out_err;
if (init_srcu_struct(&kvm->srcu))
goto out_err;
+ for (i = 0; i < KVM_NR_BUSES; i++) {
+ kvm->buses[i] = kzalloc(sizeof(struct kvm_io_bus),
+ GFP_KERNEL);
+ if (!kvm->buses[i]) {
+ cleanup_srcu_struct(&kvm->srcu);
+ goto out_err;
+ }
+ }
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
@@ -416,11 +426,9 @@ static struct kvm *kvm_create_vm(void)
atomic_inc(&kvm->mm->mm_count);
spin_lock_init(&kvm->mmu_lock);
spin_lock_init(&kvm->requests_lock);
- kvm_io_bus_init(&kvm->pio_bus);
kvm_eventfd_init(kvm);
mutex_init(&kvm->lock);
mutex_init(&kvm->irq_lock);
- kvm_io_bus_init(&kvm->mmio_bus);
init_rwsem(&kvm->slots_lock);
atomic_set(&kvm->users_count, 1);
spin_lock(&kvm_lock);
@@ -435,6 +443,8 @@ out:
out_err:
hardware_disable_all();
out_err_nodisable:
+ for (i = 0; i < KVM_NR_BUSES; i++)
+ kfree(kvm->buses[i]);
kfree(kvm->memslots);
kfree(kvm);
return ERR_PTR(r);
@@ -480,6 +490,7 @@ void kvm_free_physmem(struct kvm *kvm)
static void kvm_destroy_vm(struct kvm *kvm)
{
+ int i;
struct mm_struct *mm = kvm->mm;
kvm_arch_sync_events(kvm);
@@ -487,8 +498,8 @@ static void kvm_destroy_vm(struct kvm *k
list_del(&kvm->vm_list);
spin_unlock(&kvm_lock);
kvm_free_irq_routing(kvm);
- kvm_io_bus_destroy(&kvm->pio_bus);
- kvm_io_bus_destroy(&kvm->mmio_bus);
+ for (i = 0; i < KVM_NR_BUSES; i++)
+ kvm_io_bus_destroy(kvm->buses[i]);
kvm_coalesced_mmio_free(kvm);
#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm);
@@ -1949,12 +1960,7 @@ static struct notifier_block kvm_reboot_
.priority = 0,
};
-void kvm_io_bus_init(struct kvm_io_bus *bus)
-{
- memset(bus, 0, sizeof(*bus));
-}
-
-void kvm_io_bus_destroy(struct kvm_io_bus *bus)
+static void kvm_io_bus_destroy(struct kvm_io_bus *bus)
{
int i;
@@ -1963,13 +1969,15 @@ void kvm_io_bus_destroy(struct kvm_io_bu
kvm_iodevice_destructor(pos);
}
+ kfree(bus);
}
/* kvm_io_bus_write - called under kvm->slots_lock */
-int kvm_io_bus_write(struct kvm_io_bus *bus, gpa_t addr,
+int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
int len, const void *val)
{
int i;
+ struct kvm_io_bus *bus = rcu_dereference(kvm->buses[bus_idx]);
for (i = 0; i < bus->dev_count; i++)
if (!kvm_iodevice_write(bus->devs[i], addr, len, val))
return 0;
@@ -1977,59 +1985,71 @@ int kvm_io_bus_write(struct kvm_io_bus *
}
/* kvm_io_bus_read - called under kvm->slots_lock */
-int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val)
+int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
+ int len, void *val)
{
int i;
+ struct kvm_io_bus *bus = rcu_dereference(kvm->buses[bus_idx]);
+
for (i = 0; i < bus->dev_count; i++)
if (!kvm_iodevice_read(bus->devs[i], addr, len, val))
return 0;
return -EOPNOTSUPP;
}
-int kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
- struct kvm_io_device *dev)
+/* Caller must have write lock on slots_lock. */
+int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx,
+ struct kvm_io_device *dev)
{
- int ret;
+ struct kvm_io_bus *new_bus, *bus;
- down_write(&kvm->slots_lock);
- ret = __kvm_io_bus_register_dev(bus, dev);
- up_write(&kvm->slots_lock);
-
- return ret;
-}
-
-/* An unlocked version. Caller must have write lock on slots_lock. */
-int __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
- struct kvm_io_device *dev)
-{
+ bus = kvm->buses[bus_idx];
if (bus->dev_count > NR_IOBUS_DEVS-1)
return -ENOSPC;
- bus->devs[bus->dev_count++] = dev;
+ new_bus = kzalloc(sizeof(struct kvm_io_bus), GFP_KERNEL);
+ if (!new_bus)
+ return -ENOMEM;
+ memcpy(new_bus, bus, sizeof(struct kvm_io_bus));
+ new_bus->devs[new_bus->dev_count++] = dev;
+ rcu_assign_pointer(kvm->buses[bus_idx], new_bus);
+ synchronize_srcu_expedited(&kvm->srcu);
+ kfree(bus);
return 0;
}
-void kvm_io_bus_unregister_dev(struct kvm *kvm,
- struct kvm_io_bus *bus,
- struct kvm_io_device *dev)
+/* Caller must have write lock on slots_lock. */
+int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
+ struct kvm_io_device *dev)
{
- down_write(&kvm->slots_lock);
- __kvm_io_bus_unregister_dev(bus, dev);
- up_write(&kvm->slots_lock);
-}
+ int i, r;
+ struct kvm_io_bus *new_bus, *bus;
-/* An unlocked version. Caller must have write lock on slots_lock. */
-void __kvm_io_bus_unregister_dev(struct kvm_io_bus *bus,
- struct kvm_io_device *dev)
-{
- int i;
+ new_bus = kzalloc(sizeof(struct kvm_io_bus), GFP_KERNEL);
+ if (!new_bus)
+ return -ENOMEM;
- for (i = 0; i < bus->dev_count; i++)
- if (bus->devs[i] == dev) {
- bus->devs[i] = bus->devs[--bus->dev_count];
+ bus = kvm->buses[bus_idx];
+ memcpy(new_bus, bus, sizeof(struct kvm_io_bus));
+
+ r = -ENOENT;
+ for (i = 0; i < new_bus->dev_count; i++)
+ if (new_bus->devs[i] == dev) {
+ r = 0;
+ new_bus->devs[i] = new_bus->devs[--new_bus->dev_count];
break;
}
+
+ if (r) {
+ kfree(new_bus);
+ return r;
+ }
+
+ rcu_assign_pointer(kvm->buses[bus_idx], new_bus);
+ synchronize_srcu_expedited(&kvm->srcu);
+ kfree(bus);
+ return r;
}
static struct notifier_block kvm_cpu_notifier = {
Index: kvm/virt/kvm/coalesced_mmio.c
===================================================================
--- kvm.orig/virt/kvm/coalesced_mmio.c
+++ kvm/virt/kvm/coalesced_mmio.c
@@ -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;
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -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 *v
int 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_v
int 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;
Index: kvm/arch/ia64/kvm/kvm-ia64.c
===================================================================
--- kvm.orig/arch/ia64/kvm/kvm-ia64.c
+++ kvm/arch/ia64/kvm/kvm-ia64.c
@@ -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);
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 10/11] KVM: switch vcpu context to use SRCU
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
` (8 preceding siblings ...)
2009-12-23 16:35 ` [patch 09/11] KVM: convert io_bus to SRCU Marcelo Tosatti
@ 2009-12-23 16:35 ` Marcelo Tosatti
2009-12-23 16:35 ` [patch 11/11] KVM: convert slots_lock to a mutex Marcelo Tosatti
2009-12-24 8:30 ` [patch 00/11] convert slotslock to SRCU v2 Avi Kivity
11 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 16:35 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: switch-to-memslot-srcu --]
[-- Type: text/plain, Size: 8330 bytes --]
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -1307,15 +1307,15 @@ static int __msr_io(struct kvm_vcpu *vcp
int (*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_vcpu
static 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_v
kvm_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_v
preempt_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 *v
if (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);
}
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -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;
Index: kvm/arch/x86/kvm/mmu.c
===================================================================
--- kvm.orig/arch/x86/kvm/mmu.c
+++ kvm/arch/x86/kvm/mmu.c
@@ -2935,10 +2935,9 @@ static int mmu_shrink(int nr_to_scan, gf
spin_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);
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
--- kvm.orig/arch/x86/kvm/vmx.c
+++ kvm/arch/x86/kvm/vmx.c
@@ -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;
}
Index: kvm/arch/ia64/kvm/kvm-ia64.c
===================================================================
--- kvm.orig/arch/ia64/kvm/kvm-ia64.c
+++ kvm/arch/ia64/kvm/kvm-ia64.c
@@ -636,12 +636,9 @@ static void kvm_vcpu_post_transition(str
static 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;
}
Index: kvm/arch/s390/kvm/kvm-s390.h
===================================================================
--- kvm.orig/arch/s390/kvm/kvm-s390.h
+++ kvm/arch/s390/kvm/kvm-s390.h
@@ -67,10 +67,14 @@ static inline long kvm_s390_vcpu_get_mem
static 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 */
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch 11/11] KVM: convert slots_lock to a mutex
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
` (9 preceding siblings ...)
2009-12-23 16:35 ` [patch 10/11] KVM: switch vcpu context to use SRCU Marcelo Tosatti
@ 2009-12-23 16:35 ` Marcelo Tosatti
2009-12-24 8:30 ` [patch 00/11] convert slotslock to SRCU v2 Avi Kivity
11 siblings, 0 replies; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-23 16:35 UTC (permalink / raw)
To: kvm; +Cc: avi, Marcelo Tosatti
[-- Attachment #1: convert-slotslock-to-mutex --]
[-- Type: text/plain, Size: 9777 bytes --]
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
--- kvm.orig/arch/x86/kvm/vmx.c
+++ kvm/arch/x86/kvm/vmx.c
@@ -2222,7 +2222,7 @@ static int alloc_apic_access_page(struct
struct 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(stru
struct 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;
}
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -2209,14 +2209,14 @@ static int kvm_vm_ioctl_set_nr_mmu_pages
if (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_alias
if (!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 kv
unsigned 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 *filp
if (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: {
Index: kvm/include/linux/kvm_host.h
===================================================================
--- kvm.orig/include/linux/kvm_host.h
+++ kvm/include/linux/kvm_host.h
@@ -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;
Index: kvm/virt/kvm/coalesced_mmio.c
===================================================================
--- kvm.orig/virt/kvm/coalesced_mmio.c
+++ kvm/virt/kvm/coalesced_mmio.c
@@ -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_mmio
if (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_mm
if (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;
}
Index: kvm/virt/kvm/eventfd.c
===================================================================
--- kvm.orig/virt/kvm/eventfd.c
+++ kvm/virt/kvm/eventfd.c
@@ -496,7 +496,7 @@ kvm_assign_ioeventfd(struct kvm *kvm, st
else
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, st
list_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);
Index: kvm/virt/kvm/ioapic.c
===================================================================
--- kvm.orig/virt/kvm/ioapic.c
+++ kvm/virt/kvm/ioapic.c
@@ -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);
Index: kvm/virt/kvm/kvm_main.c
===================================================================
--- kvm.orig/virt/kvm/kvm_main.c
+++ kvm/virt/kvm/kvm_main.c
@@ -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, enu
return -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)
{
Index: kvm/arch/ia64/kvm/kvm-ia64.c
===================================================================
--- kvm.orig/arch/ia64/kvm/kvm-ia64.c
+++ kvm/arch/ia64/kvm/kvm-ia64.c
@@ -1831,7 +1831,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kv
struct 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;
}
Index: kvm/arch/x86/kvm/i8254.c
===================================================================
--- kvm.orig/arch/x86/kvm/i8254.c
+++ kvm/arch/x86/kvm/i8254.c
@@ -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;
Index: kvm/arch/x86/kvm/i8259.c
===================================================================
--- kvm.orig/arch/x86/kvm/i8259.c
+++ kvm/arch/x86/kvm/i8259.c
@@ -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;
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch 00/11] convert slotslock to SRCU v2
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
` (10 preceding siblings ...)
2009-12-23 16:35 ` [patch 11/11] KVM: convert slots_lock to a mutex Marcelo Tosatti
@ 2009-12-24 8:30 ` Avi Kivity
2009-12-24 14:56 ` Gleb Natapov
11 siblings, 1 reply; 37+ messages in thread
From: Avi Kivity @ 2009-12-24 8:30 UTC (permalink / raw)
To: Marcelo Tosatti; +Cc: kvm
On 12/23/2009 06:35 PM, Marcelo Tosatti wrote:
> Addressing comments.
>
Looks good.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch 00/11] convert slotslock to SRCU v2
2009-12-24 8:30 ` [patch 00/11] convert slotslock to SRCU v2 Avi Kivity
@ 2009-12-24 14:56 ` Gleb Natapov
2009-12-25 7:24 ` Sheng Yang
0 siblings, 1 reply; 37+ messages in thread
From: Gleb Natapov @ 2009-12-24 14:56 UTC (permalink / raw)
To: Avi Kivity; +Cc: Marcelo Tosatti, kvm
On Thu, Dec 24, 2009 at 10:30:24AM +0200, Avi Kivity wrote:
> On 12/23/2009 06:35 PM, Marcelo Tosatti wrote:
> >Addressing comments.
>
> Looks good.
>
>
Looks good to me too.
--
Gleb.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch 00/11] convert slotslock to SRCU v2
2009-12-24 14:56 ` Gleb Natapov
@ 2009-12-25 7:24 ` Sheng Yang
2009-12-25 12:25 ` Marcelo Tosatti
0 siblings, 1 reply; 37+ messages in thread
From: Sheng Yang @ 2009-12-25 7:24 UTC (permalink / raw)
To: kvm; +Cc: Gleb Natapov, Avi Kivity, Marcelo Tosatti
On Thursday 24 December 2009 22:56:38 Gleb Natapov wrote:
> On Thu, Dec 24, 2009 at 10:30:24AM +0200, Avi Kivity wrote:
> > On 12/23/2009 06:35 PM, Marcelo Tosatti wrote:
> > >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...
--
regards
Yang, Sheng
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch 00/11] convert slotslock to SRCU v2
2009-12-25 7:24 ` Sheng Yang
@ 2009-12-25 12:25 ` Marcelo Tosatti
2009-12-25 16:27 ` Avi Kivity
0 siblings, 1 reply; 37+ messages in thread
From: Marcelo Tosatti @ 2009-12-25 12:25 UTC (permalink / raw)
To: Sheng Yang; +Cc: kvm, Gleb Natapov, Avi Kivity
On Fri, Dec 25, 2009 at 03:24:49PM +0800, Sheng Yang wrote:
> On Thursday 24 December 2009 22:56:38 Gleb Natapov wrote:
> > On Thu, Dec 24, 2009 at 10:30:24AM +0200, Avi Kivity wrote:
> > > On 12/23/2009 06:35 PM, Marcelo Tosatti wrote:
> > > >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...
Hi Sheng,
Yes its somewhat confusing but i could not come up with
anything better. Suggestions?
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch 00/11] convert slotslock to SRCU v2
2009-12-25 12:25 ` Marcelo Tosatti
@ 2009-12-25 16:27 ` Avi Kivity
2009-12-25 18:22 ` Sheng Yang
0 siblings, 1 reply; 37+ messages in thread
From: Avi Kivity @ 2009-12-25 16:27 UTC (permalink / raw)
To: Marcelo Tosatti; +Cc: Sheng Yang, kvm, Gleb Natapov
On 12/25/2009 02:25 PM, Marcelo Tosatti wrote:
>
>> 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?
>
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.
--
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch 00/11] convert slotslock to SRCU v2
2009-12-25 16:27 ` Avi Kivity
@ 2009-12-25 18:22 ` Sheng Yang
0 siblings, 0 replies; 37+ messages in thread
From: Sheng Yang @ 2009-12-25 18:22 UTC (permalink / raw)
To: Avi Kivity; +Cc: Marcelo Tosatti, kvm, Gleb Natapov
On Saturday 26 December 2009 00:27:11 Avi Kivity wrote:
> On 12/25/2009 02:25 PM, Marcelo Tosatti wrote:
> >> 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?
>
> 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... :)
--
regards
Yang, Sheng
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch 00/11] convert slotslock to SRCU
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
` (12 preceding siblings ...)
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
@ 2009-12-27 13:16 ` Avi Kivity
13 siblings, 0 replies; 37+ messages in thread
From: Avi Kivity @ 2009-12-27 13:16 UTC (permalink / raw)
To: Marcelo Tosatti; +Cc: kvm
On 12/23/2009 01:38 PM, Marcelo Tosatti wrote:
> Now that synchronize_srcu_expedited is in the tree, we can continue the
> convertion of slots_lock to 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)
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 37+ messages in thread
end of thread, other threads:[~2009-12-27 13:16 UTC | newest]
Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-12-23 11:38 [patch 00/11] convert slotslock to SRCU Marcelo Tosatti
2009-12-23 11:38 ` [patch 01/11] KVM: modify memslots layout in struct kvm Marcelo Tosatti
2009-12-23 11:38 ` [patch 02/11] KVM: modify alias layout in x86s struct kvm_arch Marcelo Tosatti
2009-12-23 11:38 ` [patch 03/11] KVM: split kvm_arch_set_memory_region into prepare and commit Marcelo Tosatti
2009-12-23 11:38 ` [patch 04/11] KVM: introduce gfn_to_pfn_memslot Marcelo Tosatti
2009-12-23 12:09 ` Avi Kivity
2009-12-23 11:38 ` [patch 05/11] KVM: use gfn_to_pfn_memslot in kvm_iommu_map_pages Marcelo Tosatti
2009-12-23 11:38 ` [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update Marcelo Tosatti
2009-12-23 12:32 ` Avi Kivity
2009-12-23 14:19 ` Marcelo Tosatti
2009-12-23 14:33 ` Avi Kivity
2009-12-23 15:13 ` Marcelo Tosatti
2009-12-23 11:38 ` [patch 07/11] KVM: use SRCU for dirty log Marcelo Tosatti
2009-12-23 11:38 ` [patch 08/11] KVM: x86: switch kvm_set_memory_alias to SRCU update Marcelo Tosatti
2009-12-23 11:38 ` [patch 09/11] KVM: convert io_bus to SRCU Marcelo Tosatti
2009-12-23 11:38 ` [patch 10/11] KVM: switch vcpu context to use SRCU Marcelo Tosatti
2009-12-23 11:38 ` [patch 11/11] KVM: convert slots_lock to a mutex Marcelo Tosatti
2009-12-23 12:37 ` [patch 00/11] convert slotslock to SRCU Avi Kivity
2009-12-23 16:35 ` [patch 00/11] convert slotslock to SRCU v2 Marcelo Tosatti
2009-12-23 16:35 ` [patch 01/11] KVM: modify memslots layout in struct kvm Marcelo Tosatti
2009-12-23 16:35 ` [patch 02/11] KVM: modify alias layout in x86s struct kvm_arch Marcelo Tosatti
2009-12-23 16:35 ` [patch 03/11] KVM: split kvm_arch_set_memory_region into prepare and commit Marcelo Tosatti
2009-12-23 16:35 ` [patch 04/11] KVM: introduce gfn_to_pfn_memslot Marcelo Tosatti
2009-12-23 16:35 ` [patch 05/11] KVM: use gfn_to_pfn_memslot in kvm_iommu_map_pages Marcelo Tosatti
2009-12-23 16:35 ` [patch 06/11] KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update Marcelo Tosatti
2009-12-23 16:35 ` [patch 07/11] KVM: use SRCU for dirty log Marcelo Tosatti
2009-12-23 16:35 ` [patch 08/11] KVM: x86: switch kvm_set_memory_alias to SRCU update Marcelo Tosatti
2009-12-23 16:35 ` [patch 09/11] KVM: convert io_bus to SRCU Marcelo Tosatti
2009-12-23 16:35 ` [patch 10/11] KVM: switch vcpu context to use SRCU Marcelo Tosatti
2009-12-23 16:35 ` [patch 11/11] KVM: convert slots_lock to a mutex Marcelo Tosatti
2009-12-24 8:30 ` [patch 00/11] convert slotslock to SRCU v2 Avi Kivity
2009-12-24 14:56 ` Gleb Natapov
2009-12-25 7:24 ` Sheng Yang
2009-12-25 12:25 ` Marcelo Tosatti
2009-12-25 16:27 ` Avi Kivity
2009-12-25 18:22 ` Sheng Yang
2009-12-27 13:16 ` [patch 00/11] convert slotslock to SRCU Avi Kivity
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).