* Re: OOPS in 2.4.0-pre9 -- NULL pointer dereference in pci_insert_device
2001-01-26 23:37 OOPS in 2.4.0-pre9 -- NULL pointer dereference in pci_insert_device Miles Lane
2001-01-27 12:33 ` Andrew Morton
@ 2001-02-08 13:45 ` Andrew Morton
1 sibling, 0 replies; 3+ messages in thread
From: Andrew Morton @ 2001-02-08 13:45 UTC (permalink / raw)
To: linux-hotplug
Miles Lane wrote:
>
> Andrew Morton wrote:
>
> > Miles Lane wrote:
> >
> >> This highly reproducible OOPS gets triggered when I insert my
> >> Belkin BusPort Mobile after booting the machine with no other
> >> PC Cards inserted.
> >>
> >
> >
> > I really can't work that trace out. Are you sure it's
> > correct? System.map kosher, etc?
>
> Hi Andrew,
>
> I am adding Linus to the TO:, since this problem may be in his
> yenta code.
I took him off again :) Let's suprise him when we have a fix.
I suspect it's a broken driver and not yenta.
> I'm really not sure what why the OOPS I sent was bogus.
> Perhaps these new OOPS traces will be more useful. I hope so!
Yep. The PCI driver list has become corrupted. The bug
probably happened waaay before the oops, so we need to
find out who did this. It can happen if a driver fails
to unregister itself and then gets unloaded. Ten seconds
later, boom.
Please try this patch. It just checks the sanity of
the PCI driver list where ever it's touched, and also
immediately prior to module unload.
It's against 2.4.2-pre1. Hopefully it'll apply to
Alan's kernel. If the patch finds something, please
feed through ksymooops.
--- linux-2.4.2-pre1/kernel/module.c Tue Nov 28 12:38:07 2000
+++ lk/kernel/module.c Fri Feb 9 00:29:00 2001
@@ -1052,6 +1052,9 @@
/* And free the memory. */
+ memset(mod, 0, mod->size);
+#define CHECK_PCI_DRIVERS() check_pci_drivers(__FUNCTION__, __LINE__)
+ CHECK_PCI_DRIVERS();
module_unmap(mod);
}
--- linux-2.4.2-pre1/drivers/pci/pci.c Tue Dec 12 08:46:26 2000
+++ lk/drivers/pci/pci.c Fri Feb 9 00:18:02 2001
@@ -36,6 +36,21 @@
LIST_HEAD(pci_root_buses);
LIST_HEAD(pci_devices);
+static LIST_HEAD(pci_drivers);
+
+#define CHECK_PCI_DRIVERS() check_pci_drivers(__FUNCTION__, __LINE__)
+
+void check_pci_drivers(const char *who, int where)
+{
+ struct list_head *ln;
+ for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {
+ struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
+ if (drv = 0) {
+ printk("PCI driver list corrupted in %s:%d\n", who, where);
+ show_trace(0);
+ }
+ }
+}
/**
* pci_find_slot - locate PCI device from a given PCI slot
@@ -52,6 +67,7 @@
{
struct pci_dev *dev;
+ CHECK_PCI_DRIVERS();
pci_for_each_dev(dev) {
if (dev->bus->number = bus && dev->devfn = devfn)
return dev;
@@ -67,6 +83,7 @@
{
struct list_head *n = from ? from->global_list.next : pci_devices.next;
+ CHECK_PCI_DRIVERS();
while (n != &pci_devices) {
struct pci_dev *dev = pci_dev_g(n);
if ((vendor = PCI_ANY_ID || dev->vendor = vendor) &&
@@ -117,6 +134,7 @@
{
struct list_head *n = from ? from->global_list.next : pci_devices.next;
+ CHECK_PCI_DRIVERS();
while (n != &pci_devices) {
struct pci_dev *dev = pci_dev_g(n);
if (dev->class = class)
@@ -134,6 +152,7 @@
u8 pos, id;
int ttl = 48;
+ CHECK_PCI_DRIVERS();
pci_read_config_word(dev, PCI_STATUS, &status);
if (!(status & PCI_STATUS_CAP_LIST))
return 0;
@@ -177,6 +196,7 @@
int i;
struct resource *best = NULL;
+ CHECK_PCI_DRIVERS();
for(i=0; i<4; i++) {
struct resource *r = bus->resource[i];
if (!r)
@@ -252,6 +272,7 @@
{
int err;
+ CHECK_PCI_DRIVERS();
if ((err = pcibios_enable_device(dev)) < 0)
return err;
pci_set_power_state(dev, 0);
@@ -263,6 +284,7 @@
{
u8 pin;
+ CHECK_PCI_DRIVERS();
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin)
return -1;
@@ -279,8 +301,6 @@
* Registration of PCI drivers and handling of hot-pluggable devices.
*/
-static LIST_HEAD(pci_drivers);
-
const struct pci_device_id *
pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev)
{
@@ -302,6 +322,7 @@
const struct pci_device_id *id;
int ret = 0;
+ CHECK_PCI_DRIVERS();
if (drv->id_table) {
id = pci_match_device(drv->id_table, dev);
if (!id) {
@@ -312,10 +333,12 @@
id = NULL;
dev_probe_lock();
+ CHECK_PCI_DRIVERS();
if (drv->probe(dev, id) >= 0) {
dev->driver = drv;
ret = 1;
}
+ CHECK_PCI_DRIVERS();
dev_probe_unlock();
out:
return ret;
@@ -327,11 +350,13 @@
struct pci_dev *dev;
int count = 0;
+ CHECK_PCI_DRIVERS();
list_add_tail(&drv->node, &pci_drivers);
pci_for_each_dev(dev) {
if (!pci_dev_driver(dev))
count += pci_announce_device(drv, dev);
}
+ CHECK_PCI_DRIVERS();
return count;
}
@@ -340,14 +365,19 @@
{
struct pci_dev *dev;
+ CHECK_PCI_DRIVERS();
list_del(&drv->node);
pci_for_each_dev(dev) {
if (dev->driver = drv) {
- if (drv->remove)
+ if (drv->remove) {
+ CHECK_PCI_DRIVERS();
drv->remove(dev);
+ CHECK_PCI_DRIVERS();
+ }
dev->driver = NULL;
}
}
+ CHECK_PCI_DRIVERS();
}
#ifdef CONFIG_HOTPLUG
@@ -393,7 +423,9 @@
envp[i++] = "ACTION=remove";
envp[i] = 0;
+ CHECK_PCI_DRIVERS();
call_usermodehelper (argv [0], argv, envp);
+ CHECK_PCI_DRIVERS();
}
void
@@ -401,6 +433,7 @@
{
struct list_head *ln;
+ CHECK_PCI_DRIVERS();
list_add_tail(&dev->bus_list, &bus->devices);
list_add_tail(&dev->global_list, &pci_devices);
#ifdef CONFIG_PROC_FS
@@ -408,6 +441,10 @@
#endif
for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {
struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
+ if (drv = 0) {
+ printk("oops avoided\n");
+ return;
+ }
if (drv->remove && pci_announce_device(drv, dev))
break;
}
@@ -421,21 +458,25 @@
{
int i;
+ CHECK_PCI_DRIVERS();
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *res = dev->resource + i;
if (res->parent)
release_resource(res);
}
+ CHECK_PCI_DRIVERS();
}
void
pci_remove_device(struct pci_dev *dev)
{
+ CHECK_PCI_DRIVERS();
if (dev->driver) {
if (dev->driver->remove)
dev->driver->remove(dev);
dev->driver = NULL;
}
+ CHECK_PCI_DRIVERS();
list_del(&dev->bus_list);
list_del(&dev->global_list);
pci_free_resources(dev);
@@ -1072,21 +1113,25 @@
*/
static int pci_pm_suspend_device(struct pci_dev *dev)
{
+ CHECK_PCI_DRIVERS();
if (dev) {
struct pci_driver *driver = dev->driver;
if (driver && driver->suspend)
driver->suspend(dev);
}
+ CHECK_PCI_DRIVERS();
return 0;
}
static int pci_pm_resume_device(struct pci_dev *dev)
{
+ CHECK_PCI_DRIVERS();
if (dev) {
struct pci_driver *driver = dev->driver;
if (driver && driver->resume)
driver->resume(dev);
}
+ CHECK_PCI_DRIVERS();
return 0;
}
_______________________________________________
Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
http://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel
^ permalink raw reply [flat|nested] 3+ messages in thread