2020-08-11 01:11:45

by Michał Mirosław

[permalink] [raw]
Subject: [PATCH 0/7] regulator: fix deadlock vs memory reclaim

For systems that have eg. eMMC storage using voltage regulator, memory
reclaim path might call back into regulator subsystem. This means we
have to make sure no allocations happen with a regulator or regulator
list locked.

After this series I see no more lockdep complaints on my test system,
but please review and test further.

First four patches move allocations out of locked regions, next three
came as a drive-by cleanups.


Michał Mirosław (7):
regulator: push allocation in regulator_init_coupling() outside of
lock
regulator: push allocation in regulator_ena_gpio_request() out of lock
regulator: push allocations in create_regulator() outside of lock
regulator: push allocation in set_consumer_device_supply() out of lock
regulator: plug of_node leak in regulator_register()'s error path
regulator: cleanup regulator_ena_gpio_free()
regulator: remove superfluous lock in regulator_resolve_coupling()

drivers/regulator/core.c | 162 +++++++++++++++++++++------------------
1 file changed, 86 insertions(+), 76 deletions(-)

--
2.20.1


2020-08-11 01:11:59

by Michał Mirosław

[permalink] [raw]
Subject: [PATCH 6/7] regulator: cleanup regulator_ena_gpio_free()

Since only regulator_ena_gpio_request() allocates rdev->ena_pin, and it
guarantees that same gpiod gets same pin structure, it is enough to
compare just the pointers. Also we know there can be only one matching
entry on the list. Rework the code take advantage of the facts.

Signed-off-by: Michał Mirosław <[email protected]>
---
drivers/regulator/core.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index a9ff2ad55ee7..b85ec974944e 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2260,19 +2260,19 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev)

/* Free the GPIO only in case of no use */
list_for_each_entry_safe(pin, n, &regulator_ena_gpio_list, list) {
- if (pin->gpiod == rdev->ena_pin->gpiod) {
- if (pin->request_count <= 1) {
- pin->request_count = 0;
- gpiod_put(pin->gpiod);
- list_del(&pin->list);
- kfree(pin);
- rdev->ena_pin = NULL;
- return;
- } else {
- pin->request_count--;
- }
- }
+ if (pin != rdev->ena_pin)
+ continue;
+
+ if (--pin->request_count)
+ break;
+
+ gpiod_put(pin->gpiod);
+ list_del(&pin->list);
+ kfree(pin);
+ break;
}
+
+ rdev->ena_pin = NULL;
}

/**
--
2.20.1