diff options
| author | Jon Medhurst (Tixy) <tixy@linaro.org> | 2016-01-26 12:59:13 -0500 |
|---|---|---|
| committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2016-01-27 14:07:51 -0500 |
| commit | 57480484f9f7631738ef28b952eca3c9081c4291 (patch) | |
| tree | cd79993b4871964d8d8bef8206dde643d9c55c27 | |
| parent | 9a4e7849b5e4e8742d71fa90fbf0722dd0710a56 (diff) | |
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>
| -rw-r--r-- | drivers/base/component.c | 41 |
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, | |||
| 285 | } | 285 | } |
| 286 | EXPORT_SYMBOL(component_match_add_release); | 286 | EXPORT_SYMBOL(component_match_add_release); |
| 287 | 287 | ||
| 288 | static void free_master(struct master *master) | ||
| 289 | { | ||
| 290 | struct component_match *match = master->match; | ||
| 291 | int i; | ||
| 292 | |||
| 293 | list_del(&master->node); | ||
| 294 | |||
| 295 | if (match) { | ||
| 296 | for (i = 0; i < match->num; i++) { | ||
| 297 | struct component *c = match->compare[i].component; | ||
| 298 | if (c) | ||
| 299 | c->master = NULL; | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | kfree(master); | ||
| 304 | } | ||
| 305 | |||
| 288 | int component_master_add_with_match(struct device *dev, | 306 | int component_master_add_with_match(struct device *dev, |
| 289 | const struct component_master_ops *ops, | 307 | const struct component_master_ops *ops, |
| 290 | struct component_match *match) | 308 | struct component_match *match) |
| @@ -311,11 +329,9 @@ int component_master_add_with_match(struct device *dev, | |||
| 311 | 329 | ||
| 312 | ret = try_to_bring_up_master(master, NULL); | 330 | ret = try_to_bring_up_master(master, NULL); |
| 313 | 331 | ||
| 314 | if (ret < 0) { | 332 | if (ret < 0) |
| 315 | /* Delete off the list if we weren't successful */ | 333 | free_master(master); |
| 316 | list_del(&master->node); | 334 | |
| 317 | kfree(master); | ||
| 318 | } | ||
| 319 | mutex_unlock(&component_mutex); | 335 | mutex_unlock(&component_mutex); |
| 320 | 336 | ||
| 321 | return ret < 0 ? ret : 0; | 337 | return ret < 0 ? ret : 0; |
| @@ -326,25 +342,12 @@ void component_master_del(struct device *dev, | |||
| 326 | const struct component_master_ops *ops) | 342 | const struct component_master_ops *ops) |
| 327 | { | 343 | { |
| 328 | struct master *master; | 344 | struct master *master; |
| 329 | int i; | ||
| 330 | 345 | ||
| 331 | mutex_lock(&component_mutex); | 346 | mutex_lock(&component_mutex); |
| 332 | master = __master_find(dev, ops); | 347 | master = __master_find(dev, ops); |
| 333 | if (master) { | 348 | if (master) { |
| 334 | struct component_match *match = master->match; | ||
| 335 | |||
| 336 | take_down_master(master); | 349 | take_down_master(master); |
| 337 | 350 | free_master(master); | |
| 338 | list_del(&master->node); | ||
| 339 | |||
| 340 | if (match) { | ||
| 341 | for (i = 0; i < match->num; i++) { | ||
| 342 | struct component *c = match->compare[i].component; | ||
| 343 | if (c) | ||
| 344 | c->master = NULL; | ||
| 345 | } | ||
| 346 | } | ||
| 347 | kfree(master); | ||
| 348 | } | 351 | } |
| 349 | mutex_unlock(&component_mutex); | 352 | mutex_unlock(&component_mutex); |
| 350 | } | 353 | } |
