Commit ef83b0781a73f9efcb1228256bfdfb97fc9533a8
Committed by
Bjorn Helgaas
1 parent
ef37702eb3
Exists in
master
and in
16 other branches
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
drivers/pci/probe.c
... | ... | @@ -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 |