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 /virt/kvm/kvm_main.c | |
| 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>
Diffstat (limited to 'virt/kvm/kvm_main.c')
| -rw-r--r-- | virt/kvm/kvm_main.c | 16 |
1 files changed, 9 insertions, 7 deletions
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) |
