nfsd4: fix null dereference creating nfsv4 callback client
[safe/jmp/linux-2.6] / virt / kvm / kvm_main.c
index 63d5fa2..2884baf 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/mman.h>
 #include <linux/swap.h>
 #include <linux/bitops.h>
+#include <linux/spinlock.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -130,6 +131,7 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
         * finer-grained lock, update this
         */
        mutex_lock(&kvm->lock);
+       spin_lock_irq(&assigned_dev->assigned_dev_lock);
        if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
                struct kvm_guest_msix_entry *guest_entries =
                        assigned_dev->guest_msix_entries;
@@ -156,18 +158,21 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
                }
        }
 
+       spin_unlock_irq(&assigned_dev->assigned_dev_lock);
        mutex_unlock(&assigned_dev->kvm->lock);
 }
 
 static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
 {
+       unsigned long flags;
        struct kvm_assigned_dev_kernel *assigned_dev =
                (struct kvm_assigned_dev_kernel *) dev_id;
 
+       spin_lock_irqsave(&assigned_dev->assigned_dev_lock, flags);
        if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
                int index = find_index_from_host_irq(assigned_dev, irq);
                if (index < 0)
-                       return IRQ_HANDLED;
+                       goto out;
                assigned_dev->guest_msix_entries[index].flags |=
                        KVM_ASSIGNED_MSIX_PENDING;
        }
@@ -177,6 +182,8 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
        disable_irq_nosync(irq);
        assigned_dev->host_irq_disabled = true;
 
+out:
+       spin_unlock_irqrestore(&assigned_dev->assigned_dev_lock, flags);
        return IRQ_HANDLED;
 }
 
@@ -184,6 +191,7 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
 static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
 {
        struct kvm_assigned_dev_kernel *dev;
+       unsigned long flags;
 
        if (kian->gsi == -1)
                return;
@@ -196,10 +204,12 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
        /* The guest irq may be shared so this ack may be
         * from another device.
         */
+       spin_lock_irqsave(&dev->assigned_dev_lock, flags);
        if (dev->host_irq_disabled) {
                enable_irq(dev->host_irq);
                dev->host_irq_disabled = false;
        }
+       spin_unlock_irqrestore(&dev->assigned_dev_lock, flags);
 }
 
 static void deassign_guest_irq(struct kvm *kvm,
@@ -615,6 +625,7 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
        match->host_devfn = assigned_dev->devfn;
        match->flags = assigned_dev->flags;
        match->dev = dev;
+       spin_lock_init(&match->assigned_dev_lock);
        match->irq_source_id = -1;
        match->kvm = kvm;
        match->ack_notifier.irq_acked = kvm_assigned_dev_ack_irq;
@@ -735,6 +746,7 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
                cpumask_clear(cpus);
 
        me = get_cpu();
+       spin_lock(&kvm->requests_lock);
        for (i = 0; i < KVM_MAX_VCPUS; ++i) {
                vcpu = kvm->vcpus[i];
                if (!vcpu)
@@ -751,6 +763,7 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
                smp_call_function_many(cpus, ack_flush, NULL, 1);
        else
                called = false;
+       spin_unlock(&kvm->requests_lock);
        put_cpu();
        free_cpumask_var(cpus);
        return called;
@@ -971,6 +984,7 @@ static struct kvm *kvm_create_vm(void)
        kvm->mm = current->mm;
        atomic_inc(&kvm->mm->mm_count);
        spin_lock_init(&kvm->mmu_lock);
+       spin_lock_init(&kvm->requests_lock);
        kvm_io_bus_init(&kvm->pio_bus);
        mutex_init(&kvm->lock);
        kvm_io_bus_init(&kvm->mmio_bus);
@@ -1075,9 +1089,8 @@ int __kvm_set_memory_region(struct kvm *kvm,
 {
        int r;
        gfn_t base_gfn;
-       unsigned long npages;
-       int largepages;
-       unsigned long i;
+       unsigned long npages, ugfn;
+       unsigned long largepages, i;
        struct kvm_memory_slot *memslot;
        struct kvm_memory_slot old, new;
 
@@ -1166,6 +1179,14 @@ int __kvm_set_memory_region(struct kvm *kvm,
                        new.lpage_info[0].write_count = 1;
                if ((base_gfn+npages) % KVM_PAGES_PER_HPAGE)
                        new.lpage_info[largepages-1].write_count = 1;
+               ugfn = new.userspace_addr >> PAGE_SHIFT;
+               /*
+                * If the gfn and userspace address are not aligned wrt each
+                * other, disable large page support for this slot
+                */
+               if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE - 1))
+                       for (i = 0; i < largepages; ++i)
+                               new.lpage_info[i].write_count = 1;
        }
 
        /* Allocate page dirty bitmap if needed */
@@ -1176,6 +1197,8 @@ int __kvm_set_memory_region(struct kvm *kvm,
                if (!new.dirty_bitmap)
                        goto out_free;
                memset(new.dirty_bitmap, 0, dirty_bytes);
+               if (old.npages)
+                       kvm_arch_flush_shadow(kvm);
        }
 #endif /* not defined CONFIG_S390 */
 
@@ -1199,8 +1222,10 @@ int __kvm_set_memory_region(struct kvm *kvm,
 
        kvm_free_physmem_slot(&old, npages ? &new : NULL);
        /* Slot deletion case: we have to update the current slot */
+       spin_lock(&kvm->mmu_lock);
        if (!npages)
                *memslot = old;
+       spin_unlock(&kvm->mmu_lock);
 #ifdef CONFIG_DMAR
        /* map the pages in iommu page table */
        r = kvm_iommu_map_pages(kvm, base_gfn, npages);
@@ -2391,15 +2416,15 @@ EXPORT_SYMBOL_GPL(kvm_handle_fault_on_reboot);
 static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
                      void *v)
 {
-       if (val == SYS_RESTART) {
-               /*
-                * Some (well, at least mine) BIOSes hang on reboot if
-                * in vmx root mode.
-                */
-               printk(KERN_INFO "kvm: exiting hardware virtualization\n");
-               kvm_rebooting = true;
-               on_each_cpu(hardware_disable, NULL, 1);
-       }
+       /*
+        * Some (well, at least mine) BIOSes hang on reboot if
+        * in vmx root mode.
+        *
+        * And Intel TXT required VMX off for all cpu when system shutdown.
+        */
+       printk(KERN_INFO "kvm: exiting hardware virtualization\n");
+       kvm_rebooting = true;
+       on_each_cpu(hardware_disable, NULL, 1);
        return NOTIFY_OK;
 }
 
@@ -2584,7 +2609,6 @@ int kvm_init(void *opaque, unsigned int vcpu_size,
                r = -ENOMEM;
                goto out_free_0;
        }
-       cpumask_clear(cpus_hardware_enabled);
 
        r = kvm_arch_hardware_setup();
        if (r < 0)