diff options
author | Alex Chiang <achiang@hp.com> | 2009-03-30 12:50:19 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-04-06 14:31:14 -0400 |
commit | 72800360fdd782eda3489e555adf3b6b3abc064a (patch) | |
tree | f71284f4081b7b321a0e592f18bdd4b571bf5164 | |
parent | 5d4a4b25ddc3e864d3a562c024bebdc922118854 (diff) |
PCI: pci_slot: grab refcount on slot's bus
If a logical hot unplug (remove) is performed on a physical PCI slot's
parent bridge, and then pci_slot is unloaded, we will encounter an oops:
[<ffffffff803a788a>] kobject_release+0x9a/0x290
[<ffffffff803a77f0>] ? kobject_release+0x0/0x290
[<ffffffff803a8ce7>] kref_put+0x37/0x80
[<ffffffff803a76f7>] kobject_put+0x27/0x60
[<ffffffff803bebcc>] ? pci_destroy_slot+0x3c/0xc0
[<ffffffff803bebd5>] pci_destroy_slot+0x45/0xc0
[<ffffffffa000f05c>] acpi_pci_slot_remove+0x5c/0x91 [pci_slot]
[<ffffffff8040064b>] acpi_pci_unregister_driver+0x4b/0x62
[<ffffffffa000f5c8>] acpi_pci_slot_exit+0x10/0x12 [pci_slot]
[<ffffffff80276ce1>] sys_delete_module+0x161/0x250
We need to grab a reference to the parent PCI bus, which will pin
the bus and prevent it from being released until pci_slot is unloaded.
Cc: lenb@kernel.org
Reviewed-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Tested-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Reported-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Alex Chiang <achiang@hp.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r-- | drivers/acpi/pci_slot.c | 5 |
1 files changed, 5 insertions, 0 deletions
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index cd1f4467be7b..12158e0d009b 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c | |||
@@ -164,6 +164,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
164 | list_add(&slot->list, &slot_list); | 164 | list_add(&slot->list, &slot_list); |
165 | mutex_unlock(&slot_list_lock); | 165 | mutex_unlock(&slot_list_lock); |
166 | 166 | ||
167 | get_device(&pci_bus->dev); | ||
168 | |||
167 | dbg("pci_slot: %p, pci_bus: %x, device: %d, name: %s\n", | 169 | dbg("pci_slot: %p, pci_bus: %x, device: %d, name: %s\n", |
168 | pci_slot, pci_bus->number, device, name); | 170 | pci_slot, pci_bus->number, device, name); |
169 | 171 | ||
@@ -310,12 +312,15 @@ static void | |||
310 | acpi_pci_slot_remove(acpi_handle handle) | 312 | acpi_pci_slot_remove(acpi_handle handle) |
311 | { | 313 | { |
312 | struct acpi_pci_slot *slot, *tmp; | 314 | struct acpi_pci_slot *slot, *tmp; |
315 | struct pci_bus *pbus; | ||
313 | 316 | ||
314 | mutex_lock(&slot_list_lock); | 317 | mutex_lock(&slot_list_lock); |
315 | list_for_each_entry_safe(slot, tmp, &slot_list, list) { | 318 | list_for_each_entry_safe(slot, tmp, &slot_list, list) { |
316 | if (slot->root_handle == handle) { | 319 | if (slot->root_handle == handle) { |
317 | list_del(&slot->list); | 320 | list_del(&slot->list); |
321 | pbus = slot->pci_slot->bus; | ||
318 | pci_destroy_slot(slot->pci_slot); | 322 | pci_destroy_slot(slot->pci_slot); |
323 | put_device(&pbus->dev); | ||
319 | kfree(slot); | 324 | kfree(slot); |
320 | } | 325 | } |
321 | } | 326 | } |