in acrn/irqfd.c [111:176]
static int acrn_irqfd_assign(struct acrn_vm *vm, struct acrn_irqfd *args)
{
struct eventfd_ctx *eventfd = NULL;
struct hsm_irqfd *irqfd, *tmp;
__poll_t events;
struct fd f;
int ret = 0;
irqfd = kzalloc(sizeof(*irqfd), GFP_KERNEL);
if (!irqfd)
return -ENOMEM;
irqfd->vm = vm;
memcpy(&irqfd->msi, &args->msi, sizeof(args->msi));
INIT_LIST_HEAD(&irqfd->list);
INIT_WORK(&irqfd->shutdown, hsm_irqfd_shutdown_work);
f = fdget(args->fd);
if (!f.file) {
ret = -EBADF;
goto out;
}
eventfd = eventfd_ctx_fileget(f.file);
if (IS_ERR(eventfd)) {
ret = PTR_ERR(eventfd);
goto fail;
}
irqfd->eventfd = eventfd;
/*
* Install custom wake-up handling to be notified whenever underlying
* eventfd is signaled.
*/
init_waitqueue_func_entry(&irqfd->wait, hsm_irqfd_wakeup);
init_poll_funcptr(&irqfd->pt, hsm_irqfd_poll_func);
mutex_lock(&vm->irqfds_lock);
list_for_each_entry(tmp, &vm->irqfds, list) {
if (irqfd->eventfd != tmp->eventfd)
continue;
ret = -EBUSY;
mutex_unlock(&vm->irqfds_lock);
goto fail;
}
list_add_tail(&irqfd->list, &vm->irqfds);
mutex_unlock(&vm->irqfds_lock);
/* Check the pending event in this stage */
events = vfs_poll(f.file, &irqfd->pt);
if (events & EPOLLIN)
acrn_irqfd_inject(irqfd);
fdput(f);
return 0;
fail:
if (eventfd && !IS_ERR(eventfd))
eventfd_ctx_put(eventfd);
fdput(f);
out:
kfree(irqfd);
return ret;
}