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:
Jon Medhurst (Tixy) 2016-01-26 17:59:13 +00:00 committed by Russell King
parent 9a4e7849b5
commit 57480484f9

View File

@ -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);
}