diff options
| author | Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> | 2009-05-25 20:08:03 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2009-05-27 17:53:07 -0400 |
| commit | dacd2549ca61ddbdd1ed62a76ca95dea3f0e02c6 (patch) | |
| tree | e2369849d60890e3f5596b52346aefc74ce414c5 /drivers | |
| parent | cd86a536c81e9300d984327517548ca0652eebf9 (diff) | |
PCI/ACPI: fix wrong ref count handling in acpi_pci_bind()
The 'dev' field of struct acpi_pci_data is having a pointer to struct
pci_dev without incrementing the reference counter. Because of this, I
got the following kernel oops when I was doing some pci hotplug
operations. This patch fixes this bug by replacing wrong hand-made
pci_find_slot() with pci_get_slot() in acpi_pci_bind().
BUG: unable to handle kernel NULL pointer dereference at 00000000000000e8
IP: [<ffffffff803f0e9b>] acpi_pci_unbind+0xb1/0xdd
Call Trace:
[<ffffffff803ecee4>] acpi_bus_remove+0x54/0x68
[<ffffffff803ecf6d>] acpi_bus_trim+0x75/0xe3
[<ffffffffa0345ddd>] acpiphp_disable_slot+0x16d/0x1e0 [acpiphp]
[<ffffffffa03441f0>] disable_slot+0x20/0x60 [acpiphp]
[<ffffffff803cfc18>] power_write_file+0xc8/0x110
[<ffffffff803c6a54>] pci_slot_attr_store+0x24/0x30
[<ffffffff803469ce>] sysfs_write_file+0xce/0x140
[<ffffffff802e94e7>] vfs_write+0xc7/0x170
[<ffffffff802e9aa0>] sys_write+0x50/0x90
[<ffffffff8020bd6b>] system_call_fastpath+0x16/0x1b
Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Reviewed-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Reviewed-by: Alex Chiang <achiang@hp.com>
Tested-by: Alex Chiang <achiang@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/acpi/pci_bind.c | 24 |
1 files changed, 6 insertions, 18 deletions
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index 95650f83ce2e..bc46de3d967f 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c | |||
| @@ -116,9 +116,6 @@ int acpi_pci_bind(struct acpi_device *device) | |||
| 116 | struct acpi_pci_data *pdata; | 116 | struct acpi_pci_data *pdata; |
| 117 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 117 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
| 118 | acpi_handle handle; | 118 | acpi_handle handle; |
| 119 | struct pci_dev *dev; | ||
| 120 | struct pci_bus *bus; | ||
| 121 | |||
| 122 | 119 | ||
| 123 | if (!device || !device->parent) | 120 | if (!device || !device->parent) |
| 124 | return -EINVAL; | 121 | return -EINVAL; |
| @@ -176,20 +173,9 @@ int acpi_pci_bind(struct acpi_device *device) | |||
| 176 | * Locate matching device in PCI namespace. If it doesn't exist | 173 | * Locate matching device in PCI namespace. If it doesn't exist |
| 177 | * this typically means that the device isn't currently inserted | 174 | * this typically means that the device isn't currently inserted |
| 178 | * (e.g. docking station, port replicator, etc.). | 175 | * (e.g. docking station, port replicator, etc.). |
| 179 | * We cannot simply search the global pci device list, since | ||
| 180 | * PCI devices are added to the global pci list when the root | ||
| 181 | * bridge start ops are run, which may not have happened yet. | ||
| 182 | */ | 176 | */ |
| 183 | bus = pci_find_bus(data->id.segment, data->id.bus); | 177 | data->dev = pci_get_slot(pdata->bus, |
| 184 | if (bus) { | 178 | PCI_DEVFN(data->id.device, data->id.function)); |
| 185 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
| 186 | if (dev->devfn == PCI_DEVFN(data->id.device, | ||
| 187 | data->id.function)) { | ||
| 188 | data->dev = dev; | ||
| 189 | break; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | } | ||
| 193 | if (!data->dev) { | 179 | if (!data->dev) { |
| 194 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 180 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
| 195 | "Device %04x:%02x:%02x.%d not present in PCI namespace\n", | 181 | "Device %04x:%02x:%02x.%d not present in PCI namespace\n", |
| @@ -259,9 +245,10 @@ int acpi_pci_bind(struct acpi_device *device) | |||
| 259 | 245 | ||
| 260 | end: | 246 | end: |
| 261 | kfree(buffer.pointer); | 247 | kfree(buffer.pointer); |
| 262 | if (result) | 248 | if (result) { |
| 249 | pci_dev_put(data->dev); | ||
| 263 | kfree(data); | 250 | kfree(data); |
| 264 | 251 | } | |
| 265 | return result; | 252 | return result; |
| 266 | } | 253 | } |
| 267 | 254 | ||
| @@ -303,6 +290,7 @@ static int acpi_pci_unbind(struct acpi_device *device) | |||
| 303 | if (data->dev->subordinate) { | 290 | if (data->dev->subordinate) { |
| 304 | acpi_pci_irq_del_prt(data->id.segment, data->bus->number); | 291 | acpi_pci_irq_del_prt(data->id.segment, data->bus->number); |
| 305 | } | 292 | } |
| 293 | pci_dev_put(data->dev); | ||
| 306 | kfree(data); | 294 | kfree(data); |
| 307 | 295 | ||
| 308 | end: | 296 | end: |
