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>
This commit is contained in:
parent
9a4e7849b5
commit
57480484f9
@ -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,
|
|||||||
|
|
||||||
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,
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user