Merge branch 'tracing/core' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic...
[linux-2.6-block.git] / virt / kvm / eventfd.c
index 30f70fd511c4da7d91b83ad3aefb873134818ba8..a9d3fc6c681c5ab01bec43975d50ef93408c88e1 100644 (file)
@@ -72,12 +72,13 @@ static void
 irqfd_shutdown(struct work_struct *work)
 {
        struct _irqfd *irqfd = container_of(work, struct _irqfd, shutdown);
+       u64 cnt;
 
        /*
         * Synchronize with the wait-queue and unhook ourselves to prevent
         * further events.
         */
-       remove_wait_queue(irqfd->wqh, &irqfd->wait);
+       eventfd_ctx_remove_wait_queue(irqfd->eventfd, &irqfd->wait, &cnt);
 
        /*
         * We know no new events will be scheduled at this point, so block
@@ -166,7 +167,7 @@ irqfd_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh,
 static int
 kvm_irqfd_assign(struct kvm *kvm, int fd, int gsi)
 {
-       struct _irqfd *irqfd;
+       struct _irqfd *irqfd, *tmp;
        struct file *file = NULL;
        struct eventfd_ctx *eventfd = NULL;
        int ret;
@@ -203,9 +204,20 @@ kvm_irqfd_assign(struct kvm *kvm, int fd, int gsi)
        init_waitqueue_func_entry(&irqfd->wait, irqfd_wakeup);
        init_poll_funcptr(&irqfd->pt, irqfd_ptable_queue_proc);
 
+       spin_lock_irq(&kvm->irqfds.lock);
+
+       ret = 0;
+       list_for_each_entry(tmp, &kvm->irqfds.items, list) {
+               if (irqfd->eventfd != tmp->eventfd)
+                       continue;
+               /* This fd is used for another irq already. */
+               ret = -EBUSY;
+               spin_unlock_irq(&kvm->irqfds.lock);
+               goto fail;
+       }
+
        events = file->f_op->poll(file, &irqfd->pt);
 
-       spin_lock_irq(&kvm->irqfds.lock);
        list_add_tail(&irqfd->list, &kvm->irqfds.items);
        spin_unlock_irq(&kvm->irqfds.lock);