Commit 57480484 authored by Jon Medhurst (Tixy)'s avatar Jon Medhurst (Tixy) Committed by Russell King

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: default avatarJon Medhurst <tixy@linaro.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 9a4e7849
...@@ -285,6 +285,24 @@ void component_match_add_release(struct device *master, ...@@ -285,6 +285,24 @@ void component_match_add_release(struct device *master,
} }
EXPORT_SYMBOL(component_match_add_release); 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, int component_master_add_with_match(struct device *dev,
const struct component_master_ops *ops, const struct component_master_ops *ops,
struct component_match *match) struct component_match *match)
...@@ -311,11 +329,9 @@ int component_master_add_with_match(struct device *dev, ...@@ -311,11 +329,9 @@ int component_master_add_with_match(struct device *dev,
ret = try_to_bring_up_master(master, NULL); ret = try_to_bring_up_master(master, NULL);
if (ret < 0) { if (ret < 0)
/* Delete off the list if we weren't successful */ free_master(master);
list_del(&master->node);
kfree(master);
}
mutex_unlock(&component_mutex); mutex_unlock(&component_mutex);
return ret < 0 ? ret : 0; return ret < 0 ? ret : 0;
...@@ -326,25 +342,12 @@ void component_master_del(struct device *dev, ...@@ -326,25 +342,12 @@ void component_master_del(struct device *dev,
const struct component_master_ops *ops) const struct component_master_ops *ops)
{ {
struct master *master; struct master *master;
int i;
mutex_lock(&component_mutex); mutex_lock(&component_mutex);
master = __master_find(dev, ops); master = __master_find(dev, ops);
if (master) { if (master) {
struct component_match *match = master->match;
take_down_master(master); take_down_master(master);
free_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);
} }
mutex_unlock(&component_mutex); mutex_unlock(&component_mutex);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment