bonding: fix panic when taking bond interface down before removing module
authorAndy Gospodarek <andy@greyhouse.net>
Fri, 31 Oct 2008 00:41:16 +0000 (17:41 -0700)
committerJeff Garzik <jgarzik@redhat.com>
Fri, 31 Oct 2008 04:46:12 +0000 (00:46 -0400)
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 <andy@greyhouse.net>
Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
drivers/net/bonding/bond_alb.c

index ade5f3f6693bef27e4d006d2b370ace1956339af..87437c788476ab8a05df31a0f7fd1887ffeef497 100644 (file)
@@ -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);