printk_ratelimit() functions should use CONFIG_PRINTK
[linux-3.10.git] / virt / kvm / kvm_main.c
index 4026d7d..32fbf80 100644 (file)
@@ -165,6 +165,7 @@ static struct kvm *kvm_create_vm(void)
 
        kvm->mm = current->mm;
        atomic_inc(&kvm->mm->mm_count);
+       spin_lock_init(&kvm->mmu_lock);
        kvm_io_bus_init(&kvm->pio_bus);
        mutex_init(&kvm->lock);
        kvm_io_bus_init(&kvm->mmio_bus);
@@ -227,7 +228,7 @@ static int kvm_vm_release(struct inode *inode, struct file *filp)
  *
  * Discontiguous memory is allowed, mostly for framebuffers.
  *
- * Must be called holding kvm->lock.
+ * Must be called holding mmap_sem for write.
  */
 int __kvm_set_memory_region(struct kvm *kvm,
                            struct kvm_userspace_memory_region *mem,
@@ -338,9 +339,9 @@ int kvm_set_memory_region(struct kvm *kvm,
 {
        int r;
 
-       mutex_lock(&kvm->lock);
+       down_write(&current->mm->mmap_sem);
        r = __kvm_set_memory_region(kvm, mem, user_alloc);
-       mutex_unlock(&kvm->lock);
+       up_write(&current->mm->mmap_sem);
        return r;
 }
 EXPORT_SYMBOL_GPL(kvm_set_memory_region);
@@ -456,7 +457,7 @@ static unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
 /*
  * Requires current->mm->mmap_sem to be held
  */
-static struct page *__gfn_to_page(struct kvm *kvm, gfn_t gfn)
+struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
 {
        struct page *page[1];
        unsigned long addr;
@@ -481,17 +482,6 @@ static struct page *__gfn_to_page(struct kvm *kvm, gfn_t gfn)
        return page[0];
 }
 
-struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
-{
-       struct page *page;
-
-       down_read(&current->mm->mmap_sem);
-       page = __gfn_to_page(kvm, gfn);
-       up_read(&current->mm->mmap_sem);
-
-       return page;
-}
-
 EXPORT_SYMBOL_GPL(gfn_to_page);
 
 void kvm_release_page_clean(struct page *page)
@@ -552,6 +542,24 @@ int kvm_read_guest(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len)
 }
 EXPORT_SYMBOL_GPL(kvm_read_guest);
 
+int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data,
+                         unsigned long len)
+{
+       int r;
+       unsigned long addr;
+       gfn_t gfn = gpa >> PAGE_SHIFT;
+       int offset = offset_in_page(gpa);
+
+       addr = gfn_to_hva(kvm, gfn);
+       if (kvm_is_error_hva(addr))
+               return -EFAULT;
+       r = __copy_from_user_inatomic(data, (void __user *)addr + offset, len);
+       if (r)
+               return -EFAULT;
+       return 0;
+}
+EXPORT_SYMBOL(kvm_read_guest_atomic);
+
 int kvm_write_guest_page(struct kvm *kvm, gfn_t gfn, const void *data,
                         int offset, int len)
 {
@@ -977,8 +985,7 @@ static int kvm_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 
        if (!kvm_is_visible_gfn(kvm, vmf->pgoff))
                return VM_FAULT_SIGBUS;
-       /* current->mm->mmap_sem is already held so call lockless version */
-       page = __gfn_to_page(kvm, vmf->pgoff);
+       page = gfn_to_page(kvm, vmf->pgoff);
        if (is_error_page(page)) {
                kvm_release_page_clean(page);
                return VM_FAULT_SIGBUS;
@@ -1179,38 +1186,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");