mirror of https://gitee.com/openkylin/linux.git
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue