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>
---
v2: fix new node leak reported kernel test robot <l...@intel.com>
---
 drivers/regulator/core.c | 46 +++++++++++++++++++++++-----------------
 1 file changed, 26 insertions(+), 20 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index c95397798275..71749f48caee 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1434,7 +1434,7 @@ static int set_consumer_device_supply(struct 
regulator_dev *rdev,
                                      const char *consumer_dev_name,
                                      const char *supply)
 {
-       struct regulator_map *node;
+       struct regulator_map *node, *new_node;
        int has_dev;
 
        if (supply == NULL)
@@ -1445,6 +1445,22 @@ static int set_consumer_device_supply(struct 
regulator_dev *rdev,
        else
                has_dev = 0;
 
+       new_node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
+       if (new_node == NULL)
+               return -ENOMEM;
+
+       new_node->regulator = rdev;
+       new_node->supply = supply;
+
+       if (has_dev) {
+               new_node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL);
+               if (new_node->dev_name == NULL) {
+                       kfree(new_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;
+               goto fail;
        }
 
-       node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
-       if (node == NULL)
-               return -ENOMEM;
+       list_add(&new_node->list, &regulator_map_list);
+       mutex_unlock(&regulator_list_mutex);
 
-       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;
-               }
-       }
-
-       list_add(&node->list, &regulator_map_list);
        return 0;
+
+fail:
+       mutex_unlock(&regulator_list_mutex);
+       kfree(new_node->dev_name);
+       kfree(new_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