MIPS: SGI-IP30: Fix platform-device leak in bridge_platform_create()
authorLin Yujun <linyujun809@huawei.com>
Wed, 14 Sep 2022 03:28:07 +0000 (11:28 +0800)
committerThomas Bogendoerfer <tsbogend@alpha.franken.de>
Mon, 19 Sep 2022 14:32:54 +0000 (16:32 +0200)
In error case in bridge_platform_create after calling
platform_device_add()/platform_device_add_data()/
platform_device_add_resources(), release the failed
'pdev' or it will be leak, call platform_device_put()
to fix this problem.

Besides, 'pdev' is divided into 'pdev_wd' and 'pdev_bd',
use platform_device_unregister() to release sgi_w1
resources when xtalk-bridge registration fails.

Fixes: fd27234f24ae ("MIPS: add support for SGI Octane (IP30)")
Signed-off-by: Lin Yujun <linyujun809@huawei.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
arch/mips/sgi-ip30/ip30-xtalk.c

index 8129524..7ceb2b2 100644 (file)
@@ -40,12 +40,15 @@ static void bridge_platform_create(int widget, int masterwid)
 {
        struct xtalk_bridge_platform_data *bd;
        struct sgi_w1_platform_data *wd;
-       struct platform_device *pdev;
+       struct platform_device *pdev_wd;
+       struct platform_device *pdev_bd;
        struct resource w1_res;
 
        wd = kzalloc(sizeof(*wd), GFP_KERNEL);
-       if (!wd)
-               goto no_mem;
+       if (!wd) {
+               pr_warn("xtalk:%x bridge create out of memory\n", widget);
+               return;
+       }
 
        snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx",
                 IP30_SWIN_BASE(widget));
@@ -56,24 +59,35 @@ static void bridge_platform_create(int widget, int masterwid)
        w1_res.end = w1_res.start + 3;
        w1_res.flags = IORESOURCE_MEM;
 
-       pdev = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO);
-       if (!pdev) {
-               kfree(wd);
-               goto no_mem;
+       pdev_wd = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO);
+       if (!pdev_wd) {
+               pr_warn("xtalk:%x bridge create out of memory\n", widget);
+               goto err_kfree_wd;
+       }
+       if (platform_device_add_resources(pdev_wd, &w1_res, 1)) {
+               pr_warn("xtalk:%x bridge failed to add platform resources.\n", widget);
+               goto err_put_pdev_wd;
+       }
+       if (platform_device_add_data(pdev_wd, wd, sizeof(*wd))) {
+               pr_warn("xtalk:%x bridge failed to add platform data.\n", widget);
+               goto err_put_pdev_wd;
+       }
+       if (platform_device_add(pdev_wd)) {
+               pr_warn("xtalk:%x bridge failed to add platform device.\n", widget);
+               goto err_put_pdev_wd;
        }
-       platform_device_add_resources(pdev, &w1_res, 1);
-       platform_device_add_data(pdev, wd, sizeof(*wd));
        /* platform_device_add_data() duplicates the data */
        kfree(wd);
-       platform_device_add(pdev);
 
        bd = kzalloc(sizeof(*bd), GFP_KERNEL);
-       if (!bd)
-               goto no_mem;
-       pdev = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
-       if (!pdev) {
-               kfree(bd);
-               goto no_mem;
+       if (!bd) {
+               pr_warn("xtalk:%x bridge create out of memory\n", widget);
+               goto err_unregister_pdev_wd;
+       }
+       pdev_bd = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
+       if (!pdev_bd) {
+               pr_warn("xtalk:%x bridge create out of memory\n", widget);
+               goto err_kfree_bd;
        }
 
        bd->bridge_addr = IP30_RAW_SWIN_BASE(widget);
@@ -93,15 +107,31 @@ static void bridge_platform_create(int widget, int masterwid)
        bd->io.flags    = IORESOURCE_IO;
        bd->io_offset   = IP30_SWIN_BASE(widget);
 
-       platform_device_add_data(pdev, bd, sizeof(*bd));
+       if (platform_device_add_data(pdev_bd, bd, sizeof(*bd))) {
+               pr_warn("xtalk:%x bridge failed to add platform data.\n", widget);
+               goto err_put_pdev_bd;
+       }
+       if (platform_device_add(pdev_bd)) {
+               pr_warn("xtalk:%x bridge failed to add platform device.\n", widget);
+               goto err_put_pdev_bd;
+       }
        /* platform_device_add_data() duplicates the data */
        kfree(bd);
-       platform_device_add(pdev);
        pr_info("xtalk:%x bridge widget\n", widget);
        return;
 
-no_mem:
-       pr_warn("xtalk:%x bridge create out of memory\n", widget);
+err_put_pdev_bd:
+       platform_device_put(pdev_bd);
+err_kfree_bd:
+       kfree(bd);
+err_unregister_pdev_wd:
+       platform_device_unregister(pdev_wd);
+       return;
+err_put_pdev_wd:
+       platform_device_put(pdev_wd);
+err_kfree_wd:
+       kfree(wd);
+       return;
 }
 
 static unsigned int __init xbow_widget_active(s8 wid)