diff options
author | Yinghai Lu <yinghai@kernel.org> | 2013-11-30 17:40:29 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2013-12-18 15:53:40 -0500 |
commit | ef83b0781a73f9efcb1228256bfdfb97fc9533a8 (patch) | |
tree | 01c8a9940789bfcef622006d9d8eb26fd4ab0ce6 | |
parent | ef37702eb3cae2ec35d56ddd4f096cd47fec3f0d (diff) |
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>
-rw-r--r-- | drivers/pci/probe.c | 21 | ||||
-rw-r--r-- | drivers/pci/remove.c | 19 |
2 files changed, 19 insertions, 21 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 173a9cf4593e..12ec56c9a913 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -1154,6 +1154,18 @@ static void pci_release_capabilities(struct pci_dev *dev) | |||
1154 | pci_free_cap_save_buffers(dev); | 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 | * pci_release_dev - free a pci device structure when all users of it are finished. | 1170 | * pci_release_dev - free a pci device structure when all users of it are finished. |
1159 | * @dev: device that's been disconnected | 1171 | * @dev: device that's been disconnected |
@@ -1163,9 +1175,14 @@ static void pci_release_capabilities(struct pci_dev *dev) | |||
1163 | */ | 1175 | */ |
1164 | static void pci_release_dev(struct device *dev) | 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); |
1179 | |||
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); | ||
1167 | 1185 | ||
1168 | pci_dev = to_pci_dev(dev); | ||
1169 | pci_release_capabilities(pci_dev); | 1186 | pci_release_capabilities(pci_dev); |
1170 | pci_release_of_node(pci_dev); | 1187 | pci_release_of_node(pci_dev); |
1171 | pcibios_release_device(pci_dev); | 1188 | pcibios_release_device(pci_dev); |
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 692f4c39ac48..f452148e6d55 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c | |||
@@ -3,20 +3,6 @@ | |||
3 | #include <linux/pci-aspm.h> | 3 | #include <linux/pci-aspm.h> |
4 | #include "pci.h" | 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 | static void pci_stop_dev(struct pci_dev *dev) | 6 | static void pci_stop_dev(struct pci_dev *dev) |
21 | { | 7 | { |
22 | pci_pme_active(dev, false); | 8 | pci_pme_active(dev, false); |
@@ -36,11 +22,6 @@ static void pci_destroy_dev(struct pci_dev *dev) | |||
36 | { | 22 | { |
37 | device_del(&dev->dev); | 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 | put_device(&dev->dev); | 25 | put_device(&dev->dev); |
45 | } | 26 | } |
46 | 27 | ||