| From foo@baz Mon Apr 9 17:09:24 CEST 2018 |
| From: Jon Mason <jon.mason@broadcom.com> |
| Date: Wed, 10 May 2017 11:20:27 -0400 |
| Subject: mdio: mux: Correct mdio_mux_init error path issues |
| |
| From: Jon Mason <jon.mason@broadcom.com> |
| |
| |
| [ Upstream commit b60161668199ac62011c024adc9e66713b9554e7 ] |
| |
| There is a potential unnecessary refcount decrement on error path of |
| put_device(&pb->mii_bus->dev), as it is possible to avoid the |
| of_mdio_find_bus() call if mux_bus is specified by the calling function. |
| |
| The same put_device() is not called in the error path if the |
| devm_kzalloc of pb fails. This caused the variable used in the |
| put_device() to be changed, as the pb pointer was obviously not set up. |
| |
| There is an unnecessary of_node_get() on child_bus_node if the |
| of_mdiobus_register() is successful, as the |
| for_each_available_child_of_node() automatically increments this. |
| Thus the refcount on this node will always be +1 more than it should be. |
| |
| There is no of_node_put() on child_bus_node if the of_mdiobus_register() |
| call fails. |
| |
| Finally, it is lacking devm_kfree() of pb in the error path. While this |
| might not be technically necessary, it was present in other parts of the |
| function. So, I am adding it where necessary to make it uniform. |
| |
| Signed-off-by: Jon Mason <jon.mason@broadcom.com> |
| Fixes: f20e6657a875 ("mdio: mux: Enhanced MDIO mux framework for integrated multiplexers") |
| Fixes: 0ca2997d1452 ("netdev/of/phy: Add MDIO bus multiplexer support.") |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/phy/mdio-mux.c | 12 +++++++----- |
| 1 file changed, 7 insertions(+), 5 deletions(-) |
| |
| --- a/drivers/net/phy/mdio-mux.c |
| +++ b/drivers/net/phy/mdio-mux.c |
| @@ -122,10 +122,9 @@ int mdio_mux_init(struct device *dev, |
| pb = devm_kzalloc(dev, sizeof(*pb), GFP_KERNEL); |
| if (pb == NULL) { |
| ret_val = -ENOMEM; |
| - goto err_parent_bus; |
| + goto err_pb_kz; |
| } |
| |
| - |
| pb->switch_data = data; |
| pb->switch_fn = switch_fn; |
| pb->current_child = -1; |
| @@ -154,6 +153,7 @@ int mdio_mux_init(struct device *dev, |
| cb->mii_bus = mdiobus_alloc(); |
| if (!cb->mii_bus) { |
| ret_val = -ENOMEM; |
| + devm_kfree(dev, cb); |
| of_node_put(child_bus_node); |
| break; |
| } |
| @@ -169,8 +169,8 @@ int mdio_mux_init(struct device *dev, |
| if (r) { |
| mdiobus_free(cb->mii_bus); |
| devm_kfree(dev, cb); |
| + of_node_put(child_bus_node); |
| } else { |
| - of_node_get(child_bus_node); |
| cb->next = pb->children; |
| pb->children = cb; |
| } |
| @@ -181,9 +181,11 @@ int mdio_mux_init(struct device *dev, |
| return 0; |
| } |
| |
| + devm_kfree(dev, pb); |
| +err_pb_kz: |
| /* balance the reference of_mdio_find_bus() took */ |
| - put_device(&pb->mii_bus->dev); |
| - |
| + if (!mux_bus) |
| + put_device(&parent_bus->dev); |
| err_parent_bus: |
| of_node_put(parent_bus_node); |
| return ret_val; |