Skip to content

Commit b620ecb

Browse files
committed
vfio: Introduce interface to flush virqfd inject workqueue
In order to synchronize changes that can affect the thread callback, introduce an interface to force a flush of the inject workqueue. The irqfd pointer is only valid under spinlock, but the workqueue cannot be flushed under spinlock. Therefore the flush work for the irqfd is queued under spinlock. The vfio_irqfd_cleanup_wq workqueue is re-used for queuing this work such that flushing the workqueue is also ordered relative to shutdown. Reviewed-by: Kevin Tian <kevin.tian@intel.com> Reviewed-by: Reinette Chatre <reinette.chatre@intel.com> Reviewed-by: Eric Auger <eric.auger@redhat.com> Link: https://lore.kernel.org/r/20240308230557.805580-4-alex.williamson@redhat.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
1 parent 810cd4b commit b620ecb

File tree

2 files changed

+23
-0
lines changed

2 files changed

+23
-0
lines changed

drivers/vfio/virqfd.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@ static void virqfd_inject(struct work_struct *work)
101101
virqfd->thread(virqfd->opaque, virqfd->data);
102102
}
103103

104+
static void virqfd_flush_inject(struct work_struct *work)
105+
{
106+
struct virqfd *virqfd = container_of(work, struct virqfd, flush_inject);
107+
108+
flush_work(&virqfd->inject);
109+
}
110+
104111
int vfio_virqfd_enable(void *opaque,
105112
int (*handler)(void *, void *),
106113
void (*thread)(void *, void *),
@@ -124,6 +131,7 @@ int vfio_virqfd_enable(void *opaque,
124131

125132
INIT_WORK(&virqfd->shutdown, virqfd_shutdown);
126133
INIT_WORK(&virqfd->inject, virqfd_inject);
134+
INIT_WORK(&virqfd->flush_inject, virqfd_flush_inject);
127135

128136
irqfd = fdget(fd);
129137
if (!irqfd.file) {
@@ -213,3 +221,16 @@ void vfio_virqfd_disable(struct virqfd **pvirqfd)
213221
flush_workqueue(vfio_irqfd_cleanup_wq);
214222
}
215223
EXPORT_SYMBOL_GPL(vfio_virqfd_disable);
224+
225+
void vfio_virqfd_flush_thread(struct virqfd **pvirqfd)
226+
{
227+
unsigned long flags;
228+
229+
spin_lock_irqsave(&virqfd_lock, flags);
230+
if (*pvirqfd && (*pvirqfd)->thread)
231+
queue_work(vfio_irqfd_cleanup_wq, &(*pvirqfd)->flush_inject);
232+
spin_unlock_irqrestore(&virqfd_lock, flags);
233+
234+
flush_workqueue(vfio_irqfd_cleanup_wq);
235+
}
236+
EXPORT_SYMBOL_GPL(vfio_virqfd_flush_thread);

include/linux/vfio.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,12 +356,14 @@ struct virqfd {
356356
wait_queue_entry_t wait;
357357
poll_table pt;
358358
struct work_struct shutdown;
359+
struct work_struct flush_inject;
359360
struct virqfd **pvirqfd;
360361
};
361362

362363
int vfio_virqfd_enable(void *opaque, int (*handler)(void *, void *),
363364
void (*thread)(void *, void *), void *data,
364365
struct virqfd **pvirqfd, int fd);
365366
void vfio_virqfd_disable(struct virqfd **pvirqfd);
367+
void vfio_virqfd_flush_thread(struct virqfd **pvirqfd);
366368

367369
#endif /* VFIO_H */

0 commit comments

Comments
 (0)