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(®ulator_list_mutex); list_for_each_entry(node, ®ulator_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, ®ulator_map_list); + mutex_unlock(®ulator_list_mutex); + return 0; + +fail: + mutex_unlock(®ulator_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(®ulator_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(®ulator_list_mutex); dev_err(dev, "Failed to set supply %s\n", init_data->consumer_supplies[i].supply); goto unset_supplies; } } - mutex_unlock(®ulator_list_mutex); } if (!rdev->desc->ops->get_voltage && -- 2.20.1