[PATCH 03/10] regulator: core: Flush delayed disable_work before releasing supply in regulator_unregister()
From: Lee Jones
Date: Wed Nov 04 2026 - 14:02:42 EST
regulator_unregister() currently calls flush_work() on
rdev->disable_work.work after tearing down and freeing rdev->supply.
This has two bugs:
1. Because rdev->disable_work is a delayed_work, flush_work() only waits
for work that has already been queued and ignores an armed timer,
allowing delayed_work_timer_fn() to fire after device_unregister()
has freed rdev.
2. regulator_disable_work() locks and disables rdev->supply via
regulator_lock_dependent() and _regulator_disable(), so releasing
rdev->supply before flushing disable_work races with any pending or
running deferred disable work item.
Use flush_delayed_work() at the start of regulator_unregister() so any
deferred disable work completes before rdev->supply is torn down.
Fixes: da07ecd93b19 ("regulator: Implement deferred disable support")
Fixes: e032b376551a ("regulator: Fix deadlock on removal of regulators with supplies")
Closes: https://sashiko.dev/#/bug/linux-6ee97926-52f2-4842-ba55-b554f9b39d53
Closes: https://sashiko.dev/#/bug/linux-aac296d1-789a-469b-8bde-8e110c4447ea
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Lee Jones <lee@xxxxxxxxxx>
---
drivers/regulator/core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 14422cfe80e2..935fee27f126 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -6299,6 +6299,8 @@ void regulator_unregister(struct regulator_dev *rdev)
if (rdev == NULL)
return;
+ flush_delayed_work(&rdev->disable_work);
+
if (rdev->supply) {
regulator_unregister_notifier(rdev->supply,
&rdev->supply_fwd_nb);
@@ -6308,8 +6310,6 @@ void regulator_unregister(struct regulator_dev *rdev)
regulator_put(rdev->supply);
}
- flush_work(&rdev->disable_work.work);
-
mutex_lock(®ulator_list_mutex);
WARN_ON(rdev->open_count);
--
2.56.0.385.gac671c819a-goog