summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@quicinc.com>2017-07-06 23:41:23 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2017-07-06 23:41:23 -0700
commit97aeb32ee2273d4e39a93ee5f11566271af993fd (patch)
tree21df7d15be17df9ec35e45af5e5b960bfb42fba1
parente46fafb501980533c5d9331cca71697dba4dbbf6 (diff)
parent493d8a74b6ef923bff21e44c71ae2c6a67d6578b (diff)
Merge "regulator: core: fix a possible race in disable_work handling"
-rw-r--r--drivers/regulator/core.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index adf621430b41..188920367e84 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2361,6 +2361,14 @@ static void regulator_disable_work(struct work_struct *work)
count = rdev->deferred_disables;
rdev->deferred_disables = 0;
+ /*
+ * Workqueue functions queue the new work instance while the previous
+ * work instance is being processed. Cancel the queued work instance
+ * as the work instance under processing does the job of the queued
+ * work instance.
+ */
+ cancel_delayed_work(&rdev->disable_work);
+
for (i = 0; i < count; i++) {
ret = _regulator_disable(rdev);
if (ret != 0)
@@ -2404,10 +2412,10 @@ int regulator_disable_deferred(struct regulator *regulator, int ms)
mutex_lock(&rdev->mutex);
rdev->deferred_disables++;
+ mod_delayed_work(system_power_efficient_wq, &rdev->disable_work,
+ msecs_to_jiffies(ms));
mutex_unlock(&rdev->mutex);
- queue_delayed_work(system_power_efficient_wq, &rdev->disable_work,
- msecs_to_jiffies(ms));
return 0;
}
EXPORT_SYMBOL_GPL(regulator_disable_deferred);