diff options
| author | Alex Williamson <alex.williamson@redhat.com> | 2014-01-14 18:12:55 -0500 |
|---|---|---|
| committer | Alex Williamson <alex.williamson@redhat.com> | 2014-01-14 18:12:55 -0500 |
| commit | 3be3a074cf5ba641529d8fdae0e05ca642f23e12 (patch) | |
| tree | ae0c3fc80319e33c7618c63706a9c9dd98842b79 /drivers/vfio | |
| parent | d10999016f4164e9b80f1b3dece3842087cfa3bb (diff) | |
vfio-pci: Don't use device_lock around AER interrupt setup
device_lock is much too prone to lockups. For instance if we have a
pending .remove then device_lock is already held. If userspace
attempts to modify AER signaling after that point, a deadlock occurs.
eventfd setup/teardown is already protected in vfio with the igate
mutex. AER is not a high performance interrupt, so we can also use
the same mutex to protect signaling versus setup races.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Diffstat (limited to 'drivers/vfio')
| -rw-r--r-- | drivers/vfio/pci/vfio_pci.c | 4 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci_intrs.c | 17 |
2 files changed, 4 insertions, 17 deletions
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 6ab71b9fcf8d..3ffd27f42418 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c | |||
| @@ -883,9 +883,13 @@ static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev, | |||
| 883 | return PCI_ERS_RESULT_DISCONNECT; | 883 | return PCI_ERS_RESULT_DISCONNECT; |
| 884 | } | 884 | } |
| 885 | 885 | ||
| 886 | mutex_lock(&vdev->igate); | ||
| 887 | |||
| 886 | if (vdev->err_trigger) | 888 | if (vdev->err_trigger) |
| 887 | eventfd_signal(vdev->err_trigger, 1); | 889 | eventfd_signal(vdev->err_trigger, 1); |
| 888 | 890 | ||
| 891 | mutex_unlock(&vdev->igate); | ||
| 892 | |||
| 889 | vfio_device_put(device); | 893 | vfio_device_put(device); |
| 890 | 894 | ||
| 891 | return PCI_ERS_RESULT_CAN_RECOVER; | 895 | return PCI_ERS_RESULT_CAN_RECOVER; |
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 641bc87bdb96..210357691dc0 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c | |||
| @@ -749,54 +749,37 @@ static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev, | |||
| 749 | unsigned count, uint32_t flags, void *data) | 749 | unsigned count, uint32_t flags, void *data) |
| 750 | { | 750 | { |
| 751 | int32_t fd = *(int32_t *)data; | 751 | int32_t fd = *(int32_t *)data; |
| 752 | struct pci_dev *pdev = vdev->pdev; | ||
| 753 | 752 | ||
| 754 | if ((index != VFIO_PCI_ERR_IRQ_INDEX) || | 753 | if ((index != VFIO_PCI_ERR_IRQ_INDEX) || |
| 755 | !(flags & VFIO_IRQ_SET_DATA_TYPE_MASK)) | 754 | !(flags & VFIO_IRQ_SET_DATA_TYPE_MASK)) |
| 756 | return -EINVAL; | 755 | return -EINVAL; |
| 757 | 756 | ||
| 758 | /* | ||
| 759 | * device_lock synchronizes setting and checking of | ||
| 760 | * err_trigger. The vfio_pci_aer_err_detected() is also | ||
| 761 | * called with device_lock held. | ||
| 762 | */ | ||
| 763 | |||
| 764 | /* DATA_NONE/DATA_BOOL enables loopback testing */ | 757 | /* DATA_NONE/DATA_BOOL enables loopback testing */ |
| 765 | |||
| 766 | if (flags & VFIO_IRQ_SET_DATA_NONE) { | 758 | if (flags & VFIO_IRQ_SET_DATA_NONE) { |
| 767 | device_lock(&pdev->dev); | ||
| 768 | if (vdev->err_trigger) | 759 | if (vdev->err_trigger) |
| 769 | eventfd_signal(vdev->err_trigger, 1); | 760 | eventfd_signal(vdev->err_trigger, 1); |
| 770 | device_unlock(&pdev->dev); | ||
| 771 | return 0; | 761 | return 0; |
| 772 | } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { | 762 | } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { |
| 773 | uint8_t trigger = *(uint8_t *)data; | 763 | uint8_t trigger = *(uint8_t *)data; |
| 774 | device_lock(&pdev->dev); | ||
| 775 | if (trigger && vdev->err_trigger) | 764 | if (trigger && vdev->err_trigger) |
| 776 | eventfd_signal(vdev->err_trigger, 1); | 765 | eventfd_signal(vdev->err_trigger, 1); |
| 777 | device_unlock(&pdev->dev); | ||
| 778 | return 0; | 766 | return 0; |
| 779 | } | 767 | } |
| 780 | 768 | ||
| 781 | /* Handle SET_DATA_EVENTFD */ | 769 | /* Handle SET_DATA_EVENTFD */ |
| 782 | |||
| 783 | if (fd == -1) { | 770 | if (fd == -1) { |
| 784 | device_lock(&pdev->dev); | ||
| 785 | if (vdev->err_trigger) | 771 | if (vdev->err_trigger) |
| 786 | eventfd_ctx_put(vdev->err_trigger); | 772 | eventfd_ctx_put(vdev->err_trigger); |
| 787 | vdev->err_trigger = NULL; | 773 | vdev->err_trigger = NULL; |
| 788 | device_unlock(&pdev->dev); | ||
| 789 | return 0; | 774 | return 0; |
| 790 | } else if (fd >= 0) { | 775 | } else if (fd >= 0) { |
| 791 | struct eventfd_ctx *efdctx; | 776 | struct eventfd_ctx *efdctx; |
| 792 | efdctx = eventfd_ctx_fdget(fd); | 777 | efdctx = eventfd_ctx_fdget(fd); |
| 793 | if (IS_ERR(efdctx)) | 778 | if (IS_ERR(efdctx)) |
| 794 | return PTR_ERR(efdctx); | 779 | return PTR_ERR(efdctx); |
| 795 | device_lock(&pdev->dev); | ||
| 796 | if (vdev->err_trigger) | 780 | if (vdev->err_trigger) |
| 797 | eventfd_ctx_put(vdev->err_trigger); | 781 | eventfd_ctx_put(vdev->err_trigger); |
| 798 | vdev->err_trigger = efdctx; | 782 | vdev->err_trigger = efdctx; |
| 799 | device_unlock(&pdev->dev); | ||
| 800 | return 0; | 783 | return 0; |
| 801 | } else | 784 | } else |
| 802 | return -EINVAL; | 785 | return -EINVAL; |
