]> git.baikalelectronics.ru Git - kernel.git/commitdiff
vfio-pci: Avoid deadlock on remove
authorAlex Williamson <alex.williamson@redhat.com>
Mon, 10 Jun 2013 22:40:57 +0000 (16:40 -0600)
committerAlex Williamson <alex.williamson@redhat.com>
Wed, 24 Jul 2013 22:36:41 +0000 (16:36 -0600)
If an attempt is made to unbind a device from vfio-pci while that
device is in use, the request is blocked until the device becomes
unused.  Unfortunately, that unbind path still grabs the device_lock,
which certain things like __pci_reset_function() also want to take.
This means we need to try to acquire the locks ourselves and use the
pre-locked version, __pci_reset_function_locked().

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
drivers/vfio/pci/vfio_pci.c

index c5179e269df64ade2de20a384b6732a6922c9bcf..cef6002acbd49aa078568fe2fe9ea4511230e861 100644 (file)
@@ -137,8 +137,27 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
         */
        pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
 
-       if (vdev->reset_works)
-               __pci_reset_function(pdev);
+       /*
+        * Careful, device_lock may already be held.  This is the case if
+        * a driver unbind is blocked.  Try to get the locks ourselves to
+        * prevent a deadlock.
+        */
+       if (vdev->reset_works) {
+               bool reset_done = false;
+
+               if (pci_cfg_access_trylock(pdev)) {
+                       if (device_trylock(&pdev->dev)) {
+                               __pci_reset_function_locked(pdev);
+                               reset_done = true;
+                               device_unlock(&pdev->dev);
+                       }
+                       pci_cfg_access_unlock(pdev);
+               }
+
+               if (!reset_done)
+                       pr_warn("%s: Unable to acquire locks for reset of %s\n",
+                               __func__, dev_name(&pdev->dev));
+       }
 
        pci_restore_state(pdev);
 }