net: thunderx: Don't leak phy device references on -EPROBE_DEFER condition.
authorDavid Daney <david.daney@cavium.com>
Tue, 15 Mar 2016 00:30:39 +0000 (17:30 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 Mar 2016 23:55:37 +0000 (19:55 -0400)
It is possible, although unlikely, that probing will find the
phy_device for the first LMAC of a thunder BGX device, but then need
to fail with -EPROBE_DEFER on a subsequent LMAC.  In this case, we
need to call put_device() on each of the phy_devices that were
obtained, but will be unused due to returning -EPROBE_DEFER.

Also, since we can break out of the probing loop early, we need to
explicitly call of_node_put() outside of the loop.

Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/cavium/thunder/thunder_bgx.c

index feed2318201b28da9d2c4de6b53e100b1691cd17..967951582e033d8a34a3463d5047f15bb7c26219 100644 (file)
@@ -974,17 +974,18 @@ static int bgx_init_acpi_phy(struct bgx *bgx)
 static int bgx_init_of_phy(struct bgx *bgx)
 {
        struct fwnode_handle *fwn;
+       struct device_node *node = NULL;
        u8 lmac = 0;
-       const char *mac;
 
        device_for_each_child_node(&bgx->pdev->dev, fwn) {
                struct phy_device *pd;
                struct device_node *phy_np;
-               struct device_node *node = to_of_node(fwn);
+               const char *mac;
 
                /* Should always be an OF node.  But if it is not, we
                 * cannot handle it, so exit the loop.
                 */
+               node = to_of_node(fwn);
                if (!node)
                        break;
 
@@ -1005,17 +1006,30 @@ static int bgx_init_of_phy(struct bgx *bgx)
                        /* Wait until the phy drivers are available */
                        pd = of_phy_find_device(phy_np);
                        if (!pd)
-                               return -EPROBE_DEFER;
+                               goto defer;
                        bgx->lmac[lmac].phydev = pd;
                }
 
                lmac++;
-               if (lmac == MAX_LMAC_PER_BGX) {
-                       of_node_put(node);
+               if (lmac == MAX_LMAC_PER_BGX)
                        break;
-               }
        }
+       of_node_put(node);
        return 0;
+
+defer:
+       /* We are bailing out, try not to leak device reference counts
+        * for phy devices we may have already found.
+        */
+       while (lmac) {
+               if (bgx->lmac[lmac].phydev) {
+                       put_device(&bgx->lmac[lmac].phydev->mdio.dev);
+                       bgx->lmac[lmac].phydev = NULL;
+               }
+               lmac--;
+       }
+       of_node_put(node);
+       return -EPROBE_DEFER;
 }
 
 #else