aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2013-04-25 10:11:23 -0400
committerAlexander Graf <agraf@suse.de>2013-04-26 14:27:28 -0400
commit07f0a7bdec5c4039cfb9b836482c45004d4c21cc (patch)
treeea47de6fc439dd8d20d6d1d0c4f9cd21f95c2fcb
parent22e64024fb83065664160d1c28a10aa98cb5f24c (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.c2
-rw-r--r--include/linux/kvm_host.h3
-rw-r--r--virt/kvm/kvm_main.c29
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);
1785out: 1784out:
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;
1069struct kvm_device { 1070struct 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
585static 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
584static void kvm_destroy_vm(struct kvm *kvm) 598static 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
2198void kvm_device_get(struct kvm_device *dev)
2199{
2200 atomic_inc(&dev->users);
2201}
2202
2203void kvm_device_put(struct kvm_device *dev)
2204{
2205 if (atomic_dec_and_test(&dev->users))
2206 dev->ops->destroy(dev);
2207}
2208
2209static int kvm_device_release(struct inode *inode, struct file *filp) 2213static 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;