KVM: fix kvm_init() error handling
[safe/jmp/linux-2.6] / virt / kvm / kvm_main.c
index 0edc366..4470251 100644 (file)
@@ -68,7 +68,7 @@ MODULE_LICENSE("GPL");
 /*
  * Ordering of locks:
  *
- *             kvm->lock --> kvm->irq_lock
+ *             kvm->slots_lock --> kvm->lock --> kvm->irq_lock
  */
 
 DEFINE_SPINLOCK(kvm_lock);
@@ -741,8 +741,8 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
        if (alloc_cpumask_var(&cpus, GFP_ATOMIC))
                cpumask_clear(cpus);
 
-       me = get_cpu();
        spin_lock(&kvm->requests_lock);
+       me = smp_processor_id();
        kvm_for_each_vcpu(i, vcpu, kvm) {
                if (test_and_set_bit(req, &vcpu->requests))
                        continue;
@@ -757,7 +757,6 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
        else
                called = false;
        spin_unlock(&kvm->requests_lock);
-       put_cpu();
        free_cpumask_var(cpus);
        return called;
 }
@@ -979,7 +978,7 @@ static struct kvm *kvm_create_vm(void)
        spin_lock_init(&kvm->mmu_lock);
        spin_lock_init(&kvm->requests_lock);
        kvm_io_bus_init(&kvm->pio_bus);
-       kvm_irqfd_init(kvm);
+       kvm_eventfd_init(kvm);
        mutex_init(&kvm->lock);
        mutex_init(&kvm->irq_lock);
        kvm_io_bus_init(&kvm->mmio_bus);
@@ -1666,9 +1665,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
        for (;;) {
                prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE);
 
-               if ((kvm_arch_interrupt_allowed(vcpu) &&
-                                       kvm_cpu_has_interrupt(vcpu)) ||
-                               kvm_arch_vcpu_runnable(vcpu)) {
+               if (kvm_arch_vcpu_runnable(vcpu)) {
                        set_bit(KVM_REQ_UNHALT, &vcpu->requests);
                        break;
                }
@@ -2271,6 +2268,15 @@ static long kvm_vm_ioctl(struct file *filp,
                r = kvm_irqfd(kvm, data.fd, data.gsi, data.flags);
                break;
        }
+       case KVM_IOEVENTFD: {
+               struct kvm_ioeventfd data;
+
+               r = -EFAULT;
+               if (copy_from_user(&data, argp, sizeof data))
+                       goto out;
+               r = kvm_ioeventfd(kvm, &data);
+               break;
+       }
 #ifdef CONFIG_KVM_APIC_ARCHITECTURE
        case KVM_SET_BOOT_CPU_ID:
                r = 0;
@@ -2512,36 +2518,71 @@ void kvm_io_bus_destroy(struct kvm_io_bus *bus)
        }
 }
 
-struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus,
-                                         gpa_t addr, int len, int is_write)
+/* kvm_io_bus_write - called under kvm->slots_lock */
+int kvm_io_bus_write(struct kvm_io_bus *bus, gpa_t addr,
+                    int len, const void *val)
 {
        int i;
+       for (i = 0; i < bus->dev_count; i++)
+               if (!kvm_iodevice_write(bus->devs[i], addr, len, val))
+                       return 0;
+       return -EOPNOTSUPP;
+}
 
-       for (i = 0; i < bus->dev_count; i++) {
-               struct kvm_io_device *pos = bus->devs[i];
-
-               if (kvm_iodevice_in_range(pos, addr, len, is_write))
-                       return pos;
-       }
-
-       return NULL;
+/* kvm_io_bus_read - called under kvm->slots_lock */
+int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val)
+{
+       int i;
+       for (i = 0; i < bus->dev_count; i++)
+               if (!kvm_iodevice_read(bus->devs[i], addr, len, val))
+                       return 0;
+       return -EOPNOTSUPP;
 }
 
-void kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
+int kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
                             struct kvm_io_device *dev)
 {
+       int ret;
+
        down_write(&kvm->slots_lock);
-       __kvm_io_bus_register_dev(bus, dev);
+       ret = __kvm_io_bus_register_dev(bus, dev);
        up_write(&kvm->slots_lock);
+
+       return ret;
 }
 
 /* An unlocked version. Caller must have write lock on slots_lock. */
-void __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
-                            struct kvm_io_device *dev)
+int __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+                             struct kvm_io_device *dev)
 {
-       BUG_ON(bus->dev_count > (NR_IOBUS_DEVS-1));
+       if (bus->dev_count > NR_IOBUS_DEVS-1)
+               return -ENOSPC;
 
        bus->devs[bus->dev_count++] = dev;
+
+       return 0;
+}
+
+void kvm_io_bus_unregister_dev(struct kvm *kvm,
+                              struct kvm_io_bus *bus,
+                              struct kvm_io_device *dev)
+{
+       down_write(&kvm->slots_lock);
+       __kvm_io_bus_unregister_dev(bus, dev);
+       up_write(&kvm->slots_lock);
+}
+
+/* An unlocked version. Caller must have write lock on slots_lock. */
+void __kvm_io_bus_unregister_dev(struct kvm_io_bus *bus,
+                                struct kvm_io_device *dev)
+{
+       int i;
+
+       for (i = 0; i < bus->dev_count; i++)
+               if (bus->devs[i] == dev) {
+                       bus->devs[i] = bus->devs[--bus->dev_count];
+                       break;
+               }
 }
 
 static struct notifier_block kvm_cpu_notifier = {
@@ -2750,8 +2791,8 @@ out_free_0:
        __free_page(bad_page);
 out:
        kvm_arch_exit();
-       kvm_exit_debug();
 out_fail:
+       kvm_exit_debug();
        return r;
 }
 EXPORT_SYMBOL_GPL(kvm_init);