static int acrn_irqfd_assign()

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;
}