dev_add_child is a very unsafe function. If called multiple times it allows setting the same device to different parents thus corrupting the siblings list. This happens regularly since: | commit c2e568d19c5c34a05a1002d25280bf113b72b752 | Author: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@xxxxxxxxxxxx> | Date: Sat Nov 3 16:11:05 2012 +0100 | | bus: add bus device | | automatically add it as parent of any bus device if none already specified | | we have now a nice output per bus If for example a FATfs is mounted this nice output per bus often ends with: > `---- fat0 > `---- 0 > `---- 0x86f0000087020031-0x86f000410df27124: /dev/<NULL> > `---- sram00 > `---- 0x00000000-0xffffffffffffffff: /dev/<NULL> > `---- 0x00000000-0xffffffffffffffff: /dev/<NULL> > unable to handle NULL pointer dereference at address 0x0000000c > pc : [<87f08a20>] lr : [<87f08a04>] > sp : 86eff8c0 ip : 87f3fbde fp : ffffffff > r10: ffffffff r9 : 00000000 r8 : 00000003 > r7 : 86f075b8 r6 : 00000002 r5 : ffffffec r4 : 86f07544 > r3 : 00000000 r2 : 43f900b4 r1 : 00000020 r0 : 00000005 > Flags: Nzcv IRQs off FIQs off Mode SVC_32 > [<87f08a20>] (do_devinfo_subtree+0x90/0x130) from [<87f08a90>] (do_devinfo_subtree+0x100/0x130) > > [<87f3e070>] (unwind_backtrace+0x0/0x90) from [<87f28514>] (panic+0x28/0x3c) > [<87f28514>] (panic+0x28/0x3c) from [<87f3e4b8>] (do_exception+0x10/0x14) > [<87f3e4b8>] (do_exception+0x10/0x14) from [<87f3e544>] (do_data_abort+0x2c/0x38) > [<87f3e544>] (do_data_abort+0x2c/0x38) from [<87f3e268>] (data_abort+0x48/0x60) This patch fixes this by adding a device to its parents children list in register_device so that dev_add_child is no longer needed. This function is removed from the tree. Now callers of register_device have to clearly set the parent *before* registering a device. Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> Reported-by: Jan Lübbe <jlu@xxxxxxxxxxxxxx> --- common/console.c | 2 +- drivers/base/driver.c | 32 +++++++++++--------------------- drivers/i2c/i2c.c | 4 ---- drivers/mci/mci-core.c | 2 +- drivers/mtd/core.c | 4 +--- drivers/net/phy/mdio_bus.c | 4 ---- drivers/net/phy/phy.c | 3 ++- drivers/spi/spi.c | 2 +- drivers/w1/w1.c | 4 ---- fs/fs.c | 2 +- include/driver.h | 5 ----- net/eth.c | 2 +- 12 files changed, 19 insertions(+), 47 deletions(-) diff --git a/common/console.c b/common/console.c index fdd5f42..a085e2d 100644 --- a/common/console.c +++ b/common/console.c @@ -151,7 +151,7 @@ int console_register(struct console_device *newcdev) dev->id = DEVICE_ID_DYNAMIC; strcpy(dev->name, "cs"); if (newcdev->dev) - dev_add_child(newcdev->dev, dev); + dev->parent = newcdev->dev; platform_device_register(dev); if (newcdev->setbrg) { diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 5b3542b..d4066fc 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -133,21 +133,21 @@ int register_device(struct device_d *new_device) INIT_LIST_HEAD(&new_device->parameters); INIT_LIST_HEAD(&new_device->active); - if (!new_device->bus) - return 0; - - if (!new_device->parent) { - new_device->parent = &new_device->bus->dev; - dev_add_child(new_device->parent, new_device); - } + if (new_device->bus) { + if (!new_device->parent) + new_device->parent = &new_device->bus->dev; - list_add_tail(&new_device->bus_list, &new_device->bus->device_list); + list_add_tail(&new_device->bus_list, &new_device->bus->device_list); - bus_for_each_driver(new_device->bus, drv) { - if (!match(drv, new_device)) - break; + bus_for_each_driver(new_device->bus, drv) { + if (!match(drv, new_device)) + break; + } } + if (new_device->parent) + list_add_tail(&new_device->sibling, &new_device->parent->children); + return 0; } EXPORT_SYMBOL(register_device); @@ -186,16 +186,6 @@ int unregister_device(struct device_d *old_dev) } EXPORT_SYMBOL(unregister_device); -int dev_add_child(struct device_d *dev, struct device_d *child) -{ - child->parent = dev; - - list_add_tail(&child->sibling, &dev->children); - - return 0; -} -EXPORT_SYMBOL(dev_add_child); - struct driver_d *get_driver_by_name(const char *name) { struct driver_d *drv; diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index 07eace9..4862df3 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -258,7 +258,6 @@ struct i2c_client *i2c_new_device(struct i2c_adapter *adapter, client->addr = chip->addr; client->dev.parent = &adapter->dev; - dev_add_child(client->dev.parent, &client->dev); status = register_device(&client->dev); @@ -403,9 +402,6 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adapter) adapter->dev.id = adapter->nr; strcpy(adapter->dev.name, "i2c"); - if (adapter->dev.parent) - dev_add_child(adapter->dev.parent, &adapter->dev); - ret = register_device(&adapter->dev); if (ret) return ret; diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c index 88892b6..e29bd2e 100644 --- a/drivers/mci/mci-core.c +++ b/drivers/mci/mci-core.c @@ -1557,7 +1557,7 @@ int mci_register(struct mci_host *host) mci_dev->id = DEVICE_ID_DYNAMIC; strcpy(mci_dev->name, mci_driver.name); mci_dev->platform_data = host; - dev_add_child(host->hw_dev, mci_dev); + mci_dev->parent = host->hw_dev; return platform_device_register(mci_dev); } diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c index b5916da..92b6435 100644 --- a/drivers/mtd/core.c +++ b/drivers/mtd/core.c @@ -184,10 +184,8 @@ int add_mtd_device(struct mtd_info *mtd, char *devname) devname = "mtd"; strcpy(mtd->class_dev.name, devname); mtd->class_dev.id = DEVICE_ID_DYNAMIC; - if (mtd->parent) { + if (mtd->parent) mtd->class_dev.parent = mtd->parent; - dev_add_child(mtd->class_dev.parent, &mtd->class_dev); - } register_device(&mtd->class_dev); mtd->cdev.ops = &mtd_ops; diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 1d20bb0..d1d802b 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -47,8 +47,6 @@ int mdiobus_register(struct mii_bus *bus) bus->dev.id = DEVICE_ID_DYNAMIC; strcpy(bus->dev.name, "miibus"); bus->dev.parent = bus->parent; - if (bus->parent) - dev_add_child(bus->parent, &bus->dev); err = register_device(&bus->dev); if (err) { @@ -157,8 +155,6 @@ static int mdio_bus_probe(struct device_d *_dev) char str[16]; dev->attached_dev->phydev = dev; - dev->dev.parent = &dev->attached_dev->dev; - dev_add_child(dev->dev.parent, _dev); if (drv->probe) { ret = drv->probe(dev); diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 58546f8..9622455 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -157,7 +157,6 @@ static struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int p dev->phy_id = phy_id; dev->bus = bus; - dev->dev.parent = bus->parent; dev->dev.bus = &mdio_bus_type; strcpy(dev->dev.name, "phy"); @@ -229,6 +228,8 @@ static int phy_register_device(struct phy_device* dev) { int ret; + dev->dev.parent = &dev->attached_dev->dev; + ret = register_device(&dev->dev); if (ret) return ret; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 6a5bd6d..d58b664 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -81,7 +81,7 @@ struct spi_device *spi_new_device(struct spi_master *master, proxy->dev.id = DEVICE_ID_DYNAMIC; proxy->dev.type_data = proxy; proxy->dev.device_node = chip->device_node; - dev_add_child(master->dev, &proxy->dev); + proxy->dev.parent = master->dev; /* drivers may modify this initial i/o setup */ status = master->setup(proxy); diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 11b8320..d2f94c9 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -413,7 +413,6 @@ static int w1_device_register(struct w1_bus *bus, struct w1_device *dev) dev->bus = bus; dev->dev.parent = &bus->dev; - dev_add_child(dev->dev.parent, &dev->dev); ret = register_device(&dev->dev); if (ret) @@ -600,10 +599,7 @@ int w1_bus_register(struct w1_bus *bus) strcpy(bus->dev.name, "w1_bus"); bus->dev.id = DEVICE_ID_DYNAMIC; - bus->dev.parent = bus->parent; - if (bus->parent) - dev_add_child(bus->parent, &bus->dev); ret = register_device(&bus->dev); if (ret) diff --git a/fs/fs.c b/fs/fs.c index 4c8c61a..04331fc 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -1227,7 +1227,7 @@ int mount(const char *device, const char *fsname, const char *_path) fsdev->cdev = cdev_by_name(device + 5); if (fsdev->cdev) { - dev_add_child(fsdev->cdev->dev, &fsdev->dev); + fsdev->dev.parent = fsdev->cdev->dev; fsdev->parent_device = fsdev->cdev->dev; } diff --git a/include/driver.h b/include/driver.h index 98df4a1..7ad0374 100644 --- a/include/driver.h +++ b/include/driver.h @@ -158,11 +158,6 @@ int device_probe(struct device_d *dev); */ int unregister_device(struct device_d *); -/* Organize devices in a tree. These functions do _not_ register or - * unregister a device. Only registered devices are allowed here. - */ -int dev_add_child(struct device_d *dev, struct device_d *child); - /* Iterate over a devices children */ #define device_for_each_child(dev, child) \ diff --git a/net/eth.c b/net/eth.c index 101fc10..493ecf9 100644 --- a/net/eth.c +++ b/net/eth.c @@ -260,7 +260,7 @@ int eth_register(struct eth_device *edev) edev->dev.id = DEVICE_ID_DYNAMIC; if (edev->parent) - dev_add_child(edev->parent, &edev->dev); + edev->dev.parent = edev->parent; register_device(&edev->dev); -- 1.7.10.4 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox