Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 57480484 authored by Jon Medhurst (Tixy)'s avatar Jon Medhurst (Tixy) Committed by Russell King
Browse files

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: default avatarJon Medhurst <tixy@linaro.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 9a4e7849
Loading
Loading
Loading
Loading
+22 −19
Original line number Diff line number Diff line
@@ -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);
}