Skip to content

Commit

Permalink
vfio/pci: Implement ioeventfd thread handler for contended memory lock
Browse files Browse the repository at this point in the history
[ Upstream commit 38565c9 ]

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 <[email protected]>
Tested-by: Ian Pilcher <[email protected]>
Tested-by: Justin Gatzen <[email protected]>
Signed-off-by: Alex Williamson <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
  • Loading branch information
awilliam authored and gregkh committed Nov 18, 2020
1 parent 6b5164f commit 0a444bd
Showing 1 changed file with 35 additions and 8 deletions.
43 changes: 35 additions & 8 deletions drivers/vfio/pci/vfio_pci_rdwr.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,34 +356,60 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_device *vdev, char __user *buf,
return done;
}

static int vfio_pci_ioeventfd_handler(void *opaque, void *unused)
static void vfio_pci_ioeventfd_do_write(struct vfio_pci_ioeventfd *ioeventfd,
bool test_mem)
{
struct vfio_pci_ioeventfd *ioeventfd = opaque;

switch (ioeventfd->count) {
case 1:
vfio_pci_iowrite8(ioeventfd->vdev, ioeventfd->test_mem,
vfio_pci_iowrite8(ioeventfd->vdev, test_mem,
ioeventfd->data, ioeventfd->addr);
break;
case 2:
vfio_pci_iowrite16(ioeventfd->vdev, ioeventfd->test_mem,
vfio_pci_iowrite16(ioeventfd->vdev, test_mem,
ioeventfd->data, ioeventfd->addr);
break;
case 4:
vfio_pci_iowrite32(ioeventfd->vdev, ioeventfd->test_mem,
vfio_pci_iowrite32(ioeventfd->vdev, test_mem,
ioeventfd->data, ioeventfd->addr);
break;
#ifdef iowrite64
case 8:
vfio_pci_iowrite64(ioeventfd->vdev, ioeventfd->test_mem,
vfio_pci_iowrite64(ioeventfd->vdev, test_mem,
ioeventfd->data, ioeventfd->addr);
break;
#endif
}
}

static int vfio_pci_ioeventfd_handler(void *opaque, void *unused)
{
struct vfio_pci_ioeventfd *ioeventfd = opaque;
struct vfio_pci_device *vdev = ioeventfd->vdev;

if (ioeventfd->test_mem) {
if (!down_read_trylock(&vdev->memory_lock))
return 1; /* Lock contended, use thread */
if (!__vfio_pci_memory_enabled(vdev)) {
up_read(&vdev->memory_lock);
return 0;
}
}

vfio_pci_ioeventfd_do_write(ioeventfd, false);

if (ioeventfd->test_mem)
up_read(&vdev->memory_lock);

return 0;
}

static void vfio_pci_ioeventfd_thread(void *opaque, void *unused)
{
struct vfio_pci_ioeventfd *ioeventfd = opaque;

vfio_pci_ioeventfd_do_write(ioeventfd, ioeventfd->test_mem);
}

long vfio_pci_ioeventfd(struct vfio_pci_device *vdev, loff_t offset,
uint64_t data, int count, int fd)
{
Expand Down Expand Up @@ -457,7 +483,8 @@ long vfio_pci_ioeventfd(struct vfio_pci_device *vdev, loff_t offset,
ioeventfd->test_mem = vdev->pdev->resource[bar].flags & IORESOURCE_MEM;

ret = vfio_virqfd_enable(ioeventfd, vfio_pci_ioeventfd_handler,
NULL, NULL, &ioeventfd->virqfd, fd);
vfio_pci_ioeventfd_thread, NULL,
&ioeventfd->virqfd, fd);
if (ret) {
kfree(ioeventfd);
goto out_unlock;
Expand Down

0 comments on commit 0a444bd

Please sign in to comment.