[PATCH 1/3] media: i2c: gc0310: fix probe error handling and unwind resources properly

Sanjay Chitroda
2026-04-01T18:17:05Z

From: Sanjay Chitroda <sanjayembeddedse@gmail.com>

The GC0310 probe path currently performs error cleanup by jumping to a
common label that mirrors the driver's remove() callback. This is unsafe,
as remove() assumes that the subdevice has been fully registered with
the V4L2 framework, media and control resources have been initialized.

Calling remove() from probe can result in unregistering or cleaning up
subdevice, leading to resource leaks and subtle lifecycle bugs.

Rewrite the probe() error handling to unwind resources explicitly, using
fine‑grained goto labels along with appropriate error logs. Each failure
path now frees only successfully acquired resource, without remove().

This aligns the driver with standard V4L2 sensor lifecycle expectations
and avoids incorrect teardown during probe failures.

Fixes: 1e72afb5146a ("media: Move gc0310 sensor drivers to drivers/media/i2c/")
Signed-off-by: Sanjay Chitroda <sanjayembeddedse@gmail.com>
---
drivers/media/i2c/gc0310.c | 39 ++++++++++++++++++++++++++++----------
1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/drivers/media/i2c/gc0310.c b/drivers/media/i2c/gc0310.c
index 7af4d66f42a0..72a82ad4118a 100644
--- a/drivers/media/i2c/gc0310.c
+++ b/drivers/media/i2c/gc0310.c
@@ -721,7 +721,7 @@ static int gc0310_probe(struct i2c_client *client)

ret = gc0310_detect(sensor);
if (ret)
- goto err_power_down;
+ goto error_power_off;

sensor->sd.internal_ops = &gc0310_internal_ops;
sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -730,20 +730,27 @@ static int gc0310_probe(struct i2c_client *client)

ret = gc0310_init_controls(sensor);
if (ret)
- goto err_power_down;
+ goto error_power_off;

ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
- if (ret)
- goto err_power_down;
+ if (ret) {
+ dev_err_probe(&client->dev, ret, "failed to init entity pads\n");
+ goto error_handler_free;
+ }

sensor->sd.state_lock = sensor->ctrls.handler.lock;
ret = v4l2_subdev_init_finalize(&sensor->sd);
- if (ret)
- goto err_power_down;
+ if (ret) {
+ dev_err_probe(&client->dev, ret, "subdev init error\n");
+ goto error_media_entity;
+ }

ret = v4l2_async_register_subdev_sensor(&sensor->sd);
- if (ret)
- goto err_power_down;
+ if (ret) {
+ dev_err_probe(&client->dev, ret,
+ "failed to register gc0310 sub-device\n");
+ goto error_subdev_cleanup;
+ }

pm_runtime_set_autosuspend_delay(&client->dev, 1000);
pm_runtime_use_autosuspend(&client->dev);
@@ -751,9 +758,21 @@ static int gc0310_probe(struct i2c_client *client)

return 0;

-err_power_down:
+error_subdev_cleanup:
+ v4l2_subdev_cleanup(&sensor->sd);
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+error_media_entity:
+ media_entity_cleanup(&sensor->sd.entity);
+
+error_handler_free:
+ v4l2_ctrl_handler_free(&sensor->ctrls.handler);
+
+error_power_off:
pm_runtime_put_noidle(&client->dev);
- gc0310_remove(client);
+ gc0310_power_off(&client->dev);
+
return ret;
}

--
2.34.1