summaryrefslogtreecommitdiff
path: root/drivers/base
diff options
context:
space:
mode:
authorDaniel Stone <daniels@collabora.com>2016-02-08 21:12:58 +0000
committerRussell King <rmk+kernel@arm.linux.org.uk>2016-02-11 09:42:09 +0000
commit8e7199c2c50fff1969302643171eaa33f1ca148f (patch)
tree1eda919447d1599037fc2216ea27682f05953df4 /drivers/base
parent57480484f9f7631738ef28b952eca3c9081c4291 (diff)
component: remove device from master match list on failed add
Calling component_add() may result in the completion of a set of devices, which will try to bring up a master. In bringing the master up, we populate its match array with the current set of children. If binding any of the devices fails, component_add() itself will fail, free the struct component entry, and return to the caller. The now-freed entry is never removed from the master's match array, and will later be used in a futile attempt to bind to freed memory. Bring component_add's behaviour on failure to bring up a master into line with component_del by removing the (to-be-freed) component from the master's match array. The specific case which broke was: - rockchip_drm_drv adds a component master - dwhdmi_rockchip adds a child component in probe (master incomplete) - rockchip_drm_vop adds two children in probe, which completes the set - inside component_add, we try to bring up the master, having populated the master's match array, and fail with EPROBE_DEFER from dwhdmi_rockchip; we delete the putative component - rockchip_drm_vop's probe fails and returns EPROBE_DEFER - we later re-probe rockchip_drm_vop and add the component; the master is complete, so we attempt to bring it up again - walking the match array, we find the previous child, whose master pointer doesn't match (as it has been freed in the meantime) - rockchip_drm_vop probe fails, and will never be attempted again Fixes: ffc30b74fd6d01588bd3fdebc3b1acc0857e6fc8 Signed-off-by: Daniel Stone <daniels@collabora.com> Cc: Russell King <rmk+kernel@arm.linux.org.uk> Cc: Thierry Reding <treding@nvidia.com> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/component.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/drivers/base/component.c b/drivers/base/component.c
index 2738039aae9e..04a1582e80bb 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -491,6 +491,8 @@ int component_add(struct device *dev, const struct component_ops *ops)
ret = try_to_bring_up_masters(component);
if (ret < 0) {
+ if (component->master)
+ remove_component(component->master, component);
list_del(&component->node);
kfree(component);