summaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2012-12-12 14:55:40 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2012-12-12 15:04:27 +0100
commit1a9e93cc81dbae55743c0dafae4bd6ac8241e8a3 (patch)
tree14b39c5b2124e25e4903e497a1bca7867e73d456 /drivers/base
parentc7c9c88cc2acbba29b8cbc9ddcf320857c93134c (diff)
downloadbarebox-1a9e93cc81dbae55743c0dafae4bd6ac8241e8a3.tar.gz
barebox-1a9e93cc81dbae55743c0dafae4bd6ac8241e8a3.tar.xz
drivers/base: fix corrupt device tree
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@jcrosoft.com> | 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@pengutronix.de> Reported-by: Jan Lübbe <jlu@pengutronix.de>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/driver.c32
1 files changed, 11 insertions, 21 deletions
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 5b3542b7d3..d4066fc178 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;