Skip to contentSkip to conversation

thermal: Fix/cleanup error paths in __thermal_cooling_device_register()

PATCH In review Viresh Kumar 5 participants 13 messages Jan 18, 2023 – Jan 24, 2023 Thermal

lore
Share & tools
lore
#0 lore raw

cover thermal: Fix/cleanup error paths in __thermal_cooling_device_register()

Hi,

The error paths in __thermal_cooling_device_register() are trying to free un-acquired resources, fix that and clean it up a bit.

Caleb, can you please test this? I have just build tested it for now.

--
Viresh

Viresh Kumar (3):
thermal: core: call put_device() only after device_register() fails
thermal: core: Move cdev cleanup to thermal_release()
thermal: core: Use device_unregister() instead of device_del/put()

 drivers/thermal/thermal_core.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)
Signature · 1 line
2.31.1.272.g89b43f80a514
#1 lore raw

PATCH 2/3 thermal: core: Move cdev cleanup to thermal_release()

thermal_release() already frees cdev, let it do rest of the cleanup as well in order to simplify the error paths in __thermal_cooling_device_register().

---
 drivers/thermal/thermal_core.c | 33 ++++++++++++++-------------------
 1 file changed, 14 insertions(+), 19 deletions(-)
drivers/thermal/thermal_core.c +14 -19
index 77bd47d976a2..1fb109a97ff6 100644
@@ -774,6 +774,9 @@ static void thermal_release(struct device *dev)
 	} else if (!strncmp(dev_name(dev), "cooling_device",
 			    sizeof("cooling_device") - 1)) {
 		cdev = to_cooling_device(dev);
+		thermal_cooling_device_destroy_sysfs(cdev);
+		kfree(cdev->type);
+		ida_free(&thermal_cdev_ida, cdev->id);
 		kfree(cdev);
 	}
 }
@@ -909,23 +912,21 @@ __thermal_cooling_device_register(struct device_node *np,
 	cdev->devdata = devdata;
 
 	ret = cdev->ops->get_max_state(cdev, &cdev->max_state);
-	if (ret) {
-		kfree(cdev->type);
-		goto out_ida_remove;
-	}
+	if (ret)
+		goto out_cdev_type;
 
 	thermal_cooling_device_setup_sysfs(cdev);
 
 	ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
-	if (ret) {
-		kfree(cdev->type);
-		thermal_cooling_device_destroy_sysfs(cdev);
-		goto out_ida_remove;
-	}
+	if (ret)
+		goto out_cooling_dev;
 
 	ret = device_register(&cdev->device);
-	if (ret)
-		goto out_kfree_type;
+	if (ret) {
+		/* thermal_release() handles rest of the cleanup */
+		put_device(&cdev->device);
+		return ERR_PTR(ret);
+	}
 
 	/* Add 'this' new cdev to the global cdev list */
 	mutex_lock(&thermal_list_lock);
@@ -944,13 +945,10 @@ __thermal_cooling_device_register(struct device_node *np,
 
 	return cdev;
 
-out_kfree_type:
+out_cooling_dev:
 	thermal_cooling_device_destroy_sysfs(cdev);
+out_cdev_type:
 	kfree(cdev->type);
-	put_device(&cdev->device);
-
-	/* thermal_release() takes care of the rest */
-	cdev = NULL;
 out_ida_remove:
 	ida_free(&thermal_cdev_ida, id);
 out_kfree_cdev:
@@ -1111,10 +1109,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
 
 	mutex_unlock(&thermal_list_lock);
 
-	ida_free(&thermal_cdev_ida, cdev->id);
 	device_del(&cdev->device);
-	thermal_cooling_device_destroy_sysfs(cdev);
-	kfree(cdev->type);
 	put_device(&cdev->device);
 }
 EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
Signature · 1 line
2.31.1.272.g89b43f80a514
Reviewed-by on v1 2/3
#2 lore raw

Re: [PATCH 2/3] thermal: core: Move cdev cleanup to thermal_release()

Quoted 6 lines · Viresh Kumar

thermal_release() already frees cdev, let it do rest of the cleanup as well in order to simplify the error paths in __thermal_cooling_device_register().

---

Quoted 77 lines
  drivers/thermal/thermal_core.c | 33 ++++++++++++++-------------------
  1 file changed, 14 insertions(+), 19 deletions(-)
drivers/thermal/thermal_core.c +14 -19
index 77bd47d976a2..1fb109a97ff6 100644
@@ -774,6 +774,9 @@ static void thermal_release(struct device *dev)
  	} else if (!strncmp(dev_name(dev), "cooling_device",
  			    sizeof("cooling_device") - 1)) {
  		cdev = to_cooling_device(dev);
+		thermal_cooling_device_destroy_sysfs(cdev);
+		kfree(cdev->type);
+		ida_free(&thermal_cdev_ida, cdev->id);
  		kfree(cdev);
  	}
  }
@@ -909,23 +912,21 @@ __thermal_cooling_device_register(struct device_node *np,
  	cdev->devdata = devdata;
 
  	ret = cdev->ops->get_max_state(cdev, &cdev->max_state);
-	if (ret) {
-		kfree(cdev->type);
-		goto out_ida_remove;
-	}
+	if (ret)
+		goto out_cdev_type;
 
  	thermal_cooling_device_setup_sysfs(cdev);
 
  	ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
-	if (ret) {
-		kfree(cdev->type);
-		thermal_cooling_device_destroy_sysfs(cdev);
-		goto out_ida_remove;
-	}
+	if (ret)
+		goto out_cooling_dev;
 
  	ret = device_register(&cdev->device);
-	if (ret)
-		goto out_kfree_type;
+	if (ret) {
+		/* thermal_release() handles rest of the cleanup */
+		put_device(&cdev->device);
+		return ERR_PTR(ret);
+	}
 
  	/* Add 'this' new cdev to the global cdev list */
  	mutex_lock(&thermal_list_lock);
@@ -944,13 +945,10 @@ __thermal_cooling_device_register(struct device_node *np,
 
  	return cdev;
 
-out_kfree_type:
+out_cooling_dev:
  	thermal_cooling_device_destroy_sysfs(cdev);
+out_cdev_type:
  	kfree(cdev->type);
-	put_device(&cdev->device);
-
-	/* thermal_release() takes care of the rest */
-	cdev = NULL;
  out_ida_remove:
  	ida_free(&thermal_cdev_ida, id);
  out_kfree_cdev:
@@ -1111,10 +1109,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
 
  	mutex_unlock(&thermal_list_lock);
 
-	ida_free(&thermal_cdev_ida, cdev->id);
  	device_del(&cdev->device);
-	thermal_cooling_device_destroy_sysfs(cdev);
-	kfree(cdev->type);
  	put_device(&cdev->device);
  }
  EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
#3 lore raw

PATCH v4 1/3 thermal: core: call put_device() only after device_register() fails

In reply to Viresh Kumar

put_device() shouldn't be called before a prior call to device_register(). __thermal_cooling_device_register() doesn't follow that properly and needs fixing. Also thermal_cooling_device_destroy_sysfs() is getting called unnecessarily on few error paths.

Fix all this by placing the calls at the right place.

Based on initial work done by Caleb Connolly.

Fixes 4748f9687caa ("thermal: core: fix some possible name leaks in error paths")
Fixes c408b3d1d9bb ("thermal: Validate new state in cur_state_store()")

---
For v6.2-rc.

V3->V4:
- The first three versions were sent by Caleb.
- The new version fixes the current bugs, without looking to optimize the code any further, which is done separately in the next two patches.

 drivers/thermal/thermal_core.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/thermal/thermal_core.c +10 -3
index f17ab2316dbd..77bd47d976a2 100644
@@ -909,15 +909,20 @@ __thermal_cooling_device_register(struct device_node *np,
 	cdev->devdata = devdata;
 
 	ret = cdev->ops->get_max_state(cdev, &cdev->max_state);
-	if (ret)
-		goto out_kfree_type;
+	if (ret) {
+		kfree(cdev->type);
+		goto out_ida_remove;
+	}
 
 	thermal_cooling_device_setup_sysfs(cdev);
+
 	ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
 	if (ret) {
+		kfree(cdev->type);
 		thermal_cooling_device_destroy_sysfs(cdev);
-		goto out_kfree_type;
+		goto out_ida_remove;
 	}
+
 	ret = device_register(&cdev->device);
 	if (ret)
 		goto out_kfree_type;
@@ -943,6 +948,8 @@ __thermal_cooling_device_register(struct device_node *np,
 	thermal_cooling_device_destroy_sysfs(cdev);
 	kfree(cdev->type);
 	put_device(&cdev->device);
+
+	/* thermal_release() takes care of the rest */
 	cdev = NULL;
 out_ida_remove:
 	ida_free(&thermal_cdev_ida, id);
Signature · 1 line
2.31.1.272.g89b43f80a514
Tested-by on v4 1/3
#4 lore raw

Re: [PATCH V4 1/3] thermal: core: call put_device() only after device_register() fails

Quoted 54 lines · Viresh Kumar

put_device() shouldn't be called before a prior call to device_register(). __thermal_cooling_device_register() doesn't follow that properly and needs fixing. Also thermal_cooling_device_destroy_sysfs() is getting called unnecessarily on few error paths.

Fix all this by placing the calls at the right place.

Based on initial work done by Caleb Connolly.

Fixes 4748f9687caa ("thermal: core: fix some possible name leaks in error paths")
Fixes c408b3d1d9bb ("thermal: Validate new state in cur_state_store()")

---
For v6.2-rc.

V3->V4:
- The first three versions were sent by Caleb.
- The new version fixes the current bugs, without looking to optimize the code any further, which is done separately in the next two patches.

 drivers/thermal/thermal_core.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/thermal/thermal_core.c +8 -3
index f17ab2316dbd..77bd47d976a2 100644
@@ -909,15 +909,20 @@ __thermal_cooling_device_register(struct device_node *np,
 	cdev->devdata = devdata;
 
 	ret = cdev->ops->get_max_state(cdev, &cdev->max_state);
-	if (ret)
-		goto out_kfree_type;
+	if (ret) {
+		kfree(cdev->type);
+		goto out_ida_remove;
+	}
 
 	thermal_cooling_device_setup_sysfs(cdev);
+
 	ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
 	if (ret) {
+		kfree(cdev->type);
 		thermal_cooling_device_destroy_sysfs(cdev);
-		goto out_kfree_type;
+		goto out_ida_remove;
 	}
+
 	ret = device_register(&cdev->device);
 	if (ret)
 		goto out_kfree_type;

drivers/thermal/thermal_core.c __thermal_cooling_device_register(struct device_node *np, · line 955

Quoted 8 lines
drivers/thermal/thermal_core.c +2 -0
@@ -943,6 +948,8 @@ __thermal_cooling_device_register(struct device_node *np,
 	thermal_cooling_device_destroy_sysfs(cdev);
 	kfree(cdev->type);
 	put_device(&cdev->device);
+
+	/* thermal_release() takes care of the rest */
 	cdev = NULL;
 out_ida_remove:
 	ida_free(&thermal_cdev_ida, id);

My testing:

Applied on top of v6.2-rc1
The configuration is qcom_defconfig
The system is a Qualcomm Dragon 8074

The two WARNING stack traces no longer occur after applying the patch.

#5 lore raw

Re: [PATCH V4 1/3] thermal: core: call put_device() only after device_register() fails

In reply to Viresh Kumar
Quoted 7 lines · Viresh Kumar

put_device() shouldn't be called before a prior call to device_register(). __thermal_cooling_device_register() doesn't follow that properly and needs fixing. Also thermal_cooling_device_destroy_sysfs() is getting called unnecessarily on few error paths.

Quoted 8 lines

Fix all this by placing the calls at the right place.

Based on initial work done by Caleb Connolly.

Fixes 4748f9687caa ("thermal: core: fix some possible name leaks in error paths")
Fixes c408b3d1d9bb ("thermal: Validate new state in cur_state_store()")

OK, so I think that this patch is needed for 6.2 and the other two may be queued up for later (they do depend on this one, though, of course). Is my understanding correct?

Quoted 51 lines

---
For v6.2-rc.

V3->V4:
- The first three versions were sent by Caleb.
- The new version fixes the current bugs, without looking to optimize the code any further, which is done separately in the next two patches.

 drivers/thermal/thermal_core.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/thermal/thermal_core.c +10 -4
index f17ab2316dbd..77bd47d976a2 100644
@@ -909,15 +909,20 @@ __thermal_cooling_device_register(struct device_node *np,
        cdev->devdata = devdata;
 
        ret = cdev->ops->get_max_state(cdev, &cdev->max_state);
-       if (ret)
-               goto out_kfree_type;
+       if (ret) {
+               kfree(cdev->type);
+               goto out_ida_remove;
+       }
 
        thermal_cooling_device_setup_sysfs(cdev);
+
        ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
        if (ret) {
+               kfree(cdev->type);
                thermal_cooling_device_destroy_sysfs(cdev);
-               goto out_kfree_type;
+               goto out_ida_remove;
        }
+
        ret = device_register(&cdev->device);
        if (ret)
                goto out_kfree_type;
@@ -943,6 +948,8 @@ __thermal_cooling_device_register(struct device_node *np,
        thermal_cooling_device_destroy_sysfs(cdev);
        kfree(cdev->type);
        put_device(&cdev->device);
+
+       /* thermal_release() takes care of the rest */
        cdev = NULL;
 out_ida_remove:
        ida_free(&thermal_cdev_ida, id);
--

2.31.1.272.g89b43f80a514

#6 lore raw

Re: [PATCH V4 1/3] thermal: core: call put_device() only after device_register() fails

Quoted 12 lines · Rafael J. Wysocki
Quoted 11 lines · Viresh Kumar

put_device() shouldn't be called before a prior call to device_register(). __thermal_cooling_device_register() doesn't follow that properly and needs fixing. Also thermal_cooling_device_destroy_sysfs() is getting called unnecessarily on few error paths.

Fix all this by placing the calls at the right place.

Based on initial work done by Caleb Connolly.

Quoted 8 lines
Quoted 4 lines
Fixes 4748f9687caa ("thermal: core: fix some possible name leaks in error paths")
Fixes c408b3d1d9bb ("thermal: Validate new state in cur_state_store()")

OK, so I think that this patch is needed for 6.2 and the other two may be queued up for later (they do depend on this one, though, of course). Is my understanding correct?

Right.

Signature · 1 line
viresh
#7 lore raw

Re: [PATCH V4 1/3] thermal: core: call put_device() only after device_register() fails

Quoted 19 lines · Viresh Kumar
Quoted 17 lines · Rafael J. Wysocki
Quoted 15 lines · Viresh Kumar

put_device() shouldn't be called before a prior call to device_register(). __thermal_cooling_device_register() doesn't follow that properly and needs fixing. Also thermal_cooling_device_destroy_sysfs() is getting called unnecessarily on few error paths.

Fix all this by placing the calls at the right place.

Based on initial work done by Caleb Connolly.

Fixes 4748f9687caa ("thermal: core: fix some possible name leaks in error paths")
Fixes c408b3d1d9bb ("thermal: Validate new state in cur_state_store()")
Quoted 5 lines
Quoted 3 lines

OK, so I think that this patch is needed for 6.2 and the other two may be queued up for later (they do depend on this one, though, of course). Is my understanding correct?

Right.

OK, applied as 6.2-rc material and I'll get to the other two when this goes in.

#8 lore raw

Re: [PATCH V4 1/3] thermal: core: call put_device() only after device_register() fails

Quoted 21 lines · Rafael J. Wysocki
Quoted 19 lines · Viresh Kumar
Quoted 17 lines · Rafael J. Wysocki
Quoted 15 lines · Viresh Kumar

put_device() shouldn't be called before a prior call to device_register(). __thermal_cooling_device_register() doesn't follow that properly and needs fixing. Also thermal_cooling_device_destroy_sysfs() is getting called unnecessarily on few error paths.

Fix all this by placing the calls at the right place.

Based on initial work done by Caleb Connolly.

Fixes 4748f9687caa ("thermal: core: fix some possible name leaks in error paths")
Fixes c408b3d1d9bb ("thermal: Validate new state in cur_state_store()")
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

OK, so I think that this patch is needed for 6.2 and the other two may be queued up for later (they do depend on this one, though, of course). Is my understanding correct?

Right.

OK, applied as 6.2-rc material and I'll get to the other two when this goes in.

Patches [2-3/3] from this series have been applied as 6.3 material now, thanks!

Reviewed-by on v4 1/3
#9 lore raw

Re: [PATCH V4 1/3] thermal: core: call put_device() only after device_register() fails

In reply to Viresh Kumar
Quoted 8 lines · Viresh Kumar

put_device() shouldn't be called before a prior call to device_register(). __thermal_cooling_device_register() doesn't follow that properly and needs fixing. Also thermal_cooling_device_destroy_sysfs() is getting called unnecessarily on few error paths.

Fix all this by placing the calls at the right place.

Quoted 7 lines

Based on initial work done by Caleb Connolly.

Fixes 4748f9687caa ("thermal: core: fix some possible name leaks in error paths")
Fixes c408b3d1d9bb ("thermal: Validate new state in cur_state_store()")

---

Quoted 47 lines

For v6.2-rc.

V3->V4:
- The first three versions were sent by Caleb.
- The new version fixes the current bugs, without looking to optimize the code any further, which is done separately in the next two patches.

  drivers/thermal/thermal_core.c | 13 ++++++++++---
  1 file changed, 10 insertions(+), 3 deletions(-)
drivers/thermal/thermal_core.c +10 -3
index f17ab2316dbd..77bd47d976a2 100644
@@ -909,15 +909,20 @@ __thermal_cooling_device_register(struct device_node *np,
  	cdev->devdata = devdata;
 
  	ret = cdev->ops->get_max_state(cdev, &cdev->max_state);
-	if (ret)
-		goto out_kfree_type;
+	if (ret) {
+		kfree(cdev->type);
+		goto out_ida_remove;
+	}
 
  	thermal_cooling_device_setup_sysfs(cdev);
+
  	ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
  	if (ret) {
+		kfree(cdev->type);
  		thermal_cooling_device_destroy_sysfs(cdev);
-		goto out_kfree_type;
+		goto out_ida_remove;
  	}
+
  	ret = device_register(&cdev->device);
  	if (ret)
  		goto out_kfree_type;
@@ -943,6 +948,8 @@ __thermal_cooling_device_register(struct device_node *np,
  	thermal_cooling_device_destroy_sysfs(cdev);
  	kfree(cdev->type);
  	put_device(&cdev->device);
+
+	/* thermal_release() takes care of the rest */
  	cdev = NULL;
  out_ida_remove:
  	ida_free(&thermal_cdev_ida, id);
Tested-by on v4 1/3
#10 lore raw

Re: [PATCH V4 1/3] thermal: core: call put_device() only after device_register() fails

In reply to Viresh Kumar
Quoted 6 lines · Viresh Kumar

put_device() shouldn't be called before a prior call to device_register(). __thermal_cooling_device_register() doesn't follow that properly and needs fixing. Also thermal_cooling_device_destroy_sysfs() is getting called unnecessarily on few error paths.

Quoted 8 lines

Fix all this by placing the calls at the right place.

Based on initial work done by Caleb Connolly.

Fixes 4748f9687caa ("thermal: core: fix some possible name leaks in error paths")
Fixes c408b3d1d9bb ("thermal: Validate new state in cur_state_store()")

Thanks for sending this, with this I no longer hit the splats when get_max_state() fails.

Quoted 48 lines

---
For v6.2-rc.

V3->V4:
- The first three versions were sent by Caleb.
- The new version fixes the current bugs, without looking to optimize the code any further, which is done separately in the next two patches.

 drivers/thermal/thermal_core.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/thermal/thermal_core.c +10 -3
index f17ab2316dbd..77bd47d976a2 100644
@@ -909,15 +909,20 @@ __thermal_cooling_device_register(struct device_node *np,
 	cdev->devdata = devdata;
 
 	ret = cdev->ops->get_max_state(cdev, &cdev->max_state);
-	if (ret)
-		goto out_kfree_type;
+	if (ret) {
+		kfree(cdev->type);
+		goto out_ida_remove;
+	}
 
 	thermal_cooling_device_setup_sysfs(cdev);
+
 	ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
 	if (ret) {
+		kfree(cdev->type);
 		thermal_cooling_device_destroy_sysfs(cdev);
-		goto out_kfree_type;
+		goto out_ida_remove;
 	}
+
 	ret = device_register(&cdev->device);
 	if (ret)
 		goto out_kfree_type;
@@ -943,6 +948,8 @@ __thermal_cooling_device_register(struct device_node *np,
 	thermal_cooling_device_destroy_sysfs(cdev);
 	kfree(cdev->type);
 	put_device(&cdev->device);
+
+	/* thermal_release() takes care of the rest */
 	cdev = NULL;
 out_ida_remove:
 	ida_free(&thermal_cdev_ida, id);
Signature · 2 lines
Kind Regards,
Caleb (they/them)
#11 lore raw

PATCH 3/3 thermal: core: Use device_unregister() instead of device_del/put()

In reply to Viresh Kumar

Lets not open code device_unregister() unnecessarily.

---
 drivers/thermal/thermal_core.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/thermal/thermal_core.c +1 -2
index 1fb109a97ff6..9fb37c5d9c4f 100644
@@ -1109,8 +1109,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
 
 	mutex_unlock(&thermal_list_lock);
 
-	device_del(&cdev->device);
-	put_device(&cdev->device);
+	device_unregister(&cdev->device);
 }
 EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
 
Signature · 1 line
2.31.1.272.g89b43f80a514
Reviewed-by on v1 3/3
#12 lore raw

Re: [PATCH 3/3] thermal: core: Use device_unregister() instead of device_del/put()

Quoted 4 lines · Viresh Kumar

Lets not open code device_unregister() unnecessarily.

---

Quoted 17 lines
  drivers/thermal/thermal_core.c | 3 +--
  1 file changed, 1 insertion(+), 2 deletions(-)
drivers/thermal/thermal_core.c +1 -2
index 1fb109a97ff6..9fb37c5d9c4f 100644
@@ -1109,8 +1109,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
 
  	mutex_unlock(&thermal_list_lock);
 
-	device_del(&cdev->device);
-	put_device(&cdev->device);
+	device_unregister(&cdev->device);
  }
  EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);