Commit ef83b0781a73f9efcb1228256bfdfb97fc9533a8

Authored by Yinghai Lu
Committed by Bjorn Helgaas
1 parent ef37702eb3

PCI: Remove from bus_list and release resources in pci_release_dev()

Previously we removed the pci_dev from the bus_list and released its
resources in pci_destroy_dev().  But that's too early: it's possible to
call pci_destroy_dev() twice for the same device (e.g., via sysfs), and
that will cause an oops when we try to remove it from bus_list the second
time.

We should remove it from the bus_list only when the last reference to the
pci_dev has been released, i.e., in pci_release_dev().

[bhelgaas: changelog]
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>

Showing 2 changed files with 19 additions and 21 deletions Side-by-side Diff

... ... @@ -1154,6 +1154,18 @@
1154 1154 pci_free_cap_save_buffers(dev);
1155 1155 }
1156 1156  
  1157 +static void pci_free_resources(struct pci_dev *dev)
  1158 +{
  1159 + int i;
  1160 +
  1161 + pci_cleanup_rom(dev);
  1162 + for (i = 0; i < PCI_NUM_RESOURCES; i++) {
  1163 + struct resource *res = dev->resource + i;
  1164 + if (res->parent)
  1165 + release_resource(res);
  1166 + }
  1167 +}
  1168 +
1157 1169 /**
1158 1170 * pci_release_dev - free a pci device structure when all users of it are finished.
1159 1171 * @dev: device that's been disconnected
1160 1172  
... ... @@ -1163,9 +1175,14 @@
1163 1175 */
1164 1176 static void pci_release_dev(struct device *dev)
1165 1177 {
1166   - struct pci_dev *pci_dev;
  1178 + struct pci_dev *pci_dev = to_pci_dev(dev);
1167 1179  
1168   - pci_dev = to_pci_dev(dev);
  1180 + down_write(&pci_bus_sem);
  1181 + list_del(&pci_dev->bus_list);
  1182 + up_write(&pci_bus_sem);
  1183 +
  1184 + pci_free_resources(pci_dev);
  1185 +
1169 1186 pci_release_capabilities(pci_dev);
1170 1187 pci_release_of_node(pci_dev);
1171 1188 pcibios_release_device(pci_dev);
drivers/pci/remove.c
... ... @@ -3,20 +3,6 @@
3 3 #include <linux/pci-aspm.h>
4 4 #include "pci.h"
5 5  
6   -static void pci_free_resources(struct pci_dev *dev)
7   -{
8   - int i;
9   -
10   - msi_remove_pci_irq_vectors(dev);
11   -
12   - pci_cleanup_rom(dev);
13   - for (i = 0; i < PCI_NUM_RESOURCES; i++) {
14   - struct resource *res = dev->resource + i;
15   - if (res->parent)
16   - release_resource(res);
17   - }
18   -}
19   -
20 6 static void pci_stop_dev(struct pci_dev *dev)
21 7 {
22 8 pci_pme_active(dev, false);
... ... @@ -36,11 +22,6 @@
36 22 {
37 23 device_del(&dev->dev);
38 24  
39   - down_write(&pci_bus_sem);
40   - list_del(&dev->bus_list);
41   - up_write(&pci_bus_sem);
42   -
43   - pci_free_resources(dev);
44 25 put_device(&dev->dev);
45 26 }
46 27