diff options
author | Zhang Yanmin <yanmin.zhang@intel.com> | 2006-06-02 00:35:43 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-21 15:00:01 -0400 |
commit | d71374dafbba7ec3f67371d3b7e9f6310a588808 (patch) | |
tree | 116dcd65fde3701d10fea954cdbd5bb063182b2c /drivers/pci/probe.c | |
parent | 733a7fe12248072e1bca729c88a26298666f1956 (diff) |
[PATCH] PCI: fix race with pci_walk_bus and pci_destroy_dev
pci_walk_bus has a race with pci_destroy_dev. When cb is called
in pci_walk_bus, pci_destroy_dev might unlink the dev pointed by next.
Later on in the next loop, pointer next becomes NULL and cause
kernel panic.
Below patch against 2.6.17-rc4 fixes it by changing pci_bus_lock (spin_lock)
to pci_bus_sem (rw_semaphore).
Signed-off-by: Zhang Yanmin <yanmin.zhang@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r-- | drivers/pci/probe.c | 17 |
1 files changed, 9 insertions, 8 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 27148db06ba0..f89dbc3738b7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -383,9 +383,9 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de | |||
383 | 383 | ||
384 | child = pci_alloc_child_bus(parent, dev, busnr); | 384 | child = pci_alloc_child_bus(parent, dev, busnr); |
385 | if (child) { | 385 | if (child) { |
386 | spin_lock(&pci_bus_lock); | 386 | down_write(&pci_bus_sem); |
387 | list_add_tail(&child->node, &parent->children); | 387 | list_add_tail(&child->node, &parent->children); |
388 | spin_unlock(&pci_bus_lock); | 388 | up_write(&pci_bus_sem); |
389 | } | 389 | } |
390 | return child; | 390 | return child; |
391 | } | 391 | } |
@@ -844,9 +844,9 @@ void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus) | |||
844 | * and the bus list for fixup functions, etc. | 844 | * and the bus list for fixup functions, etc. |
845 | */ | 845 | */ |
846 | INIT_LIST_HEAD(&dev->global_list); | 846 | INIT_LIST_HEAD(&dev->global_list); |
847 | spin_lock(&pci_bus_lock); | 847 | down_write(&pci_bus_sem); |
848 | list_add_tail(&dev->bus_list, &bus->devices); | 848 | list_add_tail(&dev->bus_list, &bus->devices); |
849 | spin_unlock(&pci_bus_lock); | 849 | up_write(&pci_bus_sem); |
850 | } | 850 | } |
851 | 851 | ||
852 | struct pci_dev * __devinit | 852 | struct pci_dev * __devinit |
@@ -981,9 +981,10 @@ struct pci_bus * __devinit pci_create_bus(struct device *parent, | |||
981 | pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); | 981 | pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); |
982 | goto err_out; | 982 | goto err_out; |
983 | } | 983 | } |
984 | spin_lock(&pci_bus_lock); | 984 | |
985 | down_write(&pci_bus_sem); | ||
985 | list_add_tail(&b->node, &pci_root_buses); | 986 | list_add_tail(&b->node, &pci_root_buses); |
986 | spin_unlock(&pci_bus_lock); | 987 | up_write(&pci_bus_sem); |
987 | 988 | ||
988 | memset(dev, 0, sizeof(*dev)); | 989 | memset(dev, 0, sizeof(*dev)); |
989 | dev->parent = parent; | 990 | dev->parent = parent; |
@@ -1023,9 +1024,9 @@ class_dev_create_file_err: | |||
1023 | class_dev_reg_err: | 1024 | class_dev_reg_err: |
1024 | device_unregister(dev); | 1025 | device_unregister(dev); |
1025 | dev_reg_err: | 1026 | dev_reg_err: |
1026 | spin_lock(&pci_bus_lock); | 1027 | down_write(&pci_bus_sem); |
1027 | list_del(&b->node); | 1028 | list_del(&b->node); |
1028 | spin_unlock(&pci_bus_lock); | 1029 | up_write(&pci_bus_sem); |
1029 | err_out: | 1030 | err_out: |
1030 | kfree(dev); | 1031 | kfree(dev); |
1031 | kfree(b); | 1032 | kfree(b); |