aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/vfio
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2014-01-14 22:45:09 -0500
committerBjorn Helgaas <bhelgaas@google.com>2014-01-15 12:43:17 -0500
commit890ed578df82f5b7b5a874f9f2fa4f117305df5f (patch)
tree8105161071fa46a98feea8253f407adb71f1e242 /drivers/vfio
parent61cf16d8bd38c3dc52033ea75d5b1f8368514a17 (diff)
vfio-pci: Use pci "try" reset interface
PCI resets will attempt to take the device_lock for any device to be reset. This is a problem if that lock is already held, for instance in the device remove path. It's not sufficient to simply kill the user process or skip the reset if called after .remove as a race could result in the same deadlock. Instead, we handle all resets as "best effort" using the PCI "try" reset interfaces. This prevents the user from being able to induce a deadlock by triggering a reset. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/vfio')
-rw-r--r--drivers/vfio/pci/vfio_pci.c29
1 files changed, 9 insertions, 20 deletions
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 6ab71b9fcf8d..2319d206f630 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -139,25 +139,14 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
139 pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); 139 pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
140 140
141 /* 141 /*
142 * Careful, device_lock may already be held. This is the case if 142 * Try to reset the device. The success of this is dependent on
143 * a driver unbind is blocked. Try to get the locks ourselves to 143 * being able to lock the device, which is not always possible.
144 * prevent a deadlock.
145 */ 144 */
146 if (vdev->reset_works) { 145 if (vdev->reset_works) {
147 bool reset_done = false; 146 int ret = pci_try_reset_function(pdev);
148 147 if (ret)
149 if (pci_cfg_access_trylock(pdev)) { 148 pr_warn("%s: Failed to reset device %s (%d)\n",
150 if (device_trylock(&pdev->dev)) { 149 __func__, dev_name(&pdev->dev), ret);
151 __pci_reset_function_locked(pdev);
152 reset_done = true;
153 device_unlock(&pdev->dev);
154 }
155 pci_cfg_access_unlock(pdev);
156 }
157
158 if (!reset_done)
159 pr_warn("%s: Unable to acquire locks for reset of %s\n",
160 __func__, dev_name(&pdev->dev));
161 } 150 }
162 151
163 pci_restore_state(pdev); 152 pci_restore_state(pdev);
@@ -514,7 +503,7 @@ static long vfio_pci_ioctl(void *device_data,
514 503
515 } else if (cmd == VFIO_DEVICE_RESET) { 504 } else if (cmd == VFIO_DEVICE_RESET) {
516 return vdev->reset_works ? 505 return vdev->reset_works ?
517 pci_reset_function(vdev->pdev) : -EINVAL; 506 pci_try_reset_function(vdev->pdev) : -EINVAL;
518 507
519 } else if (cmd == VFIO_DEVICE_GET_PCI_HOT_RESET_INFO) { 508 } else if (cmd == VFIO_DEVICE_GET_PCI_HOT_RESET_INFO) {
520 struct vfio_pci_hot_reset_info hdr; 509 struct vfio_pci_hot_reset_info hdr;
@@ -684,8 +673,8 @@ reset_info_exit:
684 &info, slot); 673 &info, slot);
685 if (!ret) 674 if (!ret)
686 /* User has access, do the reset */ 675 /* User has access, do the reset */
687 ret = slot ? pci_reset_slot(vdev->pdev->slot) : 676 ret = slot ? pci_try_reset_slot(vdev->pdev->slot) :
688 pci_reset_bus(vdev->pdev->bus); 677 pci_try_reset_bus(vdev->pdev->bus);
689 678
690hot_reset_release: 679hot_reset_release:
691 for (i--; i >= 0; i--) 680 for (i--; i >= 0; i--)