PCI: Detach driver before procfs & sysfs teardown on device remove
authorAlex Williamson <alex.williamson@redhat.com>
Wed, 11 Oct 2017 21:35:56 +0000 (15:35 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Dec 2017 09:01:33 +0000 (10:01 +0100)
[ Upstream commit 16b6c8bb687cc3bec914de09061fcb8411951fda ]

When removing a device, for example a VF being removed due to SR-IOV
teardown, a "soft" hot-unplug via 'echo 1 > remove' in sysfs, or an actual
hot-unplug, we first remove the procfs and sysfs attributes for the device
before attempting to release the device from any driver bound to it.
Unbinding the driver from the device can take time.  The device might need
to write out data or it might be actively in use.  If it's in use by
userspace through a vfio driver, the unbind might block until the user
releases the device.  This leads to a potentially non-trivial amount of
time where the device exists, but we've torn down the interfaces that
userspace uses to examine devices, for instance lspci might generate this
sort of error:

  pcilib: Cannot open /sys/bus/pci/devices/0000:01:0a.3/config
  lspci: Unable to read the standard configuration space header of device 0000:01:0a.3

We don't seem to have any dependence on this teardown ordering in the
kernel, so let's unbind the driver first, which is also more symmetric with
the instantiation of the device in pci_bus_add_device().

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/pci/remove.c

index 8bd76c9ba21cf4e5c5a4b58cb40ccd990cfacc5e..edb4e3a83918cbd25ef5a80f56b2141a918656f7 100644 (file)
@@ -20,9 +20,9 @@ static void pci_stop_dev(struct pci_dev *dev)
        pci_pme_active(dev, false);
 
        if (dev->is_added) {
+               device_release_driver(&dev->dev);
                pci_proc_detach_device(dev);
                pci_remove_sysfs_dev_files(dev);
-               device_release_driver(&dev->dev);
                dev->is_added = 0;
        }