aboutsummaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2008-12-02 05:17:32 -0500
committerAvi Kivity <avi@redhat.com>2008-12-31 09:55:45 -0500
commit3d3aab1b973b01bd2a1aa46307e94a1380b1d802 (patch)
tree2bb753cd3065eda5d3d7fb2412cc3c58389219f7 /virt
parente3a2a0d4e5ace731e60e2eff4fb7056ecb34adc1 (diff)
KVM: set owner of cpu and vm file operations
There is a race between a "close of the file descriptors" and module unload in the kvm module. You can easily trigger this problem by applying this debug patch: >--- kvm.orig/virt/kvm/kvm_main.c >+++ kvm/virt/kvm/kvm_main.c >@@ -648,10 +648,14 @@ void kvm_free_physmem(struct kvm *kvm) > kvm_free_physmem_slot(&kvm->memslots[i], NULL); > } > >+#include <linux/delay.h> > static void kvm_destroy_vm(struct kvm *kvm) > { > struct mm_struct *mm = kvm->mm; > >+ printk("off1\n"); >+ msleep(5000); >+ printk("off2\n"); > spin_lock(&kvm_lock); > list_del(&kvm->vm_list); > spin_unlock(&kvm_lock); and killing the userspace, followed by an rmmod. The problem is that kvm_destroy_vm can run while the module count is 0. That means, you can remove the module while kvm_destroy_vm is running. But kvm_destroy_vm is part of the module text. This causes a kerneloops. The race exists without the msleep but is much harder to trigger. This patch requires the fix for anon_inodes (anon_inodes: use fops->owner for module refcount). With this patch, we can set the owner of all anonymous KVM inodes file operations. The VFS will then control the KVM module refcount as long as there is an open file. kvm_destroy_vm will be called by the release function of the last closed file - before the VFS drops the module refcount. Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/kvm_main.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index fd9cc79092cb..484c903544f4 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1498,7 +1498,7 @@ static int kvm_vcpu_release(struct inode *inode, struct file *filp)
1498 return 0; 1498 return 0;
1499} 1499}
1500 1500
1501static const struct file_operations kvm_vcpu_fops = { 1501static struct file_operations kvm_vcpu_fops = {
1502 .release = kvm_vcpu_release, 1502 .release = kvm_vcpu_release,
1503 .unlocked_ioctl = kvm_vcpu_ioctl, 1503 .unlocked_ioctl = kvm_vcpu_ioctl,
1504 .compat_ioctl = kvm_vcpu_ioctl, 1504 .compat_ioctl = kvm_vcpu_ioctl,
@@ -1892,7 +1892,7 @@ static int kvm_vm_mmap(struct file *file, struct vm_area_struct *vma)
1892 return 0; 1892 return 0;
1893} 1893}
1894 1894
1895static const struct file_operations kvm_vm_fops = { 1895static struct file_operations kvm_vm_fops = {
1896 .release = kvm_vm_release, 1896 .release = kvm_vm_release,
1897 .unlocked_ioctl = kvm_vm_ioctl, 1897 .unlocked_ioctl = kvm_vm_ioctl,
1898 .compat_ioctl = kvm_vm_ioctl, 1898 .compat_ioctl = kvm_vm_ioctl,
@@ -2256,6 +2256,8 @@ int kvm_init(void *opaque, unsigned int vcpu_size,
2256 } 2256 }
2257 2257
2258 kvm_chardev_ops.owner = module; 2258 kvm_chardev_ops.owner = module;
2259 kvm_vm_fops.owner = module;
2260 kvm_vcpu_fops.owner = module;
2259 2261
2260 r = misc_register(&kvm_dev); 2262 r = misc_register(&kvm_dev);
2261 if (r) { 2263 if (r) {