aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Medhurst (Tixy) <tixy@linaro.org>2016-01-26 12:59:13 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2016-01-27 14:07:51 -0500
commit57480484f9f7631738ef28b952eca3c9081c4291 (patch)
treecd79993b4871964d8d8bef8206dde643d9c55c27
parent9a4e7849b5e4e8742d71fa90fbf0722dd0710a56 (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.c41
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}
286EXPORT_SYMBOL(component_match_add_release); 286EXPORT_SYMBOL(component_match_add_release);
287 287
288static 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
288int component_master_add_with_match(struct device *dev, 306int 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}