diff options
Diffstat (limited to 'drivers/vfio/virqfd.c')
| -rw-r--r-- | drivers/vfio/virqfd.c | 56 |
1 files changed, 28 insertions, 28 deletions
diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c index 414e98d82b02..aa2891f97508 100644 --- a/drivers/vfio/virqfd.c +++ b/drivers/vfio/virqfd.c @@ -12,15 +12,12 @@ #include <linux/file.h> #include <linux/module.h> #include <linux/slab.h> - -#define DRIVER_VERSION "0.1" -#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>" -#define DRIVER_DESC "IRQFD support for VFIO bus drivers" +#include "vfio.h" static struct workqueue_struct *vfio_irqfd_cleanup_wq; static DEFINE_SPINLOCK(virqfd_lock); -static int __init vfio_virqfd_init(void) +int __init vfio_virqfd_init(void) { vfio_irqfd_cleanup_wq = create_singlethread_workqueue("vfio-irqfd-cleanup"); @@ -30,7 +27,7 @@ static int __init vfio_virqfd_init(void) return 0; } -static void __exit vfio_virqfd_exit(void) +void vfio_virqfd_exit(void) { destroy_workqueue(vfio_irqfd_cleanup_wq); } @@ -104,18 +101,24 @@ static void virqfd_inject(struct work_struct *work) virqfd->thread(virqfd->opaque, virqfd->data); } +static void virqfd_flush_inject(struct work_struct *work) +{ + struct virqfd *virqfd = container_of(work, struct virqfd, flush_inject); + + flush_work(&virqfd->inject); +} + int vfio_virqfd_enable(void *opaque, int (*handler)(void *, void *), void (*thread)(void *, void *), void *data, struct virqfd **pvirqfd, int fd) { - struct fd irqfd; struct eventfd_ctx *ctx; struct virqfd *virqfd; int ret = 0; __poll_t events; - virqfd = kzalloc(sizeof(*virqfd), GFP_KERNEL); + virqfd = kzalloc(sizeof(*virqfd), GFP_KERNEL_ACCOUNT); if (!virqfd) return -ENOMEM; @@ -127,17 +130,18 @@ int vfio_virqfd_enable(void *opaque, INIT_WORK(&virqfd->shutdown, virqfd_shutdown); INIT_WORK(&virqfd->inject, virqfd_inject); + INIT_WORK(&virqfd->flush_inject, virqfd_flush_inject); - irqfd = fdget(fd); - if (!irqfd.file) { + CLASS(fd, irqfd)(fd); + if (fd_empty(irqfd)) { ret = -EBADF; goto err_fd; } - ctx = eventfd_ctx_fileget(irqfd.file); + ctx = eventfd_ctx_fileget(fd_file(irqfd)); if (IS_ERR(ctx)) { ret = PTR_ERR(ctx); - goto err_ctx; + goto err_fd; } virqfd->eventfd = ctx; @@ -166,7 +170,7 @@ int vfio_virqfd_enable(void *opaque, init_waitqueue_func_entry(&virqfd->wait, virqfd_wakeup); init_poll_funcptr(&virqfd->pt, virqfd_ptable_queue_proc); - events = vfs_poll(irqfd.file, &virqfd->pt); + events = vfs_poll(fd_file(irqfd), &virqfd->pt); /* * Check if there was an event already pending on the eventfd @@ -176,18 +180,9 @@ int vfio_virqfd_enable(void *opaque, if ((!handler || handler(opaque, data)) && thread) schedule_work(&virqfd->inject); } - - /* - * Do not drop the file until the irqfd is fully initialized, - * otherwise we might race against the EPOLLHUP. - */ - fdput(irqfd); - return 0; err_busy: eventfd_ctx_put(ctx); -err_ctx: - fdput(irqfd); err_fd: kfree(virqfd); @@ -217,10 +212,15 @@ void vfio_virqfd_disable(struct virqfd **pvirqfd) } EXPORT_SYMBOL_GPL(vfio_virqfd_disable); -module_init(vfio_virqfd_init); -module_exit(vfio_virqfd_exit); +void vfio_virqfd_flush_thread(struct virqfd **pvirqfd) +{ + unsigned long flags; -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); + spin_lock_irqsave(&virqfd_lock, flags); + if (*pvirqfd && (*pvirqfd)->thread) + queue_work(vfio_irqfd_cleanup_wq, &(*pvirqfd)->flush_inject); + spin_unlock_irqrestore(&virqfd_lock, flags); + + flush_workqueue(vfio_irqfd_cleanup_wq); +} +EXPORT_SYMBOL_GPL(vfio_virqfd_flush_thread); |
