Skip to content

Commit 38565c9

Browse files
author
Alex Williamson
committed
vfio/pci: Implement ioeventfd thread handler for contended memory lock
The ioeventfd is called under spinlock with interrupts disabled, therefore if the memory lock is contended defer code that might sleep to a thread context. Fixes: bc93b9a ("vfio-pci: Avoid recursive read-lock usage") Link: https://bugzilla.kernel.org/show_bug.cgi?id=209253#c1 Reported-by: Ian Pilcher <arequipeno@gmail.com> Tested-by: Ian Pilcher <arequipeno@gmail.com> Tested-by: Justin Gatzen <justin.gatzen@gmail.com> Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
1 parent 8e91cb3 commit 38565c9

1 file changed

Lines changed: 35 additions & 8 deletions

File tree

drivers/vfio/pci/vfio_pci_rdwr.c

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -356,34 +356,60 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_device *vdev, char __user *buf,
356356
return done;
357357
}
358358

359-
static int vfio_pci_ioeventfd_handler(void *opaque, void *unused)
359+
static void vfio_pci_ioeventfd_do_write(struct vfio_pci_ioeventfd *ioeventfd,
360+
bool test_mem)
360361
{
361-
struct vfio_pci_ioeventfd *ioeventfd = opaque;
362-
363362
switch (ioeventfd->count) {
364363
case 1:
365-
vfio_pci_iowrite8(ioeventfd->vdev, ioeventfd->test_mem,
364+
vfio_pci_iowrite8(ioeventfd->vdev, test_mem,
366365
ioeventfd->data, ioeventfd->addr);
367366
break;
368367
case 2:
369-
vfio_pci_iowrite16(ioeventfd->vdev, ioeventfd->test_mem,
368+
vfio_pci_iowrite16(ioeventfd->vdev, test_mem,
370369
ioeventfd->data, ioeventfd->addr);
371370
break;
372371
case 4:
373-
vfio_pci_iowrite32(ioeventfd->vdev, ioeventfd->test_mem,
372+
vfio_pci_iowrite32(ioeventfd->vdev, test_mem,
374373
ioeventfd->data, ioeventfd->addr);
375374
break;
376375
#ifdef iowrite64
377376
case 8:
378-
vfio_pci_iowrite64(ioeventfd->vdev, ioeventfd->test_mem,
377+
vfio_pci_iowrite64(ioeventfd->vdev, test_mem,
379378
ioeventfd->data, ioeventfd->addr);
380379
break;
381380
#endif
382381
}
382+
}
383+
384+
static int vfio_pci_ioeventfd_handler(void *opaque, void *unused)
385+
{
386+
struct vfio_pci_ioeventfd *ioeventfd = opaque;
387+
struct vfio_pci_device *vdev = ioeventfd->vdev;
388+
389+
if (ioeventfd->test_mem) {
390+
if (!down_read_trylock(&vdev->memory_lock))
391+
return 1; /* Lock contended, use thread */
392+
if (!__vfio_pci_memory_enabled(vdev)) {
393+
up_read(&vdev->memory_lock);
394+
return 0;
395+
}
396+
}
397+
398+
vfio_pci_ioeventfd_do_write(ioeventfd, false);
399+
400+
if (ioeventfd->test_mem)
401+
up_read(&vdev->memory_lock);
383402

384403
return 0;
385404
}
386405

406+
static void vfio_pci_ioeventfd_thread(void *opaque, void *unused)
407+
{
408+
struct vfio_pci_ioeventfd *ioeventfd = opaque;
409+
410+
vfio_pci_ioeventfd_do_write(ioeventfd, ioeventfd->test_mem);
411+
}
412+
387413
long vfio_pci_ioeventfd(struct vfio_pci_device *vdev, loff_t offset,
388414
uint64_t data, int count, int fd)
389415
{
@@ -457,7 +483,8 @@ long vfio_pci_ioeventfd(struct vfio_pci_device *vdev, loff_t offset,
457483
ioeventfd->test_mem = vdev->pdev->resource[bar].flags & IORESOURCE_MEM;
458484

459485
ret = vfio_virqfd_enable(ioeventfd, vfio_pci_ioeventfd_handler,
460-
NULL, NULL, &ioeventfd->virqfd, fd);
486+
vfio_pci_ioeventfd_thread, NULL,
487+
&ioeventfd->virqfd, fd);
461488
if (ret) {
462489
kfree(ioeventfd);
463490
goto out_unlock;

0 commit comments

Comments
 (0)