mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 14:41:39 +00:00
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: bc93b9ae01
("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>
This commit is contained in:
parent
8e91cb3812
commit
38565c93c8
@ -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)
|
||||
{
|
||||
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user