diff options
| author | Marcelo Tosatti <mtosatti@redhat.com> | 2009-06-04 14:08:24 -0400 |
|---|---|---|
| committer | Avi Kivity <avi@redhat.com> | 2009-09-10 01:32:49 -0400 |
| commit | fa40a8214bb9bcae8d49c234c19d8b4a6c1f37ff (patch) | |
| tree | 6449f27072f128a1c39faaaeef1787f754345aaf | |
| parent | 60eead79ad8750f80384cbe48fc44edcc78a0305 (diff) | |
KVM: switch irq injection/acking data structures to irq_lock
Protect irq injection/acking data structures with a separate irq_lock
mutex. This fixes the following deadlock:
CPU A CPU B
kvm_vm_ioctl_deassign_dev_irq()
mutex_lock(&kvm->lock); worker_thread()
-> kvm_deassign_irq() -> kvm_assigned_dev_interrupt_work_handler()
-> deassign_host_irq() mutex_lock(&kvm->lock);
-> cancel_work_sync() [blocked]
[gleb: fix ia64 path]
Reported-by: Alex Williamson <alex.williamson@hp.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
| -rw-r--r-- | arch/ia64/kvm/kvm-ia64.c | 4 | ||||
| -rw-r--r-- | arch/x86/kvm/i8254.c | 4 | ||||
| -rw-r--r-- | arch/x86/kvm/lapic.c | 4 | ||||
| -rw-r--r-- | arch/x86/kvm/x86.c | 19 | ||||
| -rw-r--r-- | include/linux/kvm_host.h | 3 | ||||
| -rw-r--r-- | virt/kvm/eventfd.c | 4 | ||||
| -rw-r--r-- | virt/kvm/irq_comm.c | 34 | ||||
| -rw-r--r-- | virt/kvm/kvm_main.c | 16 |
8 files changed, 58 insertions, 30 deletions
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index 319922137fdd..8dde36953af3 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c | |||
| @@ -1000,10 +1000,10 @@ long kvm_arch_vm_ioctl(struct file *filp, | |||
| 1000 | goto out; | 1000 | goto out; |
| 1001 | if (irqchip_in_kernel(kvm)) { | 1001 | if (irqchip_in_kernel(kvm)) { |
| 1002 | __s32 status; | 1002 | __s32 status; |
| 1003 | mutex_lock(&kvm->lock); | 1003 | mutex_lock(&kvm->irq_lock); |
| 1004 | status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, | 1004 | status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, |
| 1005 | irq_event.irq, irq_event.level); | 1005 | irq_event.irq, irq_event.level); |
| 1006 | mutex_unlock(&kvm->lock); | 1006 | mutex_unlock(&kvm->irq_lock); |
| 1007 | if (ioctl == KVM_IRQ_LINE_STATUS) { | 1007 | if (ioctl == KVM_IRQ_LINE_STATUS) { |
| 1008 | irq_event.status = status; | 1008 | irq_event.status = status; |
| 1009 | if (copy_to_user(argp, &irq_event, | 1009 | if (copy_to_user(argp, &irq_event, |
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 977af7ab8193..3837db65d33e 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c | |||
| @@ -654,10 +654,10 @@ static void __inject_pit_timer_intr(struct kvm *kvm) | |||
| 654 | struct kvm_vcpu *vcpu; | 654 | struct kvm_vcpu *vcpu; |
| 655 | int i; | 655 | int i; |
| 656 | 656 | ||
| 657 | mutex_lock(&kvm->lock); | 657 | mutex_lock(&kvm->irq_lock); |
| 658 | kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1); | 658 | kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1); |
| 659 | kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0); | 659 | kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0); |
| 660 | mutex_unlock(&kvm->lock); | 660 | mutex_unlock(&kvm->irq_lock); |
| 661 | 661 | ||
| 662 | /* | 662 | /* |
| 663 | * Provides NMI watchdog support via Virtual Wire mode. | 663 | * Provides NMI watchdog support via Virtual Wire mode. |
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index a23f42e550af..44f20cdb5709 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
| @@ -424,7 +424,9 @@ static void apic_set_eoi(struct kvm_lapic *apic) | |||
| 424 | trigger_mode = IOAPIC_LEVEL_TRIG; | 424 | trigger_mode = IOAPIC_LEVEL_TRIG; |
| 425 | else | 425 | else |
| 426 | trigger_mode = IOAPIC_EDGE_TRIG; | 426 | trigger_mode = IOAPIC_EDGE_TRIG; |
| 427 | mutex_lock(&apic->vcpu->kvm->irq_lock); | ||
| 427 | kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode); | 428 | kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode); |
| 429 | mutex_unlock(&apic->vcpu->kvm->irq_lock); | ||
| 428 | } | 430 | } |
| 429 | 431 | ||
| 430 | static void apic_send_ipi(struct kvm_lapic *apic) | 432 | static void apic_send_ipi(struct kvm_lapic *apic) |
| @@ -448,7 +450,9 @@ static void apic_send_ipi(struct kvm_lapic *apic) | |||
| 448 | irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode, | 450 | irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode, |
| 449 | irq.vector); | 451 | irq.vector); |
| 450 | 452 | ||
| 453 | mutex_lock(&apic->vcpu->kvm->irq_lock); | ||
| 451 | kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq); | 454 | kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq); |
| 455 | mutex_unlock(&apic->vcpu->kvm->irq_lock); | ||
| 452 | } | 456 | } |
| 453 | 457 | ||
| 454 | static u32 apic_get_tmcct(struct kvm_lapic *apic) | 458 | static u32 apic_get_tmcct(struct kvm_lapic *apic) |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2ad8c97f58cc..05cbe83c74e2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
| @@ -2136,10 +2136,10 @@ long kvm_arch_vm_ioctl(struct file *filp, | |||
| 2136 | goto out; | 2136 | goto out; |
| 2137 | if (irqchip_in_kernel(kvm)) { | 2137 | if (irqchip_in_kernel(kvm)) { |
| 2138 | __s32 status; | 2138 | __s32 status; |
| 2139 | mutex_lock(&kvm->lock); | 2139 | mutex_lock(&kvm->irq_lock); |
| 2140 | status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, | 2140 | status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, |
| 2141 | irq_event.irq, irq_event.level); | 2141 | irq_event.irq, irq_event.level); |
| 2142 | mutex_unlock(&kvm->lock); | 2142 | mutex_unlock(&kvm->irq_lock); |
| 2143 | if (ioctl == KVM_IRQ_LINE_STATUS) { | 2143 | if (ioctl == KVM_IRQ_LINE_STATUS) { |
| 2144 | irq_event.status = status; | 2144 | irq_event.status = status; |
| 2145 | if (copy_to_user(argp, &irq_event, | 2145 | if (copy_to_user(argp, &irq_event, |
| @@ -2385,12 +2385,11 @@ mmio: | |||
| 2385 | */ | 2385 | */ |
| 2386 | mutex_lock(&vcpu->kvm->lock); | 2386 | mutex_lock(&vcpu->kvm->lock); |
| 2387 | mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 0); | 2387 | mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 0); |
| 2388 | mutex_unlock(&vcpu->kvm->lock); | ||
| 2388 | if (mmio_dev) { | 2389 | if (mmio_dev) { |
| 2389 | kvm_iodevice_read(mmio_dev, gpa, bytes, val); | 2390 | kvm_iodevice_read(mmio_dev, gpa, bytes, val); |
| 2390 | mutex_unlock(&vcpu->kvm->lock); | ||
| 2391 | return X86EMUL_CONTINUE; | 2391 | return X86EMUL_CONTINUE; |
| 2392 | } | 2392 | } |
| 2393 | mutex_unlock(&vcpu->kvm->lock); | ||
| 2394 | 2393 | ||
| 2395 | vcpu->mmio_needed = 1; | 2394 | vcpu->mmio_needed = 1; |
| 2396 | vcpu->mmio_phys_addr = gpa; | 2395 | vcpu->mmio_phys_addr = gpa; |
| @@ -2440,12 +2439,11 @@ mmio: | |||
| 2440 | */ | 2439 | */ |
| 2441 | mutex_lock(&vcpu->kvm->lock); | 2440 | mutex_lock(&vcpu->kvm->lock); |
| 2442 | mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 1); | 2441 | mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 1); |
| 2442 | mutex_unlock(&vcpu->kvm->lock); | ||
| 2443 | if (mmio_dev) { | 2443 | if (mmio_dev) { |
| 2444 | kvm_iodevice_write(mmio_dev, gpa, bytes, val); | 2444 | kvm_iodevice_write(mmio_dev, gpa, bytes, val); |
| 2445 | mutex_unlock(&vcpu->kvm->lock); | ||
| 2446 | return X86EMUL_CONTINUE; | 2445 | return X86EMUL_CONTINUE; |
| 2447 | } | 2446 | } |
| 2448 | mutex_unlock(&vcpu->kvm->lock); | ||
| 2449 | 2447 | ||
| 2450 | vcpu->mmio_needed = 1; | 2448 | vcpu->mmio_needed = 1; |
| 2451 | vcpu->mmio_phys_addr = gpa; | 2449 | vcpu->mmio_phys_addr = gpa; |
| @@ -2768,7 +2766,6 @@ static void kernel_pio(struct kvm_io_device *pio_dev, | |||
| 2768 | { | 2766 | { |
| 2769 | /* TODO: String I/O for in kernel device */ | 2767 | /* TODO: String I/O for in kernel device */ |
| 2770 | 2768 | ||
| 2771 | mutex_lock(&vcpu->kvm->lock); | ||
| 2772 | if (vcpu->arch.pio.in) | 2769 | if (vcpu->arch.pio.in) |
| 2773 | kvm_iodevice_read(pio_dev, vcpu->arch.pio.port, | 2770 | kvm_iodevice_read(pio_dev, vcpu->arch.pio.port, |
| 2774 | vcpu->arch.pio.size, | 2771 | vcpu->arch.pio.size, |
| @@ -2777,7 +2774,6 @@ static void kernel_pio(struct kvm_io_device *pio_dev, | |||
| 2777 | kvm_iodevice_write(pio_dev, vcpu->arch.pio.port, | 2774 | kvm_iodevice_write(pio_dev, vcpu->arch.pio.port, |
| 2778 | vcpu->arch.pio.size, | 2775 | vcpu->arch.pio.size, |
| 2779 | pd); | 2776 | pd); |
| 2780 | mutex_unlock(&vcpu->kvm->lock); | ||
| 2781 | } | 2777 | } |
| 2782 | 2778 | ||
| 2783 | static void pio_string_write(struct kvm_io_device *pio_dev, | 2779 | static void pio_string_write(struct kvm_io_device *pio_dev, |
| @@ -2787,14 +2783,12 @@ static void pio_string_write(struct kvm_io_device *pio_dev, | |||
| 2787 | void *pd = vcpu->arch.pio_data; | 2783 | void *pd = vcpu->arch.pio_data; |
| 2788 | int i; | 2784 | int i; |
| 2789 | 2785 | ||
| 2790 | mutex_lock(&vcpu->kvm->lock); | ||
| 2791 | for (i = 0; i < io->cur_count; i++) { | 2786 | for (i = 0; i < io->cur_count; i++) { |
| 2792 | kvm_iodevice_write(pio_dev, io->port, | 2787 | kvm_iodevice_write(pio_dev, io->port, |
| 2793 | io->size, | 2788 | io->size, |
| 2794 | pd); | 2789 | pd); |
| 2795 | pd += io->size; | 2790 | pd += io->size; |
| 2796 | } | 2791 | } |
| 2797 | mutex_unlock(&vcpu->kvm->lock); | ||
| 2798 | } | 2792 | } |
| 2799 | 2793 | ||
| 2800 | static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, | 2794 | static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, |
| @@ -2831,7 +2825,9 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
| 2831 | val = kvm_register_read(vcpu, VCPU_REGS_RAX); | 2825 | val = kvm_register_read(vcpu, VCPU_REGS_RAX); |
| 2832 | memcpy(vcpu->arch.pio_data, &val, 4); | 2826 | memcpy(vcpu->arch.pio_data, &val, 4); |
| 2833 | 2827 | ||
| 2828 | mutex_lock(&vcpu->kvm->lock); | ||
| 2834 | pio_dev = vcpu_find_pio_dev(vcpu, port, size, !in); | 2829 | pio_dev = vcpu_find_pio_dev(vcpu, port, size, !in); |
| 2830 | mutex_unlock(&vcpu->kvm->lock); | ||
| 2835 | if (pio_dev) { | 2831 | if (pio_dev) { |
| 2836 | kernel_pio(pio_dev, vcpu, vcpu->arch.pio_data); | 2832 | kernel_pio(pio_dev, vcpu, vcpu->arch.pio_data); |
| 2837 | complete_pio(vcpu); | 2833 | complete_pio(vcpu); |
| @@ -2895,9 +2891,12 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
| 2895 | 2891 | ||
| 2896 | vcpu->arch.pio.guest_gva = address; | 2892 | vcpu->arch.pio.guest_gva = address; |
| 2897 | 2893 | ||
| 2894 | mutex_lock(&vcpu->kvm->lock); | ||
| 2898 | pio_dev = vcpu_find_pio_dev(vcpu, port, | 2895 | pio_dev = vcpu_find_pio_dev(vcpu, port, |
| 2899 | vcpu->arch.pio.cur_count, | 2896 | vcpu->arch.pio.cur_count, |
| 2900 | !vcpu->arch.pio.in); | 2897 | !vcpu->arch.pio.in); |
| 2898 | mutex_unlock(&vcpu->kvm->lock); | ||
| 2899 | |||
| 2901 | if (!vcpu->arch.pio.in) { | 2900 | if (!vcpu->arch.pio.in) { |
| 2902 | /* string PIO write */ | 2901 | /* string PIO write */ |
| 2903 | ret = pio_copy_data(vcpu); | 2902 | ret = pio_copy_data(vcpu); |
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 0c71688b1ee3..a29ea030dd8e 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
| @@ -371,7 +371,8 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level); | |||
| 371 | void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin); | 371 | void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin); |
| 372 | void kvm_register_irq_ack_notifier(struct kvm *kvm, | 372 | void kvm_register_irq_ack_notifier(struct kvm *kvm, |
| 373 | struct kvm_irq_ack_notifier *kian); | 373 | struct kvm_irq_ack_notifier *kian); |
| 374 | void kvm_unregister_irq_ack_notifier(struct kvm_irq_ack_notifier *kian); | 374 | void kvm_unregister_irq_ack_notifier(struct kvm *kvm, |
| 375 | struct kvm_irq_ack_notifier *kian); | ||
| 375 | int kvm_request_irq_source_id(struct kvm *kvm); | 376 | int kvm_request_irq_source_id(struct kvm *kvm); |
| 376 | void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id); | 377 | void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id); |
| 377 | 378 | ||
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index 314012323afe..4092b8dcd510 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c | |||
| @@ -57,10 +57,10 @@ irqfd_inject(struct work_struct *work) | |||
| 57 | struct _irqfd *irqfd = container_of(work, struct _irqfd, inject); | 57 | struct _irqfd *irqfd = container_of(work, struct _irqfd, inject); |
| 58 | struct kvm *kvm = irqfd->kvm; | 58 | struct kvm *kvm = irqfd->kvm; |
| 59 | 59 | ||
| 60 | mutex_lock(&kvm->lock); | 60 | mutex_lock(&kvm->irq_lock); |
| 61 | kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 1); | 61 | kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 1); |
| 62 | kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 0); | 62 | kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 0); |
| 63 | mutex_unlock(&kvm->lock); | 63 | mutex_unlock(&kvm->irq_lock); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | /* | 66 | /* |
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index ddc17f0e2f35..08a9a49481b2 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c | |||
| @@ -62,6 +62,8 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, | |||
| 62 | int i, r = -1; | 62 | int i, r = -1; |
| 63 | struct kvm_vcpu *vcpu, *lowest = NULL; | 63 | struct kvm_vcpu *vcpu, *lowest = NULL; |
| 64 | 64 | ||
| 65 | WARN_ON(!mutex_is_locked(&kvm->irq_lock)); | ||
| 66 | |||
| 65 | if (irq->dest_mode == 0 && irq->dest_id == 0xff && | 67 | if (irq->dest_mode == 0 && irq->dest_id == 0xff && |
| 66 | kvm_is_dm_lowest_prio(irq)) | 68 | kvm_is_dm_lowest_prio(irq)) |
| 67 | printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n"); | 69 | printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n"); |
| @@ -113,7 +115,7 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, | |||
| 113 | return kvm_irq_delivery_to_apic(kvm, NULL, &irq); | 115 | return kvm_irq_delivery_to_apic(kvm, NULL, &irq); |
| 114 | } | 116 | } |
| 115 | 117 | ||
| 116 | /* This should be called with the kvm->lock mutex held | 118 | /* This should be called with the kvm->irq_lock mutex held |
| 117 | * Return value: | 119 | * Return value: |
| 118 | * < 0 Interrupt was ignored (masked or not delivered for other reasons) | 120 | * < 0 Interrupt was ignored (masked or not delivered for other reasons) |
| 119 | * = 0 Interrupt was coalesced (previous irq is still pending) | 121 | * = 0 Interrupt was coalesced (previous irq is still pending) |
| @@ -125,6 +127,8 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level) | |||
| 125 | unsigned long *irq_state, sig_level; | 127 | unsigned long *irq_state, sig_level; |
| 126 | int ret = -1; | 128 | int ret = -1; |
| 127 | 129 | ||
| 130 | WARN_ON(!mutex_is_locked(&kvm->irq_lock)); | ||
| 131 | |||
| 128 | if (irq < KVM_IOAPIC_NUM_PINS) { | 132 | if (irq < KVM_IOAPIC_NUM_PINS) { |
| 129 | irq_state = (unsigned long *)&kvm->arch.irq_states[irq]; | 133 | irq_state = (unsigned long *)&kvm->arch.irq_states[irq]; |
| 130 | 134 | ||
| @@ -175,19 +179,26 @@ void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) | |||
| 175 | void kvm_register_irq_ack_notifier(struct kvm *kvm, | 179 | void kvm_register_irq_ack_notifier(struct kvm *kvm, |
| 176 | struct kvm_irq_ack_notifier *kian) | 180 | struct kvm_irq_ack_notifier *kian) |
| 177 | { | 181 | { |
| 182 | mutex_lock(&kvm->irq_lock); | ||
| 178 | hlist_add_head(&kian->link, &kvm->arch.irq_ack_notifier_list); | 183 | hlist_add_head(&kian->link, &kvm->arch.irq_ack_notifier_list); |
| 184 | mutex_unlock(&kvm->irq_lock); | ||
| 179 | } | 185 | } |
| 180 | 186 | ||
| 181 | void kvm_unregister_irq_ack_notifier(struct kvm_irq_ack_notifier *kian) | 187 | void kvm_unregister_irq_ack_notifier(struct kvm *kvm, |
| 188 | struct kvm_irq_ack_notifier *kian) | ||
| 182 | { | 189 | { |
| 190 | mutex_lock(&kvm->irq_lock); | ||
| 183 | hlist_del_init(&kian->link); | 191 | hlist_del_init(&kian->link); |
| 192 | mutex_unlock(&kvm->irq_lock); | ||
| 184 | } | 193 | } |
| 185 | 194 | ||
| 186 | /* The caller must hold kvm->lock mutex */ | ||
| 187 | int kvm_request_irq_source_id(struct kvm *kvm) | 195 | int kvm_request_irq_source_id(struct kvm *kvm) |
| 188 | { | 196 | { |
| 189 | unsigned long *bitmap = &kvm->arch.irq_sources_bitmap; | 197 | unsigned long *bitmap = &kvm->arch.irq_sources_bitmap; |
| 190 | int irq_source_id = find_first_zero_bit(bitmap, | 198 | int irq_source_id; |
| 199 | |||
| 200 | mutex_lock(&kvm->irq_lock); | ||
| 201 | irq_source_id = find_first_zero_bit(bitmap, | ||
| 191 | sizeof(kvm->arch.irq_sources_bitmap)); | 202 | sizeof(kvm->arch.irq_sources_bitmap)); |
| 192 | 203 | ||
| 193 | if (irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) { | 204 | if (irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) { |
| @@ -197,6 +208,7 @@ int kvm_request_irq_source_id(struct kvm *kvm) | |||
| 197 | 208 | ||
| 198 | ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); | 209 | ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); |
| 199 | set_bit(irq_source_id, bitmap); | 210 | set_bit(irq_source_id, bitmap); |
| 211 | mutex_unlock(&kvm->irq_lock); | ||
| 200 | 212 | ||
| 201 | return irq_source_id; | 213 | return irq_source_id; |
| 202 | } | 214 | } |
| @@ -207,6 +219,7 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) | |||
| 207 | 219 | ||
| 208 | ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); | 220 | ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); |
| 209 | 221 | ||
| 222 | mutex_lock(&kvm->irq_lock); | ||
| 210 | if (irq_source_id < 0 || | 223 | if (irq_source_id < 0 || |
| 211 | irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) { | 224 | irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) { |
| 212 | printk(KERN_ERR "kvm: IRQ source ID out of range!\n"); | 225 | printk(KERN_ERR "kvm: IRQ source ID out of range!\n"); |
| @@ -215,19 +228,24 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) | |||
| 215 | for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) | 228 | for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) |
| 216 | clear_bit(irq_source_id, &kvm->arch.irq_states[i]); | 229 | clear_bit(irq_source_id, &kvm->arch.irq_states[i]); |
| 217 | clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap); | 230 | clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap); |
| 231 | mutex_unlock(&kvm->irq_lock); | ||
| 218 | } | 232 | } |
| 219 | 233 | ||
| 220 | void kvm_register_irq_mask_notifier(struct kvm *kvm, int irq, | 234 | void kvm_register_irq_mask_notifier(struct kvm *kvm, int irq, |
| 221 | struct kvm_irq_mask_notifier *kimn) | 235 | struct kvm_irq_mask_notifier *kimn) |
| 222 | { | 236 | { |
| 237 | mutex_lock(&kvm->irq_lock); | ||
| 223 | kimn->irq = irq; | 238 | kimn->irq = irq; |
| 224 | hlist_add_head(&kimn->link, &kvm->mask_notifier_list); | 239 | hlist_add_head(&kimn->link, &kvm->mask_notifier_list); |
| 240 | mutex_unlock(&kvm->irq_lock); | ||
| 225 | } | 241 | } |
| 226 | 242 | ||
| 227 | void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq, | 243 | void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq, |
| 228 | struct kvm_irq_mask_notifier *kimn) | 244 | struct kvm_irq_mask_notifier *kimn) |
| 229 | { | 245 | { |
| 246 | mutex_lock(&kvm->irq_lock); | ||
| 230 | hlist_del(&kimn->link); | 247 | hlist_del(&kimn->link); |
| 248 | mutex_unlock(&kvm->irq_lock); | ||
| 231 | } | 249 | } |
| 232 | 250 | ||
| 233 | void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask) | 251 | void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask) |
| @@ -235,6 +253,8 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask) | |||
| 235 | struct kvm_irq_mask_notifier *kimn; | 253 | struct kvm_irq_mask_notifier *kimn; |
| 236 | struct hlist_node *n; | 254 | struct hlist_node *n; |
| 237 | 255 | ||
| 256 | WARN_ON(!mutex_is_locked(&kvm->irq_lock)); | ||
| 257 | |||
| 238 | hlist_for_each_entry(kimn, n, &kvm->mask_notifier_list, link) | 258 | hlist_for_each_entry(kimn, n, &kvm->mask_notifier_list, link) |
| 239 | if (kimn->irq == irq) | 259 | if (kimn->irq == irq) |
| 240 | kimn->func(kimn, mask); | 260 | kimn->func(kimn, mask); |
| @@ -250,7 +270,9 @@ static void __kvm_free_irq_routing(struct list_head *irq_routing) | |||
| 250 | 270 | ||
| 251 | void kvm_free_irq_routing(struct kvm *kvm) | 271 | void kvm_free_irq_routing(struct kvm *kvm) |
| 252 | { | 272 | { |
| 273 | mutex_lock(&kvm->irq_lock); | ||
| 253 | __kvm_free_irq_routing(&kvm->irq_routing); | 274 | __kvm_free_irq_routing(&kvm->irq_routing); |
| 275 | mutex_unlock(&kvm->irq_lock); | ||
| 254 | } | 276 | } |
| 255 | 277 | ||
| 256 | static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e, | 278 | static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e, |
| @@ -325,13 +347,13 @@ int kvm_set_irq_routing(struct kvm *kvm, | |||
| 325 | e = NULL; | 347 | e = NULL; |
| 326 | } | 348 | } |
| 327 | 349 | ||
| 328 | mutex_lock(&kvm->lock); | 350 | mutex_lock(&kvm->irq_lock); |
| 329 | list_splice(&kvm->irq_routing, &tmp); | 351 | list_splice(&kvm->irq_routing, &tmp); |
| 330 | INIT_LIST_HEAD(&kvm->irq_routing); | 352 | INIT_LIST_HEAD(&kvm->irq_routing); |
| 331 | list_splice(&irq_list, &kvm->irq_routing); | 353 | list_splice(&irq_list, &kvm->irq_routing); |
| 332 | INIT_LIST_HEAD(&irq_list); | 354 | INIT_LIST_HEAD(&irq_list); |
| 333 | list_splice(&tmp, &irq_list); | 355 | list_splice(&tmp, &irq_list); |
| 334 | mutex_unlock(&kvm->lock); | 356 | mutex_unlock(&kvm->irq_lock); |
| 335 | 357 | ||
| 336 | r = 0; | 358 | r = 0; |
| 337 | 359 | ||
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index d47e660fb709..0d481b282448 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
| @@ -62,6 +62,12 @@ | |||
| 62 | MODULE_AUTHOR("Qumranet"); | 62 | MODULE_AUTHOR("Qumranet"); |
| 63 | MODULE_LICENSE("GPL"); | 63 | MODULE_LICENSE("GPL"); |
| 64 | 64 | ||
| 65 | /* | ||
| 66 | * Ordering of locks: | ||
| 67 | * | ||
| 68 | * kvm->lock --> kvm->irq_lock | ||
| 69 | */ | ||
| 70 | |||
| 65 | DEFINE_SPINLOCK(kvm_lock); | 71 | DEFINE_SPINLOCK(kvm_lock); |
| 66 | LIST_HEAD(vm_list); | 72 | LIST_HEAD(vm_list); |
| 67 | 73 | ||
| @@ -126,11 +132,7 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) | |||
| 126 | interrupt_work); | 132 | interrupt_work); |
| 127 | kvm = assigned_dev->kvm; | 133 | kvm = assigned_dev->kvm; |
| 128 | 134 | ||
| 129 | /* This is taken to safely inject irq inside the guest. When | 135 | mutex_lock(&kvm->irq_lock); |
| 130 | * the interrupt injection (or the ioapic code) uses a | ||
| 131 | * finer-grained lock, update this | ||
| 132 | */ | ||
| 133 | mutex_lock(&kvm->lock); | ||
| 134 | spin_lock_irq(&assigned_dev->assigned_dev_lock); | 136 | spin_lock_irq(&assigned_dev->assigned_dev_lock); |
| 135 | if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) { | 137 | if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) { |
| 136 | struct kvm_guest_msix_entry *guest_entries = | 138 | struct kvm_guest_msix_entry *guest_entries = |
| @@ -149,7 +151,7 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) | |||
| 149 | assigned_dev->guest_irq, 1); | 151 | assigned_dev->guest_irq, 1); |
| 150 | 152 | ||
| 151 | spin_unlock_irq(&assigned_dev->assigned_dev_lock); | 153 | spin_unlock_irq(&assigned_dev->assigned_dev_lock); |
| 152 | mutex_unlock(&assigned_dev->kvm->lock); | 154 | mutex_unlock(&assigned_dev->kvm->irq_lock); |
| 153 | } | 155 | } |
| 154 | 156 | ||
| 155 | static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id) | 157 | static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id) |
| @@ -207,7 +209,7 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian) | |||
| 207 | static void deassign_guest_irq(struct kvm *kvm, | 209 | static void deassign_guest_irq(struct kvm *kvm, |
| 208 | struct kvm_assigned_dev_kernel *assigned_dev) | 210 | struct kvm_assigned_dev_kernel *assigned_dev) |
| 209 | { | 211 | { |
| 210 | kvm_unregister_irq_ack_notifier(&assigned_dev->ack_notifier); | 212 | kvm_unregister_irq_ack_notifier(kvm, &assigned_dev->ack_notifier); |
| 211 | assigned_dev->ack_notifier.gsi = -1; | 213 | assigned_dev->ack_notifier.gsi = -1; |
| 212 | 214 | ||
| 213 | if (assigned_dev->irq_source_id != -1) | 215 | if (assigned_dev->irq_source_id != -1) |
