From mboxrd@z Thu Jan 1 00:00:00 1970 From: Andrew Morton Date: Thu, 08 Feb 2001 13:45:04 +0000 Subject: Re: OOPS in 2.4.0-pre9 -- NULL pointer dereference in pci_insert_device Message-Id: List-Id: References: In-Reply-To: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: linux-hotplug@vger.kernel.org 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