Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753653AbcC3QJ0 (ORCPT ); Wed, 30 Mar 2016 12:09:26 -0400 Received: from hqemgate14.nvidia.com ([216.228.121.143]:8444 "EHLO hqemgate14.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752482AbcC3QJZ (ORCPT ); Wed, 30 Mar 2016 12:09:25 -0400 X-PGP-Universal: processed; by hqnvupgp08.nvidia.com on Wed, 30 Mar 2016 09:08:08 -0700 From: Jon Hunter To: Liam Girdwood , Mark Brown , Javier Martinez Canillas CC: linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org, Jon Hunter Subject: [PATCH] regulator: Fix deadlock during regulator registration Date: Wed, 30 Mar 2016 17:09:13 +0100 Message-ID: <1459354153-6352-1-git-send-email-jonathanh@nvidia.com> X-Mailer: git-send-email 2.1.4 X-NVConfidentiality: public MIME-Version: 1.0 Content-Type: text/plain Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5421 Lines: 106 Commit 5e3ca2b349b1 ("regulator: Try to resolve regulators supplies on registration") added a call to regulator_resolve_supply() within regulator_register() where the regulator_list_mutex is held. This causes the following deadlock to occur on the Tegra114 Dalmore board when the palmas PMIC is registered because regulator_register_resolve_supply() calls regulator_dev_lookup() which may try to acquire the regulator_list_mutex again. INFO: task swapper/0:1 blocked for more than 120 seconds. Not tainted 4.6.0-rc1-00001-g5e3ca2b-dirty #290 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. swapper/0 D c07daeac 0 1 0 0x00000000 [] (__schedule) from [] (schedule+0x50/0xc0) [] (schedule) from [] (schedule_preempt_disabled+0x24/0x40) [] (schedule_preempt_disabled) from [] (__mutex_lock_slowpath+0x17c/0x3e4) [] (__mutex_lock_slowpath) from [] (mutex_lock+0xc/0x24) [] (mutex_lock) from [] (regulator_dev_lookup+0x130/0x208) [] (regulator_dev_lookup) from [] (regulator_resolve_supply+0x94/0x2bc) [] (regulator_resolve_supply) from [] (class_for_each_device+0x54/0xa8) [] (class_for_each_device) from [] (regulator_register+0x8cc/0xd10) [] (regulator_register) from [] (devm_regulator_register+0x40/0x74) [] (devm_regulator_register) from [] (palmas_smps_registration+0x254/0x3fc) [] (palmas_smps_registration) from [] (palmas_regulators_probe+0x368/0x424) [] (palmas_regulators_probe) from [] (platform_drv_probe+0x50/0xb0) [] (platform_drv_probe) from [] (driver_probe_device+0x1f4/0x2b0) [] (driver_probe_device) from [] (bus_for_each_drv+0x44/0x8c) [] (bus_for_each_drv) from [] (__device_attach+0x9c/0x100) [] (__device_attach) from [] (bus_probe_device+0x84/0x8c) [] (bus_probe_device) from [] (device_add+0x33c/0x524) [] (device_add) from [] (of_platform_device_create_pdata+0x80/0xc4) [] (of_platform_device_create_pdata) from [] (of_platform_bus_create+0xd0/0x2dc) [] (of_platform_bus_create) from [] (of_platform_populate+0x5c/0xac) [] (of_platform_populate) from [] (palmas_i2c_probe+0x324/0x580) [] (palmas_i2c_probe) from [] (i2c_device_probe+0x140/0x1d0) [] (i2c_device_probe) from [] (driver_probe_device+0x1f4/0x2b0) [] (driver_probe_device) from [] (bus_for_each_drv+0x44/0x8c) [] (bus_for_each_drv) from [] (__device_attach+0x9c/0x100) [] (__device_attach) from [] (bus_probe_device+0x84/0x8c) [] (bus_probe_device) from [] (device_add+0x33c/0x524) [] (device_add) from [] (i2c_new_device+0x14c/0x184) [] (i2c_new_device) from [] (i2c_register_adapter+0x248/0x46c) [] (i2c_register_adapter) from [] (tegra_i2c_probe+0x2d8/0x3bc) [] (tegra_i2c_probe) from [] (platform_drv_probe+0x50/0xb0) [] (platform_drv_probe) from [] (driver_probe_device+0x1f4/0x2b0) [] (driver_probe_device) from [] (__driver_attach+0xac/0xb0) [] (__driver_attach) from [] (bus_for_each_dev+0x54/0x88) [] (bus_for_each_dev) from [] (bus_add_driver+0xe8/0x1f4) [] (bus_add_driver) from [] (driver_register+0x78/0xf4) [] (driver_register) from [] (do_one_initcall+0x84/0x1d4) [] (do_one_initcall) from [] (kernel_init_freeable+0x11c/0x1e8) [] (kernel_init_freeable) from [] (kernel_init+0x8/0x118) [] (kernel_init) from [] (ret_from_fork+0x14/0x3c) Fix this by releasing the mutex before calling regulator_register_resolve_supply() and update the error exit path to ensure the mutex is released on an error. Signed-off-by: Jon Hunter --- Mark, please confirm if it is ok to move the call to release the mutex before calling regulator_register_resolve_supply(). drivers/regulator/core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 74e8a7a3b3e8..2786d251b1cc 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -4000,12 +4000,11 @@ regulator_register(const struct regulator_desc *regulator_desc, } rdev_init_debugfs(rdev); + mutex_unlock(®ulator_list_mutex); /* try to resolve regulators supply since a new one was registered */ class_for_each_device(®ulator_class, NULL, NULL, regulator_register_resolve_supply); -out: - mutex_unlock(®ulator_list_mutex); kfree(config); return rdev; @@ -4016,15 +4015,16 @@ scrub: regulator_ena_gpio_free(rdev); device_unregister(&rdev->dev); /* device core frees rdev */ - rdev = ERR_PTR(ret); goto out; wash: regulator_ena_gpio_free(rdev); clean: kfree(rdev); - rdev = ERR_PTR(ret); - goto out; +out: + mutex_unlock(®ulator_list_mutex); + kfree(config); + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(regulator_register); -- 2.1.4