[PATCH 6/6] clocksource/drivers/pistachio: Fix clock reference leaks in pistachio_clksrc_of_init

From: Wentao Liang

Date: Tue Sep 15 2026 - 01:27:39 EST


pistachio_clksrc_of_init() looks up the sys and fast clocks with
of_clk_get_by_name(), which takes a reference on each clock, but no
clk_put() exists anywhere in the driver. Both references are leaked on
several paths:

- if the "fast" clock lookup fails, the reference on the already
obtained "sys" clock is leaked;
- if clk_prepare_enable() fails for the "sys" clock, its reference is
leaked;
- if clk_prepare_enable() fails for the "fast" clock, the "sys" clock is
disabled and unprepared but neither reference is dropped;
- if clocksource_register_hz() fails, both clocks stay prepared and
enabled and both references are leaked;
- on success both clocks stay enabled but the local pointers are lost
and both references are leaked.

Add proper error unwinding with clk_disable_unprepare() plus clk_put()
where the clocks were enabled, clk_put() where they were not, and on
success drop both references while keeping the clocks enabled for the
clocksource.

Fixes: 84583983c319 ("CLOCKSOURCE: Add Pistachio clocksource-only driver")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Wentao Liang <vulab@xxxxxxxxxxx>
---
drivers/clocksource/timer-pistachio.c | 28 ++++++++++++++++++++++++---
1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/drivers/clocksource/timer-pistachio.c b/drivers/clocksource/timer-pistachio.c
index 57b2197a0b67..8749230453f8 100644
--- a/drivers/clocksource/timer-pistachio.c
+++ b/drivers/clocksource/timer-pistachio.c
@@ -181,20 +181,22 @@ static int __init pistachio_clksrc_of_init(struct device_node *node)
fast_clk = of_clk_get_by_name(node, "fast");
if (IS_ERR(fast_clk)) {
pr_err("clock get failed (%lu)\n", PTR_ERR(fast_clk));
+ clk_put(sys_clk);
return PTR_ERR(fast_clk);
}

ret = clk_prepare_enable(sys_clk);
if (ret < 0) {
pr_err("failed to enable clock (%d)\n", ret);
+ clk_put(sys_clk);
return ret;
}

ret = clk_prepare_enable(fast_clk);
if (ret < 0) {
pr_err("failed to enable clock (%d)\n", ret);
- clk_disable_unprepare(sys_clk);
- return ret;
+ clk_put(fast_clk);
+ goto disable_sys_clk;
}

rate = clk_get_rate(fast_clk);
@@ -210,7 +212,27 @@ static int __init pistachio_clksrc_of_init(struct device_node *node)

raw_spin_lock_init(&pcs_gpt.lock);
sched_clock_register(pistachio_read_sched_clock, 32, rate);
- return clocksource_register_hz(&pcs_gpt.cs, rate);
+ ret = clocksource_register_hz(&pcs_gpt.cs, rate);
+ if (ret)
+ goto disable_clks;
+
+ /*
+ * Both clocks are intentionally left enabled for the clocksource;
+ * only drop the consumer references taken by of_clk_get_by_name().
+ */
+ clk_put(fast_clk);
+ clk_put(sys_clk);
+
+ return 0;
+
+disable_clks:
+ clk_disable_unprepare(fast_clk);
+ clk_put(fast_clk);
+disable_sys_clk:
+ clk_disable_unprepare(sys_clk);
+ clk_put(sys_clk);
+
+ return ret;
}
TIMER_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer",
pistachio_clksrc_of_init);
--
2.34.1