summaryrefslogtreecommitdiffstats
path: root/drivers/base/component.c
diff options
context:
space:
mode:
authorJon Medhurst (Tixy) <tixy@linaro.org>2016-01-26 18:59:13 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2016-01-27 20:07:51 +0100
commit57480484f9f7631738ef28b952eca3c9081c4291 (patch)
treecd79993b4871964d8d8bef8206dde643d9c55c27 /drivers/base/component.c
parentcomponent: fix crash on x86_64 with hda audio drivers (diff)
downloadlinux-57480484f9f7631738ef28b952eca3c9081c4291.tar.xz
linux-57480484f9f7631738ef28b952eca3c9081c4291.zip
component: Detach components when deleting master struct
component_master_add_with_match calls find_components which, if any components already exist, it attaches to the master struct. However, if we later encounter an error the master struct is deleted, leaving components with a dangling pointer to it. If the error was a temporary one, e.g. for probe deferral, then when the master device is re-probed, it will fail to find the required components as they appear to already be attached to a master. Fix this by nulling components pointers to the master struct when it is deleted. This code is factored out into a separate function so it can be shared with component_master_del. Signed-off-by: Jon Medhurst <tixy@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/base/component.c')
-rw-r--r--drivers/base/component.c41
1 files changed, 22 insertions, 19 deletions
diff --git a/drivers/base/component.c b/drivers/base/component.c
index 05cd26c02449..2738039aae9e 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -285,6 +285,24 @@ void component_match_add_release(struct device *master,
}
EXPORT_SYMBOL(component_match_add_release);
+static void free_master(struct master *master)
+{
+ struct component_match *match = master->match;
+ int i;
+
+ list_del(&master->node);
+
+ if (match) {
+ for (i = 0; i < match->num; i++) {
+ struct component *c = match->compare[i].component;
+ if (c)
+ c->master = NULL;
+ }
+ }
+
+ kfree(master);
+}
+
int component_master_add_with_match(struct device *dev,
const struct component_master_ops *ops,
struct component_match *match)
@@ -311,11 +329,9 @@ int component_master_add_with_match(struct device *dev,
ret = try_to_bring_up_master(master, NULL);
- if (ret < 0) {
- /* Delete off the list if we weren't successful */
- list_del(&master->node);
- kfree(master);
- }
+ if (ret < 0)
+ free_master(master);
+
mutex_unlock(&component_mutex);
return ret < 0 ? ret : 0;
@@ -326,25 +342,12 @@ void component_master_del(struct device *dev,
const struct component_master_ops *ops)
{
struct master *master;
- int i;
mutex_lock(&component_mutex);
master = __master_find(dev, ops);
if (master) {
- struct component_match *match = master->match;
-
take_down_master(master);
-
- list_del(&master->node);
-
- if (match) {
- for (i = 0; i < match->num; i++) {
- struct component *c = match->compare[i].component;
- if (c)
- c->master = NULL;
- }
- }
- kfree(master);
+ free_master(master);
}
mutex_unlock(&component_mutex);
}