Pull regulator_list_mutex into set_consumer_device_supply() and keep
allocations outside of it. Fourth of the fs_reclaim deadlock case.

Cc: sta...@vger.kernel.org
Fixes: 45389c47526d ("regulator: core: Add early supply resolution for 
regulators")
Signed-off-by: Michał Mirosław <mirq-li...@rere.qmqm.pl>
---
 drivers/regulator/core.c | 44 +++++++++++++++++++++++-----------------
 1 file changed, 25 insertions(+), 19 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index c95397798275..0408c4e1d9a8 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1445,6 +1445,22 @@ static int set_consumer_device_supply(struct 
regulator_dev *rdev,
        else
                has_dev = 0;
 
+       node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
+       if (node == NULL)
+               return -ENOMEM;
+
+       node->regulator = rdev;
+       node->supply = supply;
+
+       if (has_dev) {
+               node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL);
+               if (node->dev_name == NULL) {
+                       kfree(node);
+                       return -ENOMEM;
+               }
+       }
+
+       mutex_lock(&regulator_list_mutex);
        list_for_each_entry(node, &regulator_map_list, list) {
                if (node->dev_name && consumer_dev_name) {
                        if (strcmp(node->dev_name, consumer_dev_name) != 0)
@@ -1462,26 +1478,19 @@ static int set_consumer_device_supply(struct 
regulator_dev *rdev,
                         node->regulator->desc->name,
                         supply,
                         dev_name(&rdev->dev), rdev_get_name(rdev));
-               return -EBUSY;
-       }
-
-       node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
-       if (node == NULL)
-               return -ENOMEM;
-
-       node->regulator = rdev;
-       node->supply = supply;
-
-       if (has_dev) {
-               node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL);
-               if (node->dev_name == NULL) {
-                       kfree(node);
-                       return -ENOMEM;
-               }
+               goto fail;
        }
 
        list_add(&node->list, &regulator_map_list);
+       mutex_unlock(&regulator_list_mutex);
+
        return 0;
+
+fail:
+       mutex_unlock(&regulator_list_mutex);
+       kfree(node->dev_name);
+       kfree(node);
+       return -EBUSY;
 }
 
 static void unset_regulator_supplies(struct regulator_dev *rdev)
@@ -5239,19 +5248,16 @@ regulator_register(const struct regulator_desc 
*regulator_desc,
 
        /* add consumers devices */
        if (init_data) {
-               mutex_lock(&regulator_list_mutex);
                for (i = 0; i < init_data->num_consumer_supplies; i++) {
                        ret = set_consumer_device_supply(rdev,
                                init_data->consumer_supplies[i].dev_name,
                                init_data->consumer_supplies[i].supply);
                        if (ret < 0) {
-                               mutex_unlock(&regulator_list_mutex);
                                dev_err(dev, "Failed to set supply %s\n",
                                        init_data->consumer_supplies[i].supply);
                                goto unset_supplies;
                        }
                }
-               mutex_unlock(&regulator_list_mutex);
        }
 
        if (!rdev->desc->ops->get_voltage &&
-- 
2.20.1

Reply via email to