| From 73a32129f8ccb556704a26b422f54e048bf14bd0 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= <mirq-linux@rere.qmqm.pl> |
| Date: Wed, 12 Aug 2020 03:31:34 +0200 |
| Subject: [PATCH] regulator: push allocation in regulator_init_coupling() |
| outside of lock |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| commit 73a32129f8ccb556704a26b422f54e048bf14bd0 upstream. |
| |
| Allocating memory with regulator_list_mutex held makes lockdep unhappy |
| when memory pressure makes the system do fs_reclaim on eg. eMMC using |
| a regulator. Push the lock inside regulator_init_coupling() after the |
| allocation. |
| |
| ====================================================== |
| WARNING: possible circular locking dependency detected |
| 5.7.13+ #533 Not tainted |
| ------------------------------------------------------ |
| kswapd0/383 is trying to acquire lock: |
| cca78ca4 (&sbi->write_io[i][j].io_rwsem){++++}-{3:3}, at: __submit_merged_write_cond+0x104/0x154 |
| but task is already holding lock: |
| c0e38518 (fs_reclaim){+.+.}-{0:0}, at: __fs_reclaim_acquire+0x0/0x50 |
| which lock already depends on the new lock. |
| the existing dependency chain (in reverse order) is: |
| -> #2 (fs_reclaim){+.+.}-{0:0}: |
| fs_reclaim_acquire.part.11+0x40/0x50 |
| fs_reclaim_acquire+0x24/0x28 |
| __kmalloc+0x54/0x218 |
| regulator_register+0x860/0x1584 |
| dummy_regulator_probe+0x60/0xa8 |
| [...] |
| other info that might help us debug this: |
| |
| Chain exists of: |
| &sbi->write_io[i][j].io_rwsem --> regulator_list_mutex --> fs_reclaim |
| |
| Possible unsafe locking scenario: |
| |
| CPU0 CPU1 |
| ---- ---- |
| lock(fs_reclaim); |
| lock(regulator_list_mutex); |
| lock(fs_reclaim); |
| lock(&sbi->write_io[i][j].io_rwsem); |
| *** DEADLOCK *** |
| |
| 1 lock held by kswapd0/383: |
| #0: c0e38518 (fs_reclaim){+.+.}-{0:0}, at: __fs_reclaim_acquire+0x0/0x50 |
| [...] |
| |
| Fixes: d8ca7d184b33 ("regulator: core: Introduce API for regulators coupling customization") |
| Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl> |
| Reviewed-by: Dmitry Osipenko <digetx@gmail.com> |
| Cc: stable@vger.kernel.org |
| Link: https://lore.kernel.org/r/1a889cf7f61c6429c9e6b34ddcdde99be77a26b6.1597195321.git.mirq-linux@rere.qmqm.pl |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| |
| diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c |
| index 75ff7c563c5d..513f95c6f837 100644 |
| --- a/drivers/regulator/core.c |
| +++ b/drivers/regulator/core.c |
| @@ -5040,7 +5040,10 @@ static int regulator_init_coupling(struct regulator_dev *rdev) |
| if (!of_check_coupling_data(rdev)) |
| return -EPERM; |
| |
| + mutex_lock(®ulator_list_mutex); |
| rdev->coupling_desc.coupler = regulator_find_coupler(rdev); |
| + mutex_unlock(®ulator_list_mutex); |
| + |
| if (IS_ERR(rdev->coupling_desc.coupler)) { |
| err = PTR_ERR(rdev->coupling_desc.coupler); |
| rdev_err(rdev, "failed to get coupler: %d\n", err); |
| @@ -5248,9 +5251,7 @@ regulator_register(const struct regulator_desc *regulator_desc, |
| if (ret < 0) |
| goto wash; |
| |
| - mutex_lock(®ulator_list_mutex); |
| ret = regulator_init_coupling(rdev); |
| - mutex_unlock(®ulator_list_mutex); |
| if (ret < 0) |
| goto wash; |
| |
| -- |
| 2.27.0 |
| |