kmb_probe() obtain a reference to a platform device by
of_find_device_by_node(). This call increases the reference count of
the returned device, which should be dropped by calling put_device()
when the device is no longer needed. However, the code fails to call
put_device() in several error handling paths and the normal device
removal path. This could result in reference count leaks that prevent
the proper cleanup of the platform device when the driver is unloaded
or during error recovery.

Add put_device() in all code paths where dsi_pdev is no longer needed,
including error paths and the normal removal path.

Found by code review.

Cc: [email protected]
Fixes: 7f7b96a8a0a1 ("drm/kmb: Add support for KeemBay Display")
Signed-off-by: Ma Ke <[email protected]>
---
 drivers/gpu/drm/kmb/kmb_drv.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c
index 32cda134ae3e..4fc9fdf92118 100644
--- a/drivers/gpu/drm/kmb/kmb_drv.c
+++ b/drivers/gpu/drm/kmb/kmb_drv.c
@@ -473,6 +473,8 @@ static void kmb_remove(struct platform_device *pdev)
 
        /* Unregister DSI host */
        kmb_dsi_host_unregister(kmb->kmb_dsi);
+       if (kmb->kmb_dsi && kmb->kmb_dsi->pdev)
+               put_device(&kmb->kmb_dsi->pdev->dev);
        drm_atomic_helper_shutdown(drm);
 }
 
@@ -517,17 +519,20 @@ static int kmb_probe(struct platform_device *pdev)
        ret = kmb_dsi_host_bridge_init(get_device(&dsi_pdev->dev));
 
        if (ret == -EPROBE_DEFER) {
-               return -EPROBE_DEFER;
+               ret = -EPROBE_DEFER;
+               goto err_free2;
        } else if (ret) {
                DRM_ERROR("probe failed to initialize DSI host bridge\n");
-               return ret;
+               goto err_free2;
        }
 
        /* Create DRM device */
        kmb = devm_drm_dev_alloc(dev, &kmb_driver,
                                 struct kmb_drm_private, drm);
-       if (IS_ERR(kmb))
-               return PTR_ERR(kmb);
+       if (IS_ERR(kmb)) {
+               ret = PTR_ERR(kmb);
+               goto err_free2;
+       }
 
        dev_set_drvdata(dev, &kmb->drm);
 
@@ -576,7 +581,8 @@ static int kmb_probe(struct platform_device *pdev)
  err_free1:
        dev_set_drvdata(dev, NULL);
        kmb_dsi_host_unregister(kmb->kmb_dsi);
-
+ err_free2:
+       put_device(&dsi_pdev->dev);
        return ret;
 }
 
-- 
2.17.1

Reply via email to