mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-23 10:35:15 +07:00
regulator: push allocations in create_regulator() outside of lock
Move all allocations outside of the regulator_lock()ed section.
======================================================
WARNING: possible circular locking dependency detected
5.7.13+ #535 Not tainted
------------------------------------------------------
f2fs_discard-179:7/702 is trying to acquire lock:
c0e5d920 (regulator_list_mutex){+.+.}-{3:3}, at: regulator_lock_dependent+0x54/0x2c0
but task is already holding lock:
cb95b080 (&dcc->cmd_lock){+.+.}-{3:3}, at: __issue_discard_cmd+0xec/0x5f8
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
[...]
-> #3 (fs_reclaim){+.+.}-{0:0}:
fs_reclaim_acquire.part.11+0x40/0x50
fs_reclaim_acquire+0x24/0x28
__kmalloc_track_caller+0x54/0x218
kstrdup+0x40/0x5c
create_regulator+0xf4/0x368
regulator_resolve_supply+0x1a0/0x200
regulator_register+0x9c8/0x163c
[...]
other info that might help us debug this:
Chain exists of:
regulator_list_mutex --> &sit_i->sentry_lock --> &dcc->cmd_lock
[...]
Fixes: f8702f9e4a
("regulator: core: Use ww_mutex for regulators locking")
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/6eebc99b2474f4ffaa0405b15178ece0e7e4f608.1597195321.git.mirq-linux@rere.qmqm.pl
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
467bf30142
commit
87fe29b61f
@ -1580,44 +1580,53 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
|
|||||||
const char *supply_name)
|
const char *supply_name)
|
||||||
{
|
{
|
||||||
struct regulator *regulator;
|
struct regulator *regulator;
|
||||||
char buf[REG_STR_SIZE];
|
int err;
|
||||||
int err, size;
|
|
||||||
|
if (dev) {
|
||||||
|
char buf[REG_STR_SIZE];
|
||||||
|
int size;
|
||||||
|
|
||||||
|
size = snprintf(buf, REG_STR_SIZE, "%s-%s",
|
||||||
|
dev->kobj.name, supply_name);
|
||||||
|
if (size >= REG_STR_SIZE)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
supply_name = kstrdup(buf, GFP_KERNEL);
|
||||||
|
if (supply_name == NULL)
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
supply_name = kstrdup_const(supply_name, GFP_KERNEL);
|
||||||
|
if (supply_name == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
regulator = kzalloc(sizeof(*regulator), GFP_KERNEL);
|
regulator = kzalloc(sizeof(*regulator), GFP_KERNEL);
|
||||||
if (regulator == NULL)
|
if (regulator == NULL) {
|
||||||
|
kfree(supply_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
regulator->rdev = rdev;
|
||||||
|
regulator->supply_name = supply_name;
|
||||||
|
|
||||||
regulator_lock(rdev);
|
regulator_lock(rdev);
|
||||||
regulator->rdev = rdev;
|
|
||||||
list_add(®ulator->list, &rdev->consumer_list);
|
list_add(®ulator->list, &rdev->consumer_list);
|
||||||
|
regulator_unlock(rdev);
|
||||||
|
|
||||||
if (dev) {
|
if (dev) {
|
||||||
regulator->dev = dev;
|
regulator->dev = dev;
|
||||||
|
|
||||||
/* Add a link to the device sysfs entry */
|
/* Add a link to the device sysfs entry */
|
||||||
size = snprintf(buf, REG_STR_SIZE, "%s-%s",
|
|
||||||
dev->kobj.name, supply_name);
|
|
||||||
if (size >= REG_STR_SIZE)
|
|
||||||
goto overflow_err;
|
|
||||||
|
|
||||||
regulator->supply_name = kstrdup(buf, GFP_KERNEL);
|
|
||||||
if (regulator->supply_name == NULL)
|
|
||||||
goto overflow_err;
|
|
||||||
|
|
||||||
err = sysfs_create_link_nowarn(&rdev->dev.kobj, &dev->kobj,
|
err = sysfs_create_link_nowarn(&rdev->dev.kobj, &dev->kobj,
|
||||||
buf);
|
supply_name);
|
||||||
if (err) {
|
if (err) {
|
||||||
rdev_dbg(rdev, "could not add device link %s err %d\n",
|
rdev_dbg(rdev, "could not add device link %s err %d\n",
|
||||||
dev->kobj.name, err);
|
dev->kobj.name, err);
|
||||||
/* non-fatal */
|
/* non-fatal */
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
regulator->supply_name = kstrdup_const(supply_name, GFP_KERNEL);
|
|
||||||
if (regulator->supply_name == NULL)
|
|
||||||
goto overflow_err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
regulator->debugfs = debugfs_create_dir(regulator->supply_name,
|
regulator->debugfs = debugfs_create_dir(supply_name,
|
||||||
rdev->debugfs);
|
rdev->debugfs);
|
||||||
if (!regulator->debugfs) {
|
if (!regulator->debugfs) {
|
||||||
rdev_dbg(rdev, "Failed to create debugfs directory\n");
|
rdev_dbg(rdev, "Failed to create debugfs directory\n");
|
||||||
@ -1642,13 +1651,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
|
|||||||
_regulator_is_enabled(rdev))
|
_regulator_is_enabled(rdev))
|
||||||
regulator->always_on = true;
|
regulator->always_on = true;
|
||||||
|
|
||||||
regulator_unlock(rdev);
|
|
||||||
return regulator;
|
return regulator;
|
||||||
overflow_err:
|
|
||||||
list_del(®ulator->list);
|
|
||||||
kfree(regulator);
|
|
||||||
regulator_unlock(rdev);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _regulator_get_enable_time(struct regulator_dev *rdev)
|
static int _regulator_get_enable_time(struct regulator_dev *rdev)
|
||||||
|
Loading…
Reference in New Issue
Block a user