bonding: fix set_multicast_list locking
authorJay Vosburgh <fubar@us.ibm.com>
Wed, 30 Jan 2008 02:07:44 +0000 (18:07 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sun, 3 Feb 2008 12:28:12 +0000 (04:28 -0800)
This patch eliminates a problem (reported by lockdep) in the
bond_set_multicast_list function.  It first reduces the locking on
bond->lock to a simple read_lock, and second, adds netif_tx locking
around the bonding mc_list manipulations that occur outside of the
set_multicast_list function.

The original problem was related to IPv6 addrconf activity.

Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/bonding/bond_main.c

index 2766855a5aeec1f96502d3cdcf021df87a6ace2b..65c7ebafaacd7e0caa734bef1f6d0cbfe5631962 100644 (file)
@@ -1464,10 +1464,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                        dev_set_allmulti(slave_dev, 1);
                }
 
+               netif_tx_lock_bh(bond_dev);
                /* upload master's mc_list to new slave */
                for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) {
                        dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
                }
+               netif_tx_unlock_bh(bond_dev);
        }
 
        if (bond->params.mode == BOND_MODE_8023AD) {
@@ -1821,7 +1823,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
                }
 
                /* flush master's mc_list from slave */
+               netif_tx_lock_bh(bond_dev);
                bond_mc_list_flush(bond_dev, slave_dev);
+               netif_tx_unlock_bh(bond_dev);
        }
 
        netdev_set_master(slave_dev, NULL);
@@ -1942,7 +1946,9 @@ static int bond_release_all(struct net_device *bond_dev)
                        }
 
                        /* flush master's mc_list from slave */
+                       netif_tx_lock_bh(bond_dev);
                        bond_mc_list_flush(bond_dev, slave_dev);
+                       netif_tx_unlock_bh(bond_dev);
                }
 
                netdev_set_master(slave_dev, NULL);
@@ -3937,8 +3943,6 @@ static void bond_set_multicast_list(struct net_device *bond_dev)
        struct bonding *bond = bond_dev->priv;
        struct dev_mc_list *dmi;
 
-       write_lock_bh(&bond->lock);
-
        /*
         * Do promisc before checking multicast_mode
         */
@@ -3959,6 +3963,8 @@ static void bond_set_multicast_list(struct net_device *bond_dev)
                bond_set_allmulti(bond, -1);
        }
 
+       read_lock(&bond->lock);
+
        bond->flags = bond_dev->flags;
 
        /* looking for addresses to add to slaves' mc list */
@@ -3979,7 +3985,7 @@ static void bond_set_multicast_list(struct net_device *bond_dev)
        bond_mc_list_destroy(bond);
        bond_mc_list_copy(bond_dev->mc_list, bond, GFP_ATOMIC);
 
-       write_unlock_bh(&bond->lock);
+       read_unlock(&bond->lock);
 }
 
 /*
@@ -4526,7 +4532,9 @@ static void bond_free_all(void)
                struct net_device *bond_dev = bond->dev;
 
                bond_work_cancel_all(bond);
+               netif_tx_lock_bh(bond_dev);
                bond_mc_list_destroy(bond);
+               netif_tx_unlock_bh(bond_dev);
                /* Release the bonded slaves */
                bond_release_all(bond_dev);
                bond_deinit(bond_dev);