KVM: Keep slot ID in memory slot structure
[linux-2.6.git] / virt / kvm / kvm_main.c
index f032806..74f7319 100644 (file)
@@ -5,6 +5,7 @@
  * machines without emulation or binary translation.
  *
  * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
  *
  * Authors:
  *   Avi Kivity   <avi@qumranet.com>
@@ -92,6 +93,9 @@ static bool kvm_rebooting;
 
 static bool largepages_enabled = true;
 
+struct page *hwpoison_page;
+pfn_t hwpoison_pfn;
+
 inline int kvm_is_mmio_pfn(pfn_t pfn)
 {
        if (pfn_valid(pfn)) {
@@ -141,7 +145,7 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
        raw_spin_lock(&kvm->requests_lock);
        me = smp_processor_id();
        kvm_for_each_vcpu(i, vcpu, kvm) {
-               if (test_and_set_bit(req, &vcpu->requests))
+               if (kvm_make_check_request(req, vcpu))
                        continue;
                cpu = vcpu->cpu;
                if (cpus != NULL && cpu != -1 && cpu != me)
@@ -566,6 +570,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
 
        new = old = *memslot;
 
+       new.id = mem->slot;
        new.base_gfn = base_gfn;
        new.npages = npages;
        new.flags = mem->flags;
@@ -596,7 +601,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
        /* Allocate if a slot is being created */
 #ifndef CONFIG_S390
        if (npages && !new.rmap) {
-               new.rmap = vmalloc(npages * sizeof(struct page *));
+               new.rmap = vmalloc(npages * sizeof(*new.rmap));
 
                if (!new.rmap)
                        goto out_free;
@@ -810,16 +815,22 @@ EXPORT_SYMBOL_GPL(kvm_disable_largepages);
 
 int is_error_page(struct page *page)
 {
-       return page == bad_page;
+       return page == bad_page || page == hwpoison_page;
 }
 EXPORT_SYMBOL_GPL(is_error_page);
 
 int is_error_pfn(pfn_t pfn)
 {
-       return pfn == bad_pfn;
+       return pfn == bad_pfn || pfn == hwpoison_pfn;
 }
 EXPORT_SYMBOL_GPL(is_error_pfn);
 
+int is_hwpoison_pfn(pfn_t pfn)
+{
+       return pfn == hwpoison_pfn;
+}
+EXPORT_SYMBOL_GPL(is_hwpoison_pfn);
+
 static inline unsigned long bad_hva(void)
 {
        return PAGE_OFFSET;
@@ -831,7 +842,7 @@ int kvm_is_error_hva(unsigned long addr)
 }
 EXPORT_SYMBOL_GPL(kvm_is_error_hva);
 
-struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn)
+struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
 {
        int i;
        struct kvm_memslots *slots = kvm_memslots(kvm);
@@ -845,20 +856,13 @@ struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn)
        }
        return NULL;
 }
-EXPORT_SYMBOL_GPL(gfn_to_memslot_unaliased);
-
-struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
-{
-       gfn = unalias_gfn(kvm, gfn);
-       return gfn_to_memslot_unaliased(kvm, gfn);
-}
+EXPORT_SYMBOL_GPL(gfn_to_memslot);
 
 int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
 {
        int i;
        struct kvm_memslots *slots = kvm_memslots(kvm);
 
-       gfn = unalias_gfn_instantiation(kvm, gfn);
        for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
                struct kvm_memory_slot *memslot = &slots->memslots[i];
 
@@ -903,7 +907,6 @@ int memslot_id(struct kvm *kvm, gfn_t gfn)
        struct kvm_memslots *slots = kvm_memslots(kvm);
        struct kvm_memory_slot *memslot = NULL;
 
-       gfn = unalias_gfn(kvm, gfn);
        for (i = 0; i < slots->nmemslots; ++i) {
                memslot = &slots->memslots[i];
 
@@ -924,8 +927,7 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
 {
        struct kvm_memory_slot *slot;
 
-       gfn = unalias_gfn_instantiation(kvm, gfn);
-       slot = gfn_to_memslot_unaliased(kvm, gfn);
+       slot = gfn_to_memslot(kvm, gfn);
        if (!slot || slot->flags & KVM_MEMSLOT_INVALID)
                return bad_hva();
        return gfn_to_hva_memslot(slot, gfn);
@@ -945,6 +947,11 @@ static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr)
        if (unlikely(npages != 1)) {
                struct vm_area_struct *vma;
 
+               if (is_hwpoison_address(addr)) {
+                       get_page(hwpoison_page);
+                       return page_to_pfn(hwpoison_page);
+               }
+
                down_read(&current->mm->mmap_sem);
                vma = find_vma(current->mm, addr);
 
@@ -1187,8 +1194,7 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
 {
        struct kvm_memory_slot *memslot;
 
-       gfn = unalias_gfn(kvm, gfn);
-       memslot = gfn_to_memslot_unaliased(kvm, gfn);
+       memslot = gfn_to_memslot(kvm, gfn);
        if (memslot && memslot->dirty_bitmap) {
                unsigned long rel_gfn = gfn - memslot->base_gfn;
 
@@ -1207,7 +1213,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
                prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE);
 
                if (kvm_arch_vcpu_runnable(vcpu)) {
-                       set_bit(KVM_REQ_UNHALT, &vcpu->requests);
+                       kvm_make_request(KVM_REQ_UNHALT, vcpu);
                        break;
                }
                if (kvm_cpu_has_pending_timer(vcpu))
@@ -1378,6 +1384,18 @@ static long kvm_vcpu_ioctl(struct file *filp,
 
        if (vcpu->kvm->mm != current->mm)
                return -EIO;
+
+#if defined(CONFIG_S390) || defined(CONFIG_PPC)
+       /*
+        * Special cases: vcpu ioctls that are asynchronous to vcpu execution,
+        * so vcpu_load() would break it.
+        */
+       if (ioctl == KVM_S390_INTERRUPT || ioctl == KVM_INTERRUPT)
+               return kvm_arch_vcpu_ioctl(filp, ioctl, arg);
+#endif
+
+
+       vcpu_load(vcpu);
        switch (ioctl) {
        case KVM_RUN:
                r = -EINVAL;
@@ -1520,7 +1538,7 @@ out_free2:
                                goto out;
                        p = &sigset;
                }
-               r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset);
+               r = kvm_vcpu_ioctl_set_sigmask(vcpu, p);
                break;
        }
        case KVM_GET_FPU: {
@@ -1555,6 +1573,7 @@ out_free2:
                r = kvm_arch_vcpu_ioctl(filp, ioctl, arg);
        }
 out:
+       vcpu_put(vcpu);
        kfree(fpu);
        kfree(kvm_sregs);
        return r;
@@ -2197,6 +2216,15 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
 
        bad_pfn = page_to_pfn(bad_page);
 
+       hwpoison_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+
+       if (hwpoison_page == NULL) {
+               r = -ENOMEM;
+               goto out_free_0;
+       }
+
+       hwpoison_pfn = page_to_pfn(hwpoison_page);
+
        if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) {
                r = -ENOMEM;
                goto out_free_0;
@@ -2269,6 +2297,8 @@ out_free_1:
 out_free_0a:
        free_cpumask_var(cpus_hardware_enabled);
 out_free_0:
+       if (hwpoison_page)
+               __free_page(hwpoison_page);
        __free_page(bad_page);
 out:
        kvm_arch_exit();
@@ -2290,6 +2320,7 @@ void kvm_exit(void)
        kvm_arch_hardware_unsetup();
        kvm_arch_exit();
        free_cpumask_var(cpus_hardware_enabled);
+       __free_page(hwpoison_page);
        __free_page(bad_page);
 }
 EXPORT_SYMBOL_GPL(kvm_exit);