diff --git a/drivers/base/component.c b/drivers/base/component.c
index f748430bb654..d72fe9bc7033 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -30,7 +30,10 @@ struct component_match {
 struct master {
 	struct list_head node;
 	struct list_head components;
+	struct kref kref;
+	struct mutex mutex;
 	bool bound;
+	bool dead;
 
 	const struct component_master_ops *ops;
 	struct device *dev;
@@ -49,8 +52,33 @@ struct component {
 
 static DEFINE_MUTEX(component_mutex);
 static LIST_HEAD(component_list);
+static DEFINE_MUTEX(master_mutex);
 static LIST_HEAD(masters);
 
+static void master_release(struct kref *kref) __releases(master_mutex)
+{
+	struct master *master = container_of(kref, struct master, kref);
+
+	list_del(&master->node);
+	mutex_unlock(&master_mutex);
+	WARN_ON(!list_empty(&master->components));
+	kfree(master);
+}
+
+static void master_release_nolock(struct kref *kref)
+{
+	struct master *master = container_of(kref, struct master, kref);
+
+	list_del(&master->node);
+	WARN_ON(!list_empty(&master->components));
+	kfree(master);
+}
+
+static void master_norelease(struct kref *kref)
+{
+	WARN_ON(kref);
+}
+
 static struct master *__master_find(struct device *dev,
 	const struct component_master_ops *ops)
 {
@@ -63,9 +91,30 @@ static struct master *__master_find(struct device *dev,
 	return NULL;
 }
 
+/*
+ * Find the master structure for this device, and make sure that the
+ * per-master lock is held.  This is used from within the master device
+ * drivers bind and unbind callbacks, which should only be called from
+ * paths where the per-master lock is already held.
+ */
+static struct master *master_find_locked(struct device *dev,
+	const struct component_master_ops *ops)
+{
+	struct master *master;
+
+	mutex_lock(&master_mutex);
+	master = __master_find(dev, NULL);
+	WARN_ON(master && !mutex_is_locked(&master->mutex));
+	mutex_unlock(&master_mutex);
+
+	return master;
+}
+
 /* Attach an unattached component to a master. */
 static void component_attach_master(struct master *master, struct component *c)
 {
+	kref_get(&master->kref);
+
 	c->master = master;
 
 	list_add_tail(&c->master_node, &master->components);
@@ -77,6 +126,9 @@ static void component_detach_master(struct master *master, struct component *c)
 	list_del(&c->master_node);
 
 	c->master = NULL;
+
+	/* This kref_put should never release the master */
+	kref_put(&master->kref, master_norelease);
 }
 
 /*
@@ -90,6 +142,7 @@ int component_master_add_child(struct master *master,
 	struct component *c;
 	int ret = -ENXIO;
 
+	mutex_lock(&component_mutex);
 	list_for_each_entry(c, &component_list, node) {
 		if (c->master && c->master != master)
 			continue;
@@ -101,6 +154,7 @@ int component_master_add_child(struct master *master,
 			break;
 		}
 	}
+	mutex_unlock(&component_mutex);
 
 	return ret;
 }
@@ -137,6 +191,7 @@ static int find_components(struct master *master)
 /* Detach all attached components from this master */
 static void master_remove_components(struct master *master)
 {
+	mutex_lock(&component_mutex);
 	while (!list_empty(&master->components)) {
 		struct component *c = list_first_entry(&master->components,
 					struct component, master_node);
@@ -145,6 +200,7 @@ static void master_remove_components(struct master *master)
 
 		component_detach_master(master, c);
 	}
+	mutex_unlock(&component_mutex);
 }
 
 /*
@@ -201,20 +257,43 @@ static int try_to_bring_up_master(struct master *master,
 
 static int try_to_bring_up_masters(struct component *component)
 {
-	struct master *m;
+	struct master *m, *last = NULL;
 	int ret = 0;
 
+	mutex_lock(&master_mutex);
 	list_for_each_entry(m, &masters, node) {
+		if (last) {
+			kref_put(&last->kref, master_release_nolock);
+			last = NULL;
+		}
+
+		if (m->dead || m->bound)
+			continue;
+
+		kref_get(&m->kref);
+		mutex_unlock(&master_mutex);
+
+		mutex_lock(&m->mutex);
 		ret = try_to_bring_up_master(m, component);
+		mutex_unlock(&m->mutex);
+
+		mutex_lock(&master_mutex);
+		last = m;
+
 		if (ret != 0)
 			break;
 	}
 
+	if (last)
+		kref_put(&last->kref, master_release_nolock);
+	mutex_unlock(&master_mutex);
+
 	return ret;
 }
 
 static void take_down_master(struct master *master)
 {
+	mutex_lock(&master->mutex);
 	if (master->bound) {
 		master->ops->unbind(master->dev);
 		devres_release_group(master->dev, NULL);
@@ -222,6 +301,7 @@ static void take_down_master(struct master *master)
 	}
 
 	master_remove_components(master);
+	mutex_unlock(&master->mutex);
 }
 
 static size_t component_match_size(size_t num)
@@ -307,20 +387,25 @@ int component_master_add_with_match(struct device *dev,
 	master->dev = dev;
 	master->ops = ops;
 	master->match = match;
+	mutex_init(&master->mutex);
 	INIT_LIST_HEAD(&master->components);
+	kref_init(&master->kref);
 
-	/* Add to the list of available masters. */
-	mutex_lock(&component_mutex);
+	/*
+	 * Add to the list of available masters.  This is so
+	 * the component code below can find this master.
+	 */
+	mutex_lock(&master_mutex);
 	list_add(&master->node, &masters);
+	mutex_unlock(&master_mutex);
 
+	mutex_lock(&master->mutex);
 	ret = try_to_bring_up_master(master, NULL);
+	mutex_unlock(&master->mutex);
 
-	if (ret < 0) {
-		/* Delete off the list if we weren't successful */
-		list_del(&master->node);
-		kfree(master);
-	}
-	mutex_unlock(&component_mutex);
+	/* Delete off the list if we weren't successful */
+	if (ret < 0)
+		kref_put_mutex(&master->kref, master_release, &master_mutex);
 
 	return ret < 0 ? ret : 0;
 }
@@ -338,15 +423,17 @@ void component_master_del(struct device *dev,
 {
 	struct master *master;
 
-	mutex_lock(&component_mutex);
+	mutex_lock(&master_mutex);
 	master = __master_find(dev, ops);
+	if (master)
+		master->dead = true;
+	mutex_unlock(&master_mutex);
+
 	if (master) {
 		take_down_master(master);
 
-		list_del(&master->node);
-		kfree(master);
+		kref_put_mutex(&master->kref, master_release, &master_mutex);
 	}
-	mutex_unlock(&component_mutex);
 }
 EXPORT_SYMBOL_GPL(component_master_del);
 
@@ -364,12 +451,9 @@ static void component_unbind(struct component *component,
 
 void component_unbind_all(struct device *master_dev, void *data)
 {
-	struct master *master;
+	struct master *master = master_find_locked(master_dev, NULL);
 	struct component *c;
 
-	WARN_ON(!mutex_is_locked(&component_mutex));
-
-	master = __master_find(master_dev, NULL);
 	if (!master)
 		return;
 
@@ -432,13 +516,10 @@ static int component_bind(struct component *component, struct master *master,
 
 int component_bind_all(struct device *master_dev, void *data)
 {
-	struct master *master;
+	struct master *master = master_find_locked(master_dev, NULL);
 	struct component *c;
 	int ret = 0;
 
-	WARN_ON(!mutex_is_locked(&component_mutex));
-
-	master = __master_find(master_dev, NULL);
 	if (!master)
 		return -EINVAL;
 
@@ -474,14 +555,16 @@ int component_add(struct device *dev, const struct component_ops *ops)
 
 	mutex_lock(&component_mutex);
 	list_add_tail(&component->node, &component_list);
+	mutex_unlock(&component_mutex);
 
 	ret = try_to_bring_up_masters(component);
 	if (ret < 0) {
+		mutex_lock(&component_mutex);
 		list_del(&component->node);
+		mutex_unlock(&component_mutex);
 
 		kfree(component);
 	}
-	mutex_unlock(&component_mutex);
 
 	return ret < 0 ? ret : 0;
 }
@@ -490,21 +573,28 @@ EXPORT_SYMBOL_GPL(component_add);
 void component_del(struct device *dev, const struct component_ops *ops)
 {
 	struct component *c, *component = NULL;
+	struct master *master = NULL;
 
 	mutex_lock(&component_mutex);
 	list_for_each_entry(c, &component_list, node)
 		if (c->dev == dev && c->ops == ops) {
+			master = c->master;
+			if (master)
+				kref_get(&master->kref);
 			list_del(&c->node);
 			component = c;
 			break;
 		}
+	mutex_unlock(&component_mutex);
 
-	if (component && component->master)
-		take_down_master(component->master);
+	if (WARN_ON(!component))
+		return;
 
-	mutex_unlock(&component_mutex);
+	if (master) {
+		take_down_master(master);
+		kref_put_mutex(&master->kref, master_release, &master_mutex);
+	}
 
-	WARN_ON(!component);
 	kfree(component);
 }
 EXPORT_SYMBOL_GPL(component_del);
