PCI: Add pci_try_reset_function(), pci_try_reset_slot(), pci_try_reset_bus()
authorAlex Williamson <alex.williamson@redhat.com>
Mon, 16 Dec 2013 22:14:31 +0000 (15:14 -0700)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 14 Jan 2014 23:34:44 +0000 (16:34 -0700)
commit61cf16d8bd38c3dc52033ea75d5b1f8368514a17
treeba64244d5bb7cf59fcaf43b0784a938da146ce74
parenta870614a5371f8e36676e9bb2e089f4121976135
PCI: Add pci_try_reset_function(), pci_try_reset_slot(), pci_try_reset_bus()

When doing a function/slot/bus reset PCI grabs the device_lock for each
device to block things like suspend and driver probes, but call paths exist
where this lock may already be held.  This creates an opportunity for
deadlock.  For instance, vfio allows userspace to issue resets so long as
it owns the device(s).  If a driver unbind .remove callback races with
userspace issuing a reset, we have a deadlock as userspace gets stuck
waiting on device_lock while another thread has device_lock and waits for
.remove to complete.  To resolve this, we can make a version of the reset
interfaces which use trylock.  With this, we can safely attempt a reset and
return error to userspace if there is contention.

[bhelgaas: the deadlock happens when A (userspace) has a file descriptor for
the device, and B waits in this path:

  driver_detach
    device_lock                     # take device_lock
    __device_release_driver
      pci_device_remove             # pci_bus_type.remove
        vfio_pci_remove             # pci_driver .remove
          vfio_del_group_dev
            wait_event(vfio.release_q, !vfio_dev_present)   # wait (holding device_lock)

Now B is stuck until A gives up the file descriptor.  If A tries to acquire
device_lock for any reason, we deadlock because A is waiting for B to release
the lock, and B is waiting for A to release the file descriptor.]

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
drivers/pci/pci.c
include/linux/pci.h