diff options
author | Alex Chiang <achiang@hp.com> | 2009-05-22 00:21:15 +0200 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-05-27 11:04:24 +0200 |
commit | 9d911d7903926a65ef49ec671bacd86bcee5eb51 (patch) | |
tree | b41ef12ea20ae6a040fe1373a958befa07d434db /drivers/pci/hotplug/acpiphp.h | |
parent | PCI PM: Fix initialization and kexec breakage for some devices (diff) | |
download | linux-9d911d7903926a65ef49ec671bacd86bcee5eb51.tar.xz linux-9d911d7903926a65ef49ec671bacd86bcee5eb51.zip |
PCI Hotplug: acpiphp: don't store a pci_dev in acpiphp_func
An oops can occur if a user attempts to use both PCI logical
hotplug and the ACPI physical hotplug driver (acpiphp) in this
sequence, where $slot/address == $device.
In other words, if acpiphp has claimed a PCI device, and that
device is logically removed, then acpiphp may oops when it
attempts to access it again.
# echo 1 > /sys/bus/pci/devices/$device/remove
# echo 0 > /sys/bus/pci/slots/$slot/power
Unable to handle kernel NULL pointer dereference (address 0000000000000000)
Call Trace:
[<a000000100016390>] show_stack+0x50/0xa0
[<a000000100016c60>] show_regs+0x820/0x860
[<a00000010003b390>] die+0x190/0x2a0
[<a000000100066a40>] ia64_do_page_fault+0x8e0/0xa40
[<a00000010000c7a0>] ia64_native_leave_kernel+0x0/0x270
[<a0000001003b2660>] pci_remove_bus_device+0x120/0x260
[<a0000002060549f0>] acpiphp_disable_slot+0x410/0x540 [acpiphp]
[<a0000002060505c0>] disable_slot+0xc0/0x120 [acpiphp]
[<a0000002040d21c0>] power_write_file+0x1e0/0x2a0 [pci_hotplug]
[<a0000001003bb820>] pci_slot_attr_store+0x60/0xa0
[<a000000100240f70>] sysfs_write_file+0x230/0x2c0
[<a000000100195750>] vfs_write+0x190/0x2e0
[<a0000001001961a0>] sys_write+0x80/0x100
[<a00000010000c600>] ia64_ret_from_syscall+0x0/0x20
[<a000000000010720>] __kernel_syscall_via_break+0x0/0x20
The root cause of this oops is that the logical remove ("echo 1 >
/sys/bus/pci/devices/$device/remove") destroyed the pci_dev. The
pci_dev struct itself wasn't deallocated because acpiphp kept a
reference, but some of its fields became invalid.
acpiphp doesn't have any real reason to keep a pointer to a
pci_dev around. It can always derive it using pci_get_slot().
If a logical remove destroys the pci_dev, acpiphp won't find it
and is thus prevented from causing mischief.
Reviewed-by: Matthew Wilcox <willy@linux.intel.com>
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>
Acked-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Alex Chiang <achiang@hp.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/hotplug/acpiphp.h')
-rw-r--r-- | drivers/pci/hotplug/acpiphp.h | 1 |
1 files changed, 0 insertions, 1 deletions
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 4fc168b70095..e68d5f20ffb3 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -129,7 +129,6 @@ struct acpiphp_func { struct acpiphp_bridge *bridge; /* Ejectable PCI-to-PCI bridge */ struct list_head sibling; - struct pci_dev *pci_dev; struct notifier_block nb; acpi_handle handle; |