aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2015-09-24 15:35:57 -0400
committerDavid S. Miller <davem@davemloft.net>2015-09-25 02:04:52 -0400
commite496ae690b2faff751e1849fb97b060615e21f28 (patch)
treee32e9642246190efcb59077b698a6398928f0d65 /net
parenta136442131443d929d2d8d243157824de4dfbae8 (diff)
net: dsa: fix of_mdio_find_bus() device refcount leak
Current users of of_mdio_find_bus() leak a struct device refcount, as they fail to clean up the reference obtained inside class_find_device(). Fix the DSA code to properly refcount the returned MDIO bus by: 1. taking a reference on the struct device whenever we assign it to pd->chip[x].host_dev. 2. dropping the reference when we overwrite the existing reference. 3. dropping the reference when we free the data structure. 4. dropping the initial reference we obtained after setting up the platform data structure, or on failure. In step 2 above, where we obtain a new MDIO bus, there is no need to take a reference on it as we would only have to drop it immediately after assignment again, iow: put_device(cd->host_dev); /* drop original assignment ref */ cd->host_dev = get_device(&mdio_bus_switch->dev); /* get our ref */ put_device(&mdio_bus_switch->dev); /* drop of_mdio_find_bus ref */ Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/dsa/dsa.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 76e3800765f8..bf4ba15fb780 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -634,6 +634,10 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd)
634 port_index++; 634 port_index++;
635 } 635 }
636 kfree(pd->chip[i].rtable); 636 kfree(pd->chip[i].rtable);
637
638 /* Drop our reference to the MDIO bus device */
639 if (pd->chip[i].host_dev)
640 put_device(pd->chip[i].host_dev);
637 } 641 }
638 kfree(pd->chip); 642 kfree(pd->chip);
639} 643}
@@ -661,16 +665,22 @@ static int dsa_of_probe(struct device *dev)
661 return -EPROBE_DEFER; 665 return -EPROBE_DEFER;
662 666
663 ethernet = of_parse_phandle(np, "dsa,ethernet", 0); 667 ethernet = of_parse_phandle(np, "dsa,ethernet", 0);
664 if (!ethernet) 668 if (!ethernet) {
665 return -EINVAL; 669 ret = -EINVAL;
670 goto out_put_mdio;
671 }
666 672
667 ethernet_dev = of_find_net_device_by_node(ethernet); 673 ethernet_dev = of_find_net_device_by_node(ethernet);
668 if (!ethernet_dev) 674 if (!ethernet_dev) {
669 return -EPROBE_DEFER; 675 ret = -EPROBE_DEFER;
676 goto out_put_mdio;
677 }
670 678
671 pd = kzalloc(sizeof(*pd), GFP_KERNEL); 679 pd = kzalloc(sizeof(*pd), GFP_KERNEL);
672 if (!pd) 680 if (!pd) {
673 return -ENOMEM; 681 ret = -ENOMEM;
682 goto out_put_mdio;
683 }
674 684
675 dev->platform_data = pd; 685 dev->platform_data = pd;
676 pd->of_netdev = ethernet_dev; 686 pd->of_netdev = ethernet_dev;
@@ -691,7 +701,9 @@ static int dsa_of_probe(struct device *dev)
691 cd = &pd->chip[chip_index]; 701 cd = &pd->chip[chip_index];
692 702
693 cd->of_node = child; 703 cd->of_node = child;
694 cd->host_dev = &mdio_bus->dev; 704
705 /* When assigning the host device, increment its refcount */
706 cd->host_dev = get_device(&mdio_bus->dev);
695 707
696 sw_addr = of_get_property(child, "reg", NULL); 708 sw_addr = of_get_property(child, "reg", NULL);
697 if (!sw_addr) 709 if (!sw_addr)
@@ -711,6 +723,12 @@ static int dsa_of_probe(struct device *dev)
711 ret = -EPROBE_DEFER; 723 ret = -EPROBE_DEFER;
712 goto out_free_chip; 724 goto out_free_chip;
713 } 725 }
726
727 /* Drop the mdio_bus device ref, replacing the host
728 * device with the mdio_bus_switch device, keeping
729 * the refcount from of_mdio_find_bus() above.
730 */
731 put_device(cd->host_dev);
714 cd->host_dev = &mdio_bus_switch->dev; 732 cd->host_dev = &mdio_bus_switch->dev;
715 } 733 }
716 734
@@ -744,6 +762,10 @@ static int dsa_of_probe(struct device *dev)
744 } 762 }
745 } 763 }
746 764
765 /* The individual chips hold their own refcount on the mdio bus,
766 * so drop ours */
767 put_device(&mdio_bus->dev);
768
747 return 0; 769 return 0;
748 770
749out_free_chip: 771out_free_chip:
@@ -751,6 +773,8 @@ out_free_chip:
751out_free: 773out_free:
752 kfree(pd); 774 kfree(pd);
753 dev->platform_data = NULL; 775 dev->platform_data = NULL;
776out_put_mdio:
777 put_device(&mdio_bus->dev);
754 return ret; 778 return ret;
755} 779}
756 780