Linux Hardware Monitor development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Cong Nguyen" <congnt264@gmail.com>
Cc: linux-hwmon@vger.kernel.org
Subject: Re: [PATCH v3] hwmon: (gpio-fan) fix pm_runtime imbalance for alarm-only fans
Date: Tue, 01 Sep 2026 11:32:26 +0000	[thread overview]
Message-ID: <20260901113227.3694B1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260901111903.660681-1-congnt264@gmail.com>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:

New issues:
- [High] Unbalanced pm_runtime_disable() on probe error paths permanently disables runtime PM.

Pre-existing issues:
- [High] Failing to resume the device at the end of probe causes a usage count underflow during devm cleanup.
- [High] A race condition between probe and sysfs writes can cause a double-increment of the runtime PM usage count, permanently blocking runtime suspend.
- [High] Missing synchronize_irq() in runtime suspend callback for shared IRQ.
- [High] Missing cancel_work_sync() for alarm_work leads to a Use-After-Free on driver unbind or probe failure.
- [High] Unconditional IRQ_NONE return in a shared interrupt handler.
--

commit c1b61438a4a40096fe54d7b86037b9d5eebc1cae
Author: Cong Nguyen <congnt264@gmail.com>

hwmon: (gpio-fan) fix pm_runtime imbalance for alarm-only fans

pm_runtime_enable() runs unconditionally in probe, but the devm cleanup
that calls pm_runtime_disable() is only registered when control GPIOs
are present. Alarm-only fans never get it, so unbind warns about the
missing disable.

Link: https://lore.kernel.org/r/20260830152150.27F5F1F000E9@smtp.kernel.org

> diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
> index 084828e1e2817..8b28f0d58c638 100644
> --- a/drivers/hwmon/gpio-fan.c
> +++ b/drivers/hwmon/gpio-fan.c
[ ... ]
> @@ -553,6 +556,17 @@ static int gpio_fan_probe(struct platform_device *pdev)
>  		return dev_err_probe(dev, PTR_ERR(fan_data->supply),
>  				     "Failed to get fan-supply");
>  
> +	/*
> +	 * Reserve this devm slot before gpio_fan_stop()'s so LIFO teardown
> +	 * runs gpio_fan_stop() (needs PM enabled to disable the regulator)
> +	 * first. pm_runtime_enable() itself still happens at its original
> +	 * position below, so this doesn't change when PM actually becomes
> +	 * enabled -- only where its eventual disable is queued.
> +	 */
> +	err = devm_add_action_or_reset(dev, gpio_fan_pm_runtime_disable, dev);
> +	if (err)
> +		return err;

[Severity: High]
Does unconditionally registering devm_add_action_or_reset() early in the
probe path cause an unbalanced pm_runtime_disable() on probe error paths?

If probe fails at any intermediate point (e.g., in fan_ctrl_init(),
hwmon_device_register_with_groups(), or fan_alarm_init()), devm teardown will
execute gpio_fan_pm_runtime_disable(). Since pm_runtime_enable() hasn't been
reached yet, this incorrectly increments dev->power.disable_depth. On a
subsequent probe attempt, pm_runtime_enable() will only decrement it to 1,
leaving runtime PM permanently disabled.

[Severity: High]
This isn't a bug introduced by this patch, but does failing to resume the device
at the end of probe cause a usage count underflow during devm cleanup?

fan_ctrl_init() initializes fan_data->speed_index based on the hardware state.
If the fan is active, speed_index > 0. gpio_fan_stop() is then queued as a devm
action. If probe subsequently fails before the final pm_runtime_resume_and_get()
succeeds, the devm cleanup runs gpio_fan_stop(), which calls set_fan_speed():

drivers/hwmon/gpio-fan.c:set_fan_speed() {
	...
	if (fan_data->speed_index > 0 && speed_index == 0) {
		int ret;

		ret = pm_runtime_put_sync(fan_data->dev);
		if (ret < 0 && ret != -ENOSYS)
			return ret;
	}
	...
}

Because speed_index > 0, set_fan_speed() drops a PM reference that was never
actually acquired, pushing the usage count below zero.

[Severity: High]
This is a pre-existing issue, but does a race condition between probe and
sysfs writes cause a double-increment of the runtime PM usage count?

Sysfs attributes are exposed early by devm_hwmon_device_register_with_groups().
Userspace can write to pwm1 right after probe calls pm_runtime_enable(). The
sysfs handler acquires a PM reference and sets speed_index > 0.

The probe thread then checks the state:

drivers/hwmon/gpio-fan.c:gpio_fan_probe() {
	...
	/* If current GPIO state is active, mark RPM as active as well */
	if (fan_data->speed_index > 0) {
		int ret;

		ret = pm_runtime_resume_and_get(&pdev->dev);
		if (ret)
			return ret;
	}
	...
}

Since this check doesn't hold fan_data->lock, probe sees the new value and takes
a second PM reference. When userspace later stops the fan, only one reference
is dropped, permanently blocking runtime suspend.

[Severity: High]
This is a pre-existing issue, but is synchronize_irq() missing in the runtime
suspend callback for a shared IRQ?

The driver requests a shared interrupt for the alarm GPIO:

drivers/hwmon/gpio-fan.c:fan_alarm_init() {
	...
	return devm_request_irq(dev, alarm_irq, fan_alarm_irq_handler,
				IRQF_SHARED, "GPIO fan alarm", fan_data);
}

The PM subsystem guide mandates that drivers using IRQF_SHARED MUST call
synchronize_irq() in their runtime suspend callback before powering down
hardware.

Since this is missing, the IRQ handler could execute mid-flight while the
regulator is being disabled in gpio_fan_runtime_suspend():

drivers/hwmon/gpio-fan.c:gpio_fan_runtime_suspend() {
	...
	if (fan_data->supply)
		ret = regulator_disable(fan_data->supply);
	...
}

[Severity: High]
This is a pre-existing issue, but does missing cancel_work_sync() for alarm_work
lead to a use-after-free on driver unbind or probe failure?

The driver initializes fan_data->alarm_work and requests an interrupt to
schedule it:

drivers/hwmon/gpio-fan.c:fan_alarm_init() {
	...
	INIT_WORK(&fan_data->alarm_work, fan_alarm_notify);
	...
	return devm_request_irq(dev, alarm_irq, ...);
}

It fails to register a cleanup action to call cancel_work_sync(). During driver
unbind or probe failure, devm_request_irq is unwound, which synchronizes with
running handlers but does not cancel pending work. fan_data is then freed by
devm. If an interrupt fired right before cleanup, the work executes
asynchronously and dereferences the freed fan_data pointer.

[Severity: High]
This is a pre-existing issue, but does the shared interrupt handler return an
unconditional IRQ_NONE?

drivers/hwmon/gpio-fan.c:fan_alarm_irq_handler() {
	...
	schedule_work(&fan_data->alarm_work);

	return IRQ_NONE;
}

The driver requests an IRQF_SHARED interrupt. In its handler, it processes the
event but unconditionally returns IRQ_NONE. When the kernel sees IRQ_NONE from
all handlers on a shared line, it registers an unhandled interrupt. After enough
unhandled interrupts, the kernel disables the IRQ line permanently, breaking all
devices sharing it.

> +
>  	/* Configure control GPIOs if available. */
>  	if (fan_data->gpios && fan_data->num_gpios > 0) {
>  		if (!fan_data->speed || fan_data->num_speed <= 1)

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901111903.660681-1-congnt264@gmail.com?part=1

  reply	other threads:[~2026-09-01 11:32 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-01 11:19 [PATCH v3] hwmon: (gpio-fan) fix pm_runtime imbalance for alarm-only fans Cong Nguyen
2026-09-01 11:32 ` sashiko-bot [this message]
2026-09-01 15:57   ` Guenter Roeck

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260901113227.3694B1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=congnt264@gmail.com \
    --cc=linux-hwmon@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox