Linux Power Management development
 help / color / mirror / Atom feed
From: Lukasz Luba <lukasz.luba@arm.com>
To: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
Cc: rui.zhang@intel.com, linux-pm@vger.kernel.org,
	linux-kernel@vger.kernel.org, rafael@kernel.org
Subject: Re: [PATCH] thermal/core: Split __thermal_cooling_device_register() into two functions
Date: Thu, 7 May 2026 11:02:11 +0100	[thread overview]
Message-ID: <96515043-d9be-475e-81ba-71a8fbeeaedd@arm.com> (raw)
In-Reply-To: <20260505144447.2853933-1-daniel.lezcano@oss.qualcomm.com>

Hi Daniel,

On 5/5/26 15:44, Daniel Lezcano wrote:
> In preparation for the upcoming changes separating OF and non-OF code,
> split __thermal_cooling_device_register() into allocation and addition
> phases.
> 
> This allows moving the device node assignment out of the core
> initialization path.
> 
> This change is not a trivial split. The lifetime of the cooling device
> is managed by the device core through put_device(), which triggers
> thermal_release() to free all associated resources.
> 
> With the introduction of thermal_cooling_device_alloc(), the allocation
> path must mirror what thermal_release() undoes. In contrast,
> thermal_cooling_device_add() must not perform any rollback and relies
> on put_device() for cleanup on error paths. This avoids both double
> free and resource leaks.
> 
> As part of this rework, add the missing device_initialize() call when
> allocating the cooling device.
> 
> Suggested-by: Rafael J. Wysocki <rafael@kernel.org>
> Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
> ---
>   drivers/thermal/thermal_core.c | 117 ++++++++++++++++++++-------------
>   1 file changed, 73 insertions(+), 44 deletions(-)
> 
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index 664a4cc95199..fd4c61197d1e 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -1040,29 +1040,10 @@ static void thermal_cooling_device_init_complete(struct thermal_cooling_device *
>   		thermal_zone_cdev_bind(tz, cdev);
>   }
>   
> -/**
> - * __thermal_cooling_device_register() - register a new thermal cooling device
> - * @np:		a pointer to a device tree node.
> - * @type:	the thermal cooling device type.
> - * @devdata:	device private data.
> - * @ops:	standard thermal cooling devices callbacks.
> - *
> - * This interface function adds a new thermal cooling device (fan/processor/...)
> - * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
> - * to all the thermal zone devices registered at the same time.
> - * It also gives the opportunity to link the cooling device to a device tree
> - * node, so that it can be bound to a thermal zone created out of device tree.
> - *
> - * Return: a pointer to the created struct thermal_cooling_device or an
> - * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
> - */
>   static struct thermal_cooling_device *
> -__thermal_cooling_device_register(struct device_node *np,
> -				  const char *type, void *devdata,
> -				  const struct thermal_cooling_device_ops *ops)
> +thermal_cooling_device_alloc(const char *type, const struct thermal_cooling_device_ops *ops)
>   {
>   	struct thermal_cooling_device *cdev;
> -	unsigned long current_state;
>   	int ret;
>   
>   	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> @@ -1076,6 +1057,8 @@ __thermal_cooling_device_register(struct device_node *np,
>   	if (!cdev)
>   		return ERR_PTR(-ENOMEM);
>   
> +	cdev->ops = ops;
> +
>   	ret = ida_alloc(&thermal_cdev_ida, GFP_KERNEL);
>   	if (ret < 0)
>   		goto out_kfree_cdev;
> @@ -1087,17 +1070,36 @@ __thermal_cooling_device_register(struct device_node *np,
>   		goto out_ida_remove;
>   	}
>   
> +	return cdev;
> +
> +out_ida_remove:
> +	ida_free(&thermal_cdev_ida, cdev->id);
> +out_kfree_cdev:
> +	kfree(cdev);
> +	return ERR_PTR(ret);
> +}
> +
> +static int thermal_cooling_device_add(struct thermal_cooling_device *cdev, void *devdata)
> +{
> +	unsigned long current_state;
> +	int ret;
> +
>   	mutex_init(&cdev->lock);
>   	INIT_LIST_HEAD(&cdev->thermal_instances);
> -	cdev->np = np;
> -	cdev->ops = ops;
>   	cdev->updated = false;
>   	cdev->device.class = &thermal_class;
> +	device_initialize(&cdev->device);
>   	cdev->devdata = devdata;
>   
> +	thermal_cooling_device_setup_sysfs(cdev);
> +
> +	ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> +	if (ret)

In case of error here, when the cdev->device won't have this name,
would thermal_release() still be able to call the cleanup
for the sysfs bits?
IMHO the check 'if()' there might bite us and we might not free
the sysfs allocated memory.


> +		goto out_put_device;
> +
>   	ret = cdev->ops->get_max_state(cdev, &cdev->max_state);
>   	if (ret)
> -		goto out_cdev_type;
> +		goto out_put_device;
>   
>   	/*
>   	 * The cooling device's current state is only needed for debug
> @@ -1111,35 +1113,62 @@ __thermal_cooling_device_register(struct device_node *np,
>   	if (ret)
>   		current_state = ULONG_MAX;
>   
> -	thermal_cooling_device_setup_sysfs(cdev);
> -
> -	ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> -	if (ret)

In this current code case, we explicitly call the
thermal_cooling_device_destroy_sysfs() which will definitely clean-up
all stuff.


> -		goto out_cooling_dev;
> -
>   	ret = device_register(&cdev->device);
> -	if (ret) {
> -		/* thermal_release() handles rest of the cleanup */
> -		put_device(&cdev->device);
> -		return ERR_PTR(ret);
> -	}
> +	if (ret)
> +		goto out_put_device;
>   
>   	if (current_state <= cdev->max_state)
>   		thermal_debug_cdev_add(cdev, current_state);
>   
>   	thermal_cooling_device_init_complete(cdev);
>   
> -	return cdev;
> +	return 0;
>   
> -out_cooling_dev:
> -	thermal_cooling_device_destroy_sysfs(cdev);
> -out_cdev_type:
> -	kfree_const(cdev->type);
> -out_ida_remove:
> -	ida_free(&thermal_cdev_ida, cdev->id);
> -out_kfree_cdev:
> -	kfree(cdev);
> -	return ERR_PTR(ret);
> +out_put_device:
> +	/*
> +	 * The device core will release the memory via
> +	 * thermal_release() after put_device() is called in the error
> +	 * path
> +	 */
> +	put_device(&cdev->device);
> +	return ret;
> +}
> +
> +/**
> + * __thermal_cooling_device_register() - register a new thermal cooling device
> + * @np:		a pointer to a device tree node.
> + * @type:	the thermal cooling device type.
> + * @devdata:	device private data.
> + * @ops:	standard thermal cooling devices callbacks.
> + *
> + * This interface function adds a new thermal cooling device (fan/processor/...)
> + * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
> + * to all the thermal zone devices registered at the same time.
> + * It also gives the opportunity to link the cooling device to a device tree
> + * node, so that it can be bound to a thermal zone created out of device tree.
> + *
> + * Return: a pointer to the created struct thermal_cooling_device or an
> + * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
> + */
> +static struct thermal_cooling_device *
> +__thermal_cooling_device_register(struct device_node *np,
> +				  const char *type, void *devdata,
> +				  const struct thermal_cooling_device_ops *ops)
> +{
> +	struct thermal_cooling_device *cdev;
> +	int ret;
> +
> +	cdev = thermal_cooling_device_alloc(type, ops);
> +	if (IS_ERR(cdev))
> +		return cdev;
> +
> +	cdev->np = np;
> +
> +	ret = thermal_cooling_device_add(cdev, devdata);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	return cdev;
>   }
>   
>   /**

The rest looks OK

Regards,
Lukasz


  parent reply	other threads:[~2026-05-07 10:02 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-05 14:44 [PATCH] thermal/core: Split __thermal_cooling_device_register() into two functions Daniel Lezcano
2026-05-07  8:29 ` Daniel Lezcano
2026-05-07 10:02 ` Lukasz Luba [this message]
2026-05-07 18:26   ` Daniel Lezcano
2026-05-08 10:35     ` Lukasz Luba
2026-05-08 11:25       ` Daniel Lezcano
2026-05-08 12:08         ` Rafael J. Wysocki
2026-05-08 12:40           ` Daniel Lezcano

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=96515043-d9be-475e-81ba-71a8fbeeaedd@arm.com \
    --to=lukasz.luba@arm.com \
    --cc=daniel.lezcano@oss.qualcomm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=rafael@kernel.org \
    --cc=rui.zhang@intel.com \
    /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