diff options
author | Scott Wood <scottwood@freescale.com> | 2013-04-25 10:11:23 -0400 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2013-04-26 14:27:28 -0400 |
commit | 07f0a7bdec5c4039cfb9b836482c45004d4c21cc (patch) | |
tree | ea47de6fc439dd8d20d6d1d0c4f9cd21f95c2fcb | |
parent | 22e64024fb83065664160d1c28a10aa98cb5f24c (diff) |
kvm: destroy emulated devices on VM exit
The hassle of getting refcounting right was greater than the hassle
of keeping a list of devices to destroy on VM exit.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
-rw-r--r-- | arch/powerpc/kvm/mpic.c | 2 | ||||
-rw-r--r-- | include/linux/kvm_host.h | 3 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 29 |
3 files changed, 18 insertions, 16 deletions
diff --git a/arch/powerpc/kvm/mpic.c b/arch/powerpc/kvm/mpic.c index 89fe1d66a7fb..795ca0c9ae69 100644 --- a/arch/powerpc/kvm/mpic.c +++ b/arch/powerpc/kvm/mpic.c | |||
@@ -1781,7 +1781,6 @@ int kvmppc_mpic_connect_vcpu(struct kvm_device *dev, struct kvm_vcpu *vcpu, | |||
1781 | if (opp->mpic_mode_mask == GCR_MODE_PROXY) | 1781 | if (opp->mpic_mode_mask == GCR_MODE_PROXY) |
1782 | vcpu->arch.epr_flags |= KVMPPC_EPR_KERNEL; | 1782 | vcpu->arch.epr_flags |= KVMPPC_EPR_KERNEL; |
1783 | 1783 | ||
1784 | kvm_device_get(dev); | ||
1785 | out: | 1784 | out: |
1786 | spin_unlock_irq(&opp->lock); | 1785 | spin_unlock_irq(&opp->lock); |
1787 | return ret; | 1786 | return ret; |
@@ -1797,7 +1796,6 @@ void kvmppc_mpic_disconnect_vcpu(struct openpic *opp, struct kvm_vcpu *vcpu) | |||
1797 | BUG_ON(!opp->dst[vcpu->arch.irq_cpu_id].vcpu); | 1796 | BUG_ON(!opp->dst[vcpu->arch.irq_cpu_id].vcpu); |
1798 | 1797 | ||
1799 | opp->dst[vcpu->arch.irq_cpu_id].vcpu = NULL; | 1798 | opp->dst[vcpu->arch.irq_cpu_id].vcpu = NULL; |
1800 | kvm_device_put(opp->dev); | ||
1801 | } | 1799 | } |
1802 | 1800 | ||
1803 | /* | 1801 | /* |
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index feffbdaf8986..36c977694741 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -393,6 +393,7 @@ struct kvm { | |||
393 | long mmu_notifier_count; | 393 | long mmu_notifier_count; |
394 | #endif | 394 | #endif |
395 | long tlbs_dirty; | 395 | long tlbs_dirty; |
396 | struct list_head devices; | ||
396 | }; | 397 | }; |
397 | 398 | ||
398 | #define kvm_err(fmt, ...) \ | 399 | #define kvm_err(fmt, ...) \ |
@@ -1069,8 +1070,8 @@ struct kvm_device_ops; | |||
1069 | struct kvm_device { | 1070 | struct kvm_device { |
1070 | struct kvm_device_ops *ops; | 1071 | struct kvm_device_ops *ops; |
1071 | struct kvm *kvm; | 1072 | struct kvm *kvm; |
1072 | atomic_t users; | ||
1073 | void *private; | 1073 | void *private; |
1074 | struct list_head vm_node; | ||
1074 | }; | 1075 | }; |
1075 | 1076 | ||
1076 | /* create, destroy, and name are mandatory */ | 1077 | /* create, destroy, and name are mandatory */ |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index f6cd14d2f0d9..5da9f02a2a67 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -504,6 +504,7 @@ static struct kvm *kvm_create_vm(unsigned long type) | |||
504 | mutex_init(&kvm->irq_lock); | 504 | mutex_init(&kvm->irq_lock); |
505 | mutex_init(&kvm->slots_lock); | 505 | mutex_init(&kvm->slots_lock); |
506 | atomic_set(&kvm->users_count, 1); | 506 | atomic_set(&kvm->users_count, 1); |
507 | INIT_LIST_HEAD(&kvm->devices); | ||
507 | 508 | ||
508 | r = kvm_init_mmu_notifier(kvm); | 509 | r = kvm_init_mmu_notifier(kvm); |
509 | if (r) | 510 | if (r) |
@@ -581,6 +582,19 @@ void kvm_free_physmem(struct kvm *kvm) | |||
581 | kfree(kvm->memslots); | 582 | kfree(kvm->memslots); |
582 | } | 583 | } |
583 | 584 | ||
585 | static void kvm_destroy_devices(struct kvm *kvm) | ||
586 | { | ||
587 | struct list_head *node, *tmp; | ||
588 | |||
589 | list_for_each_safe(node, tmp, &kvm->devices) { | ||
590 | struct kvm_device *dev = | ||
591 | list_entry(node, struct kvm_device, vm_node); | ||
592 | |||
593 | list_del(node); | ||
594 | dev->ops->destroy(dev); | ||
595 | } | ||
596 | } | ||
597 | |||
584 | static void kvm_destroy_vm(struct kvm *kvm) | 598 | static void kvm_destroy_vm(struct kvm *kvm) |
585 | { | 599 | { |
586 | int i; | 600 | int i; |
@@ -600,6 +614,7 @@ static void kvm_destroy_vm(struct kvm *kvm) | |||
600 | kvm_arch_flush_shadow_all(kvm); | 614 | kvm_arch_flush_shadow_all(kvm); |
601 | #endif | 615 | #endif |
602 | kvm_arch_destroy_vm(kvm); | 616 | kvm_arch_destroy_vm(kvm); |
617 | kvm_destroy_devices(kvm); | ||
603 | kvm_free_physmem(kvm); | 618 | kvm_free_physmem(kvm); |
604 | cleanup_srcu_struct(&kvm->srcu); | 619 | cleanup_srcu_struct(&kvm->srcu); |
605 | kvm_arch_free_vm(kvm); | 620 | kvm_arch_free_vm(kvm); |
@@ -2195,23 +2210,11 @@ static long kvm_device_ioctl(struct file *filp, unsigned int ioctl, | |||
2195 | } | 2210 | } |
2196 | } | 2211 | } |
2197 | 2212 | ||
2198 | void kvm_device_get(struct kvm_device *dev) | ||
2199 | { | ||
2200 | atomic_inc(&dev->users); | ||
2201 | } | ||
2202 | |||
2203 | void kvm_device_put(struct kvm_device *dev) | ||
2204 | { | ||
2205 | if (atomic_dec_and_test(&dev->users)) | ||
2206 | dev->ops->destroy(dev); | ||
2207 | } | ||
2208 | |||
2209 | static int kvm_device_release(struct inode *inode, struct file *filp) | 2213 | static int kvm_device_release(struct inode *inode, struct file *filp) |
2210 | { | 2214 | { |
2211 | struct kvm_device *dev = filp->private_data; | 2215 | struct kvm_device *dev = filp->private_data; |
2212 | struct kvm *kvm = dev->kvm; | 2216 | struct kvm *kvm = dev->kvm; |
2213 | 2217 | ||
2214 | kvm_device_put(dev); | ||
2215 | kvm_put_kvm(kvm); | 2218 | kvm_put_kvm(kvm); |
2216 | return 0; | 2219 | return 0; |
2217 | } | 2220 | } |
@@ -2257,7 +2260,6 @@ static int kvm_ioctl_create_device(struct kvm *kvm, | |||
2257 | 2260 | ||
2258 | dev->ops = ops; | 2261 | dev->ops = ops; |
2259 | dev->kvm = kvm; | 2262 | dev->kvm = kvm; |
2260 | atomic_set(&dev->users, 1); | ||
2261 | 2263 | ||
2262 | ret = ops->create(dev, cd->type); | 2264 | ret = ops->create(dev, cd->type); |
2263 | if (ret < 0) { | 2265 | if (ret < 0) { |
@@ -2271,6 +2273,7 @@ static int kvm_ioctl_create_device(struct kvm *kvm, | |||
2271 | return ret; | 2273 | return ret; |
2272 | } | 2274 | } |
2273 | 2275 | ||
2276 | list_add(&dev->vm_node, &kvm->devices); | ||
2274 | kvm_get_kvm(kvm); | 2277 | kvm_get_kvm(kvm); |
2275 | cd->fd = ret; | 2278 | cd->fd = ret; |
2276 | return 0; | 2279 | return 0; |