]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - virt/kvm/kvm_main.c
KVM: Disable pagefaults during copy_from_user_inatomic()
[mv-sheeva.git] / virt / kvm / kvm_main.c
index 3c4fe26096fcd3917db20d8a9ecfa6188496f420..cf6df5167af62fd0f9b89b2e52f10aacab4a181f 100644 (file)
@@ -169,6 +169,7 @@ static struct kvm *kvm_create_vm(void)
        kvm_io_bus_init(&kvm->pio_bus);
        mutex_init(&kvm->lock);
        kvm_io_bus_init(&kvm->mmio_bus);
+       init_rwsem(&kvm->slots_lock);
        spin_lock(&kvm_lock);
        list_add(&kvm->vm_list, &vm_list);
        spin_unlock(&kvm_lock);
@@ -339,9 +340,9 @@ int kvm_set_memory_region(struct kvm *kvm,
 {
        int r;
 
-       down_write(&current->mm->mmap_sem);
+       down_write(&kvm->slots_lock);
        r = __kvm_set_memory_region(kvm, mem, user_alloc);
-       up_write(&current->mm->mmap_sem);
+       up_write(&kvm->slots_lock);
        return r;
 }
 EXPORT_SYMBOL_GPL(kvm_set_memory_region);
@@ -553,7 +554,9 @@ int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data,
        addr = gfn_to_hva(kvm, gfn);
        if (kvm_is_error_hva(addr))
                return -EFAULT;
+       pagefault_disable();
        r = __copy_from_user_inatomic(data, (void __user *)addr + offset, len);
+       pagefault_enable();
        if (r)
                return -EFAULT;
        return 0;
@@ -677,8 +680,10 @@ static int kvm_vcpu_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 
        if (vmf->pgoff == 0)
                page = virt_to_page(vcpu->run);
+#ifdef CONFIG_X86
        else if (vmf->pgoff == KVM_PIO_PAGE_OFFSET)
                page = virt_to_page(vcpu->arch.pio_data);
+#endif
        else
                return VM_FAULT_SIGBUS;
        get_page(page);
@@ -704,7 +709,7 @@ static int kvm_vcpu_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
-static struct file_operations kvm_vcpu_fops = {
+static const struct file_operations kvm_vcpu_fops = {
        .release        = kvm_vcpu_release,
        .unlocked_ioctl = kvm_vcpu_ioctl,
        .compat_ioctl   = kvm_vcpu_ioctl,
@@ -1004,7 +1009,7 @@ static int kvm_vm_mmap(struct file *file, struct vm_area_struct *vma)
        return 0;
 }
 
-static struct file_operations kvm_vm_fops = {
+static const struct file_operations kvm_vm_fops = {
        .release        = kvm_vm_release,
        .unlocked_ioctl = kvm_vm_ioctl,
        .compat_ioctl   = kvm_vm_ioctl,
@@ -1058,7 +1063,10 @@ static long kvm_dev_ioctl(struct file *filp,
                r = -EINVAL;
                if (arg)
                        goto out;
-               r = 2 * PAGE_SIZE;
+               r = PAGE_SIZE;     /* struct kvm_run */
+#ifdef CONFIG_X86
+               r += PAGE_SIZE;    /* pio data page */
+#endif
                break;
        default:
                return kvm_arch_dev_ioctl(filp, ioctl, arg);
@@ -1186,38 +1194,38 @@ static struct notifier_block kvm_cpu_notifier = {
        .priority = 20, /* must be > scheduler priority */
 };
 
-static u64 vm_stat_get(void *_offset)
+static int vm_stat_get(void *_offset, u64 *val)
 {
        unsigned offset = (long)_offset;
-       u64 total = 0;
        struct kvm *kvm;
 
+       *val = 0;
        spin_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list)
-               total += *(u32 *)((void *)kvm + offset);
+               *val += *(u32 *)((void *)kvm + offset);
        spin_unlock(&kvm_lock);
-       return total;
+       return 0;
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(vm_stat_fops, vm_stat_get, NULL, "%llu\n");
 
-static u64 vcpu_stat_get(void *_offset)
+static int vcpu_stat_get(void *_offset, u64 *val)
 {
        unsigned offset = (long)_offset;
-       u64 total = 0;
        struct kvm *kvm;
        struct kvm_vcpu *vcpu;
        int i;
 
+       *val = 0;
        spin_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list)
                for (i = 0; i < KVM_MAX_VCPUS; ++i) {
                        vcpu = kvm->vcpus[i];
                        if (vcpu)
-                               total += *(u32 *)((void *)vcpu + offset);
+                               *val += *(u32 *)((void *)vcpu + offset);
                }
        spin_unlock(&kvm_lock);
-       return total;
+       return 0;
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(vcpu_stat_fops, vcpu_stat_get, NULL, "%llu\n");