From fba4acda35f3119328bcba28aacefae14245d2bb Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Thu, 30 Oct 2008 17:41:14 -0700 Subject: bonding: fix miimon failure counter During the rework of the mii monitor for: commit f0c76d61779b153dbfb955db3f144c62d02173c2 Author: Jay Vosburgh Date: Wed Jul 2 18:21:58 2008 -0700 bonding: refactor mii monitor I left out the increment of the link failure counter. This patch corrects that omission. Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/bonding') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 832739f38db4..85de1d04d1ee 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2376,6 +2376,9 @@ static void bond_miimon_commit(struct bonding *bond) continue; case BOND_LINK_DOWN: + if (slave->link_failure_count < UINT_MAX) + slave->link_failure_count++; + slave->link = BOND_LINK_DOWN; if (bond->params.mode == BOND_MODE_ACTIVEBACKUP || -- cgit v1.2.3 From a434e43f3d844192bc23bd7b408bac979c40efe7 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Thu, 30 Oct 2008 17:41:15 -0700 Subject: bonding: Clean up resource leaks This patch reworks the resource free logic performed at the time a bonding device is released. This (a) closes two resource leaks, one for workqueues and one for multicast lists, and (b) improves commonality of code between the "destroy one" and "destroy all" paths by performing final free activity via destructor instead of explicitly (and differently) in each path. "Sean E. Millichamp" reported the workqueue leak, and included a different patch. Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 49 ++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 18 deletions(-) (limited to 'drivers/net/bonding') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 85de1d04d1ee..a3efba59eee9 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1979,6 +1979,20 @@ void bond_destroy(struct bonding *bond) unregister_netdevice(bond->dev); } +static void bond_destructor(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + + if (bond->wq) + destroy_workqueue(bond->wq); + + netif_addr_lock_bh(bond_dev); + bond_mc_list_destroy(bond); + netif_addr_unlock_bh(bond_dev); + + free_netdev(bond_dev); +} + /* * First release a slave and than destroy the bond if no more slaves iare left. * Must be under rtnl_lock when this function is called. @@ -4553,7 +4567,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) bond_set_mode_ops(bond, bond->params.mode); - bond_dev->destructor = free_netdev; + bond_dev->destructor = bond_destructor; /* Initialize the device options */ bond_dev->tx_queue_len = 0; @@ -4592,20 +4606,6 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) return 0; } -/* De-initialize device specific data. - * Caller must hold rtnl_lock. - */ -static void bond_deinit(struct net_device *bond_dev) -{ - struct bonding *bond = bond_dev->priv; - - list_del(&bond->bond_list); - -#ifdef CONFIG_PROC_FS - bond_remove_proc_entry(bond); -#endif -} - static void bond_work_cancel_all(struct bonding *bond) { write_lock_bh(&bond->lock); @@ -4627,6 +4627,22 @@ static void bond_work_cancel_all(struct bonding *bond) cancel_delayed_work(&bond->ad_work); } +/* De-initialize device specific data. + * Caller must hold rtnl_lock. + */ +static void bond_deinit(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + + list_del(&bond->bond_list); + + bond_work_cancel_all(bond); + +#ifdef CONFIG_PROC_FS + bond_remove_proc_entry(bond); +#endif +} + /* Unregister and free all bond devices. * Caller must hold rtnl_lock. */ @@ -4638,9 +4654,6 @@ static void bond_free_all(void) struct net_device *bond_dev = bond->dev; bond_work_cancel_all(bond); - netif_addr_lock_bh(bond_dev); - bond_mc_list_destroy(bond); - netif_addr_unlock_bh(bond_dev); /* Release the bonded slaves */ bond_release_all(bond_dev); bond_destroy(bond); -- cgit v1.2.3 From ce39a800ea87c655de49af021c8b20ee323cb40d Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Thu, 30 Oct 2008 17:41:16 -0700 Subject: bonding: fix panic when taking bond interface down before removing module A panic was discovered with bonding when using mode 5 or 6 and trying to remove the slaves from the bond after the interface was taken down. When calling 'ifconfig bond0 down' the following happens: bond_close() bond_alb_deinitialize() tlb_deinitialize() kfree(bond_info->tx_hashtbl) bond_info->tx_hashtbl = NULL Unfortunately if there are still slaves in the bond, when removing the module the following happens: bonding_exit() bond_free_all() bond_release_all() bond_alb_deinit_slave() tlb_clear_slave() tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl u32 next_index = tx_hash_table[index].next As you might guess we panic when trying to access a few entries into the table that no longer exists. I experimented with several options (like moving the calls to tlb_deinitialize somewhere else), but it really makes the most sense to be part of the bond_close routine. It also didn't seem logical move tlb_clear_slave around too much, so the simplest option seems to add a check in tlb_clear_slave to make sure we haven't already wiped the tx_hashtbl away before searching for all the non-existent hash-table entries that used to point to the slave as the output interface. Signed-off-by: Andy Gospodarek Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_alb.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/net/bonding') diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index ade5f3f6693b..87437c788476 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -169,11 +169,14 @@ static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_ /* clear slave from tx_hashtbl */ tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl; - index = SLAVE_TLB_INFO(slave).head; - while (index != TLB_NULL_INDEX) { - u32 next_index = tx_hash_table[index].next; - tlb_init_table_entry(&tx_hash_table[index], save_load); - index = next_index; + /* skip this if we've already freed the tx hash table */ + if (tx_hash_table) { + index = SLAVE_TLB_INFO(slave).head; + while (index != TLB_NULL_INDEX) { + u32 next_index = tx_hash_table[index].next; + tlb_init_table_entry(&tx_hash_table[index], save_load); + index = next_index; + } } tlb_init_slave(slave); -- cgit v1.2.3