[PATCH v2] clk: devres: fix cleanup in devm_clk_get_optional_enabled_with_rate()
Onur Özkan <[email protected]> Sun, 9 Aug 2026 12:54:04 +0300
| Newsgroups | org.kernel.vger.linux-clk,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
devm_clk_get_optional_enabled_with_rate() registers its cleanup action before setting the clock rate. If setting the rate fails, it attempts to disable and unprepare a clock that was never enabled. This issue was spotted while reviewing "rust: clk: add devres-managed clks" [1]. Register the cleanup action only after successfully preparing and enabling the clock. [1]: https://lore.kernel.org/rust-for-linux/[email protected] Fixes: 9934a1bd45b2 ("clk: provide devm_clk_get_optional_enabled_with_rate()") Reviewed-by: Brian Masney <[email protected]> Signed-off-by: Onur Özkan <[email protected]> --- Changes since v1: - Explicit cleanup to avoid smatch warning. drivers/clk/clk-devres.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c index 994d5bc5168b..66c35201104c 100644 --- a/drivers/clk/clk-devres.c +++ b/drivers/clk/clk-devres.c @@ -99,6 +99,11 @@ struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id) } EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled); +static void devm_clk_disable_unprepare(void *data) +{ + clk_disable_unprepare(data); +} + struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev, const char *id, unsigned long rate) @@ -106,8 +111,7 @@ struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev, struct clk *clk; int ret; - clk = __devm_clk_get(dev, id, clk_get_optional, NULL, - clk_disable_unprepare); + clk = devm_clk_get_optional(dev, id); if (IS_ERR(clk)) return ERR_CAST(clk); @@ -119,6 +123,12 @@ struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev, if (ret) goto out_put_clk; + ret = devm_add_action(dev, devm_clk_disable_unprepare, clk); + if (ret) { + clk_disable_unprepare(clk); + goto out_put_clk; + } + return clk; out_put_clk: -- 2.51.2