diff options
-rw-r--r-- | include/linux/kvm_host.h | 16 | ||||
-rw-r--r-- | virt/kvm/eventfd.c | 91 | ||||
-rw-r--r-- | virt/kvm/irq_comm.c | 7 |
3 files changed, 99 insertions, 15 deletions
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 4bd663d6443d..f17beae3cca0 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/preempt.h> | 17 | #include <linux/preempt.h> |
18 | #include <linux/msi.h> | 18 | #include <linux/msi.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/rcupdate.h> | ||
20 | #include <asm/signal.h> | 21 | #include <asm/signal.h> |
21 | 22 | ||
22 | #include <linux/kvm.h> | 23 | #include <linux/kvm.h> |
@@ -240,6 +241,10 @@ struct kvm { | |||
240 | 241 | ||
241 | struct mutex irq_lock; | 242 | struct mutex irq_lock; |
242 | #ifdef CONFIG_HAVE_KVM_IRQCHIP | 243 | #ifdef CONFIG_HAVE_KVM_IRQCHIP |
244 | /* | ||
245 | * Update side is protected by irq_lock and, | ||
246 | * if configured, irqfds.lock. | ||
247 | */ | ||
243 | struct kvm_irq_routing_table __rcu *irq_routing; | 248 | struct kvm_irq_routing_table __rcu *irq_routing; |
244 | struct hlist_head mask_notifier_list; | 249 | struct hlist_head mask_notifier_list; |
245 | struct hlist_head irq_ack_notifier_list; | 250 | struct hlist_head irq_ack_notifier_list; |
@@ -511,6 +516,8 @@ void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic, | |||
511 | unsigned long *deliver_bitmask); | 516 | unsigned long *deliver_bitmask); |
512 | #endif | 517 | #endif |
513 | int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level); | 518 | int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level); |
519 | int kvm_set_msi(struct kvm_kernel_irq_routing_entry *irq_entry, struct kvm *kvm, | ||
520 | int irq_source_id, int level); | ||
514 | void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin); | 521 | void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin); |
515 | void kvm_register_irq_ack_notifier(struct kvm *kvm, | 522 | void kvm_register_irq_ack_notifier(struct kvm *kvm, |
516 | struct kvm_irq_ack_notifier *kian); | 523 | struct kvm_irq_ack_notifier *kian); |
@@ -652,17 +659,26 @@ static inline void kvm_free_irq_routing(struct kvm *kvm) {} | |||
652 | void kvm_eventfd_init(struct kvm *kvm); | 659 | void kvm_eventfd_init(struct kvm *kvm); |
653 | int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags); | 660 | int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags); |
654 | void kvm_irqfd_release(struct kvm *kvm); | 661 | void kvm_irqfd_release(struct kvm *kvm); |
662 | void kvm_irq_routing_update(struct kvm *, struct kvm_irq_routing_table *); | ||
655 | int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args); | 663 | int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args); |
656 | 664 | ||
657 | #else | 665 | #else |
658 | 666 | ||
659 | static inline void kvm_eventfd_init(struct kvm *kvm) {} | 667 | static inline void kvm_eventfd_init(struct kvm *kvm) {} |
668 | |||
660 | static inline int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags) | 669 | static inline int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags) |
661 | { | 670 | { |
662 | return -EINVAL; | 671 | return -EINVAL; |
663 | } | 672 | } |
664 | 673 | ||
665 | static inline void kvm_irqfd_release(struct kvm *kvm) {} | 674 | static inline void kvm_irqfd_release(struct kvm *kvm) {} |
675 | |||
676 | static inline void kvm_irq_routing_update(struct kvm *kvm, | ||
677 | struct kvm_irq_routing_table *irq_rt) | ||
678 | { | ||
679 | rcu_assign_pointer(kvm->irq_routing, irq_rt); | ||
680 | } | ||
681 | |||
666 | static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) | 682 | static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) |
667 | { | 683 | { |
668 | return -ENOSYS; | 684 | return -ENOSYS; |
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index c1f1e3c62984..2ca4535f4fb7 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c | |||
@@ -44,14 +44,19 @@ | |||
44 | */ | 44 | */ |
45 | 45 | ||
46 | struct _irqfd { | 46 | struct _irqfd { |
47 | struct kvm *kvm; | 47 | /* Used for MSI fast-path */ |
48 | struct eventfd_ctx *eventfd; | 48 | struct kvm *kvm; |
49 | int gsi; | 49 | wait_queue_t wait; |
50 | struct list_head list; | 50 | /* Update side is protected by irqfds.lock */ |
51 | poll_table pt; | 51 | struct kvm_kernel_irq_routing_entry __rcu *irq_entry; |
52 | wait_queue_t wait; | 52 | /* Used for level IRQ fast-path */ |
53 | struct work_struct inject; | 53 | int gsi; |
54 | struct work_struct shutdown; | 54 | struct work_struct inject; |
55 | /* Used for setup/shutdown */ | ||
56 | struct eventfd_ctx *eventfd; | ||
57 | struct list_head list; | ||
58 | poll_table pt; | ||
59 | struct work_struct shutdown; | ||
55 | }; | 60 | }; |
56 | 61 | ||
57 | static struct workqueue_struct *irqfd_cleanup_wq; | 62 | static struct workqueue_struct *irqfd_cleanup_wq; |
@@ -125,14 +130,22 @@ irqfd_wakeup(wait_queue_t *wait, unsigned mode, int sync, void *key) | |||
125 | { | 130 | { |
126 | struct _irqfd *irqfd = container_of(wait, struct _irqfd, wait); | 131 | struct _irqfd *irqfd = container_of(wait, struct _irqfd, wait); |
127 | unsigned long flags = (unsigned long)key; | 132 | unsigned long flags = (unsigned long)key; |
133 | struct kvm_kernel_irq_routing_entry *irq; | ||
134 | struct kvm *kvm = irqfd->kvm; | ||
128 | 135 | ||
129 | if (flags & POLLIN) | 136 | if (flags & POLLIN) { |
137 | rcu_read_lock(); | ||
138 | irq = rcu_dereference(irqfd->irq_entry); | ||
130 | /* An event has been signaled, inject an interrupt */ | 139 | /* An event has been signaled, inject an interrupt */ |
131 | schedule_work(&irqfd->inject); | 140 | if (irq) |
141 | kvm_set_msi(irq, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1); | ||
142 | else | ||
143 | schedule_work(&irqfd->inject); | ||
144 | rcu_read_unlock(); | ||
145 | } | ||
132 | 146 | ||
133 | if (flags & POLLHUP) { | 147 | if (flags & POLLHUP) { |
134 | /* The eventfd is closing, detach from KVM */ | 148 | /* The eventfd is closing, detach from KVM */ |
135 | struct kvm *kvm = irqfd->kvm; | ||
136 | unsigned long flags; | 149 | unsigned long flags; |
137 | 150 | ||
138 | spin_lock_irqsave(&kvm->irqfds.lock, flags); | 151 | spin_lock_irqsave(&kvm->irqfds.lock, flags); |
@@ -163,9 +176,31 @@ irqfd_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh, | |||
163 | add_wait_queue(wqh, &irqfd->wait); | 176 | add_wait_queue(wqh, &irqfd->wait); |
164 | } | 177 | } |
165 | 178 | ||
179 | /* Must be called under irqfds.lock */ | ||
180 | static void irqfd_update(struct kvm *kvm, struct _irqfd *irqfd, | ||
181 | struct kvm_irq_routing_table *irq_rt) | ||
182 | { | ||
183 | struct kvm_kernel_irq_routing_entry *e; | ||
184 | struct hlist_node *n; | ||
185 | |||
186 | if (irqfd->gsi >= irq_rt->nr_rt_entries) { | ||
187 | rcu_assign_pointer(irqfd->irq_entry, NULL); | ||
188 | return; | ||
189 | } | ||
190 | |||
191 | hlist_for_each_entry(e, n, &irq_rt->map[irqfd->gsi], link) { | ||
192 | /* Only fast-path MSI. */ | ||
193 | if (e->type == KVM_IRQ_ROUTING_MSI) | ||
194 | rcu_assign_pointer(irqfd->irq_entry, e); | ||
195 | else | ||
196 | rcu_assign_pointer(irqfd->irq_entry, NULL); | ||
197 | } | ||
198 | } | ||
199 | |||
166 | static int | 200 | static int |
167 | kvm_irqfd_assign(struct kvm *kvm, int fd, int gsi) | 201 | kvm_irqfd_assign(struct kvm *kvm, int fd, int gsi) |
168 | { | 202 | { |
203 | struct kvm_irq_routing_table *irq_rt; | ||
169 | struct _irqfd *irqfd, *tmp; | 204 | struct _irqfd *irqfd, *tmp; |
170 | struct file *file = NULL; | 205 | struct file *file = NULL; |
171 | struct eventfd_ctx *eventfd = NULL; | 206 | struct eventfd_ctx *eventfd = NULL; |
@@ -215,6 +250,10 @@ kvm_irqfd_assign(struct kvm *kvm, int fd, int gsi) | |||
215 | goto fail; | 250 | goto fail; |
216 | } | 251 | } |
217 | 252 | ||
253 | irq_rt = rcu_dereference_protected(kvm->irq_routing, | ||
254 | lockdep_is_held(&kvm->irqfds.lock)); | ||
255 | irqfd_update(kvm, irqfd, irq_rt); | ||
256 | |||
218 | events = file->f_op->poll(file, &irqfd->pt); | 257 | events = file->f_op->poll(file, &irqfd->pt); |
219 | 258 | ||
220 | list_add_tail(&irqfd->list, &kvm->irqfds.items); | 259 | list_add_tail(&irqfd->list, &kvm->irqfds.items); |
@@ -271,8 +310,17 @@ kvm_irqfd_deassign(struct kvm *kvm, int fd, int gsi) | |||
271 | spin_lock_irq(&kvm->irqfds.lock); | 310 | spin_lock_irq(&kvm->irqfds.lock); |
272 | 311 | ||
273 | list_for_each_entry_safe(irqfd, tmp, &kvm->irqfds.items, list) { | 312 | list_for_each_entry_safe(irqfd, tmp, &kvm->irqfds.items, list) { |
274 | if (irqfd->eventfd == eventfd && irqfd->gsi == gsi) | 313 | if (irqfd->eventfd == eventfd && irqfd->gsi == gsi) { |
314 | /* | ||
315 | * This rcu_assign_pointer is needed for when | ||
316 | * another thread calls kvm_irqfd_update before | ||
317 | * we flush workqueue below. | ||
318 | * It is paired with synchronize_rcu done by caller | ||
319 | * of that function. | ||
320 | */ | ||
321 | rcu_assign_pointer(irqfd->irq_entry, NULL); | ||
275 | irqfd_deactivate(irqfd); | 322 | irqfd_deactivate(irqfd); |
323 | } | ||
276 | } | 324 | } |
277 | 325 | ||
278 | spin_unlock_irq(&kvm->irqfds.lock); | 326 | spin_unlock_irq(&kvm->irqfds.lock); |
@@ -322,6 +370,25 @@ kvm_irqfd_release(struct kvm *kvm) | |||
322 | } | 370 | } |
323 | 371 | ||
324 | /* | 372 | /* |
373 | * Change irq_routing and irqfd. | ||
374 | * Caller must invoke synchronize_rcu afterwards. | ||
375 | */ | ||
376 | void kvm_irq_routing_update(struct kvm *kvm, | ||
377 | struct kvm_irq_routing_table *irq_rt) | ||
378 | { | ||
379 | struct _irqfd *irqfd; | ||
380 | |||
381 | spin_lock_irq(&kvm->irqfds.lock); | ||
382 | |||
383 | rcu_assign_pointer(kvm->irq_routing, irq_rt); | ||
384 | |||
385 | list_for_each_entry(irqfd, &kvm->irqfds.items, list) | ||
386 | irqfd_update(kvm, irqfd, irq_rt); | ||
387 | |||
388 | spin_unlock_irq(&kvm->irqfds.lock); | ||
389 | } | ||
390 | |||
391 | /* | ||
325 | * create a host-wide workqueue for issuing deferred shutdown requests | 392 | * create a host-wide workqueue for issuing deferred shutdown requests |
326 | * aggregated from all vm* instances. We need our own isolated single-thread | 393 | * aggregated from all vm* instances. We need our own isolated single-thread |
327 | * queue to prevent deadlock against flushing the normal work-queue. | 394 | * queue to prevent deadlock against flushing the normal work-queue. |
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index 8edca9141b78..9f614b4e365f 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c | |||
@@ -114,8 +114,8 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, | |||
114 | return r; | 114 | return r; |
115 | } | 115 | } |
116 | 116 | ||
117 | static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, | 117 | int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, |
118 | struct kvm *kvm, int irq_source_id, int level) | 118 | struct kvm *kvm, int irq_source_id, int level) |
119 | { | 119 | { |
120 | struct kvm_lapic_irq irq; | 120 | struct kvm_lapic_irq irq; |
121 | 121 | ||
@@ -409,8 +409,9 @@ int kvm_set_irq_routing(struct kvm *kvm, | |||
409 | 409 | ||
410 | mutex_lock(&kvm->irq_lock); | 410 | mutex_lock(&kvm->irq_lock); |
411 | old = kvm->irq_routing; | 411 | old = kvm->irq_routing; |
412 | rcu_assign_pointer(kvm->irq_routing, new); | 412 | kvm_irq_routing_update(kvm, new); |
413 | mutex_unlock(&kvm->irq_lock); | 413 | mutex_unlock(&kvm->irq_lock); |
414 | |||
414 | synchronize_rcu(); | 415 | synchronize_rcu(); |
415 | 416 | ||
416 | new = old; | 417 | new = old; |