Skip to content

Commit

Permalink
PCI: Stop all children first, before removing all children
Browse files Browse the repository at this point in the history
This restores the previous behavior of stopping all child devices before
removing any of them.  The current SR-IOV design, where removing the PF
also drops references on all the VFs, depends on having the VFs continue
to exist after having been stopped.

[bhelgaas: changelog]
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
  • Loading branch information
Yinghai Lu authored and Bjorn Helgaas committed Sep 20, 2012
1 parent 94bb346 commit 3891b6a
Showing 1 changed file with 35 additions and 16 deletions.
51 changes: 35 additions & 16 deletions drivers/pci/remove.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,39 +56,58 @@ void pci_remove_bus(struct pci_bus *bus)
}
EXPORT_SYMBOL(pci_remove_bus);

/**
* pci_stop_and_remove_bus_device - remove a PCI device and any children
* @dev: the device to remove
*
* Remove a PCI device from the device lists, informing the drivers
* that the device has been removed. We also remove any subordinate
* buses and children in a depth-first manner.
*
* For each device we remove, delete the device structure from the
* device lists, remove the /proc entry, and notify userspace
* (/sbin/hotplug).
*/
void pci_stop_and_remove_bus_device(struct pci_dev *dev)
static void pci_stop_bus_device(struct pci_dev *dev)
{
struct pci_bus *bus = dev->subordinate;
struct pci_dev *child, *tmp;

/*
* Removing an SR-IOV PF device removes all the associated VFs,
* Stopping an SR-IOV PF device removes all the associated VFs,
* which will update the bus->devices list and confuse the
* iterator. Therefore, iterate in reverse so we remove the VFs
* first, then the PF.
*/
if (bus) {
list_for_each_entry_safe_reverse(child, tmp,
&bus->devices, bus_list)
pci_stop_and_remove_bus_device(child);
pci_stop_bus_device(child);
}

pci_stop_dev(dev);
}

static void pci_remove_bus_device(struct pci_dev *dev)
{
struct pci_bus *bus = dev->subordinate;
struct pci_dev *child, *tmp;

if (bus) {
list_for_each_entry_safe(child, tmp,
&bus->devices, bus_list)
pci_remove_bus_device(child);

pci_remove_bus(bus);
dev->subordinate = NULL;
}

pci_stop_dev(dev);
pci_destroy_dev(dev);
}

/**
* pci_stop_and_remove_bus_device - remove a PCI device and any children
* @dev: the device to remove
*
* Remove a PCI device from the device lists, informing the drivers
* that the device has been removed. We also remove any subordinate
* buses and children in a depth-first manner.
*
* For each device we remove, delete the device structure from the
* device lists, remove the /proc entry, and notify userspace
* (/sbin/hotplug).
*/
void pci_stop_and_remove_bus_device(struct pci_dev *dev)
{
pci_stop_bus_device(dev);
pci_remove_bus_device(dev);
}
EXPORT_SYMBOL(pci_stop_and_remove_bus_device);

0 comments on commit 3891b6a

Please sign in to comment.