From: Charles Keepax Date: Thu, 4 Apr 2019 15:32:18 +0000 (+0100) Subject: regulator: core: Avoid potential deadlock on regulator_unregister X-Git-Tag: v5.0.20~133 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=36e250cb89d0dc5ce2cad7c283c9b54aba2e37a0;p=thirdparty%2Fkernel%2Fstable.git regulator: core: Avoid potential deadlock on regulator_unregister [ Upstream commit 063773011d33bb36588a90385aa9eb75d13c6d80 ] Lockdep reports the following issue on my setup: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock((work_completion)(&(&rdev->disable_work)->work)); lock(regulator_list_mutex); lock((work_completion)(&(&rdev->disable_work)->work)); lock(regulator_list_mutex); The problem is that regulator_unregister takes the regulator_list_mutex and then calls flush_work on disable_work. But regulator_disable_work calls regulator_lock_dependent which will also take the regulator_list_mutex. Resulting in a deadlock if the flush_work call actually needs to flush the work. Fix this issue by moving the flush_work outside of the regulator_list_mutex. The list mutex is not used to guard the point at which the delayed work is queued, so its use adds no additional safety. Fixes: f8702f9e4aa7 ("regulator: core: Use ww_mutex for regulators locking") Signed-off-by: Charles Keepax Reviewed-by: Dmitry Osipenko Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index fb9fe26fd0fa1..218b9331475b7 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -5101,10 +5101,11 @@ void regulator_unregister(struct regulator_dev *rdev) regulator_put(rdev->supply); } + flush_work(&rdev->disable_work.work); + mutex_lock(®ulator_list_mutex); debugfs_remove_recursive(rdev->debugfs); - flush_work(&rdev->disable_work.work); WARN_ON(rdev->open_count); regulator_remove_coupling(rdev); unset_regulator_supplies(rdev);