]> git.itanic.dy.fi Git - linux-stable/commitdiff
net: fec: Better handle pm_runtime_get() failing in .remove()
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Wed, 10 May 2023 20:00:20 +0000 (22:00 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 30 May 2023 11:38:36 +0000 (12:38 +0100)
[ Upstream commit f816b9829b19394d318e01953aa3b2721bca040d ]

In the (unlikely) event that pm_runtime_get() (disguised as
pm_runtime_resume_and_get()) fails, the remove callback returned an
error early. The problem with this is that the driver core ignores the
error value and continues removing the device. This results in a
resource leak. Worse the devm allocated resources are freed and so if a
callback of the driver is called later the register mapping is already
gone which probably results in a crash.

Fixes: a31eda65ba21 ("net: fec: fix clock count mis-match")
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20230510200020.1534610-1-u.kleine-koenig@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/ethernet/freescale/fec_main.c

index c6fc77a211ea6ebb26fc0be292e72276ad23bcab..1085f1d721b028ab4c0c56ad7215d3ee11b8dc7c 100644 (file)
@@ -3569,7 +3569,9 @@ fec_drv_remove(struct platform_device *pdev)
 
        ret = pm_runtime_get_sync(&pdev->dev);
        if (ret < 0)
-               return ret;
+               dev_err(&pdev->dev,
+                       "Failed to resume device in remove callback (%pe)\n",
+                       ERR_PTR(ret));
 
        cancel_work_sync(&fep->tx_timeout_work);
        fec_ptp_stop(pdev);
@@ -3582,8 +3584,13 @@ fec_drv_remove(struct platform_device *pdev)
                of_phy_deregister_fixed_link(np);
        of_node_put(fep->phy_node);
 
-       clk_disable_unprepare(fep->clk_ahb);
-       clk_disable_unprepare(fep->clk_ipg);
+       /* After pm_runtime_get_sync() failed, the clks are still off, so skip
+        * disabling them again.
+        */
+       if (ret >= 0) {
+               clk_disable_unprepare(fep->clk_ahb);
+               clk_disable_unprepare(fep->clk_ipg);
+       }
        pm_runtime_put_noidle(&pdev->dev);
        pm_runtime_disable(&pdev->dev);