]> err.no Git - linux-2.6/blobdiff - drivers/net/bonding/bond_main.c
ath5k: Misc hw_attach fixes
[linux-2.6] / drivers / net / bonding / bond_main.c
index 5b4af3cc2a44231ecae682180abc0e3ac3d77ef2..a641eeaa2a2f488bdef9a074e431c187321135f7 100644 (file)
@@ -772,39 +772,49 @@ static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct
 /*
  * Push the promiscuity flag down to appropriate slaves
  */
-static void bond_set_promiscuity(struct bonding *bond, int inc)
+static int bond_set_promiscuity(struct bonding *bond, int inc)
 {
+       int err = 0;
        if (USES_PRIMARY(bond->params.mode)) {
                /* write lock already acquired */
                if (bond->curr_active_slave) {
-                       dev_set_promiscuity(bond->curr_active_slave->dev, inc);
+                       err = dev_set_promiscuity(bond->curr_active_slave->dev,
+                                                 inc);
                }
        } else {
                struct slave *slave;
                int i;
                bond_for_each_slave(bond, slave, i) {
-                       dev_set_promiscuity(slave->dev, inc);
+                       err = dev_set_promiscuity(slave->dev, inc);
+                       if (err)
+                               return err;
                }
        }
+       return err;
 }
 
 /*
  * Push the allmulti flag down to all slaves
  */
-static void bond_set_allmulti(struct bonding *bond, int inc)
+static int bond_set_allmulti(struct bonding *bond, int inc)
 {
+       int err = 0;
        if (USES_PRIMARY(bond->params.mode)) {
                /* write lock already acquired */
                if (bond->curr_active_slave) {
-                       dev_set_allmulti(bond->curr_active_slave->dev, inc);
+                       err = dev_set_allmulti(bond->curr_active_slave->dev,
+                                              inc);
                }
        } else {
                struct slave *slave;
                int i;
                bond_for_each_slave(bond, slave, i) {
-                       dev_set_allmulti(slave->dev, inc);
+                       err = dev_set_allmulti(slave->dev, inc);
+                       if (err)
+                               return err;
                }
        }
+       return err;
 }
 
 /*
@@ -965,6 +975,7 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct
        }
 
        if (new_active) {
+               /* FIXME: Signal errors upstream. */
                if (bond->dev->flags & IFF_PROMISC) {
                        dev_set_promiscuity(new_active->dev, 1);
                }
@@ -1189,22 +1200,21 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
 
                if (new_active) {
                        bond_set_slave_active_flags(new_active);
-               }
 
-               if (new_active && bond->params.fail_over_mac)
-                       bond_do_fail_over_mac(bond, new_active, old_active);
+                       if (bond->params.fail_over_mac)
+                               bond_do_fail_over_mac(bond, new_active,
+                                                     old_active);
 
-               bond->send_grat_arp = bond->params.num_grat_arp;
-               if (bond->curr_active_slave &&
-                       test_bit(__LINK_STATE_LINKWATCH_PENDING,
-                                       &bond->curr_active_slave->dev->state)) {
-                       dprintk("delaying gratuitous arp on %s\n",
-                               bond->curr_active_slave->dev->name);
-               } else {
-                       if (bond->send_grat_arp > 0) {
-                               bond_send_gratuitous_arp(bond);
-                               bond->send_grat_arp--;
-                       }
+                       bond->send_grat_arp = bond->params.num_grat_arp;
+                       bond_send_gratuitous_arp(bond);
+
+                       write_unlock_bh(&bond->curr_slave_lock);
+                       read_unlock(&bond->lock);
+
+                       netdev_bonding_change(bond->dev);
+
+                       read_lock(&bond->lock);
+                       write_lock_bh(&bond->curr_slave_lock);
                }
        }
 }
@@ -1545,20 +1555,24 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        if (!USES_PRIMARY(bond->params.mode)) {
                /* set promiscuity level to new slave */
                if (bond_dev->flags & IFF_PROMISC) {
-                       dev_set_promiscuity(slave_dev, 1);
+                       res = dev_set_promiscuity(slave_dev, 1);
+                       if (res)
+                               goto err_close;
                }
 
                /* set allmulti level to new slave */
                if (bond_dev->flags & IFF_ALLMULTI) {
-                       dev_set_allmulti(slave_dev, 1);
+                       res = dev_set_allmulti(slave_dev, 1);
+                       if (res)
+                               goto err_close;
                }
 
-               netif_tx_lock_bh(bond_dev);
+               netif_addr_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);
+               netif_addr_unlock_bh(bond_dev);
        }
 
        if (bond->params.mode == BOND_MODE_8023AD) {
@@ -1922,9 +1936,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);
+               netif_addr_lock_bh(bond_dev);
                bond_mc_list_flush(bond_dev, slave_dev);
-               netif_tx_unlock_bh(bond_dev);
+               netif_addr_unlock_bh(bond_dev);
        }
 
        netdev_set_master(slave_dev, NULL);
@@ -2045,9 +2059,9 @@ static int bond_release_all(struct net_device *bond_dev)
                        }
 
                        /* flush master's mc_list from slave */
-                       netif_tx_lock_bh(bond_dev);
+                       netif_addr_lock_bh(bond_dev);
                        bond_mc_list_flush(bond_dev, slave_dev);
-                       netif_tx_unlock_bh(bond_dev);
+                       netif_addr_unlock_bh(bond_dev);
                }
 
                netdev_set_master(slave_dev, NULL);
@@ -2235,17 +2249,6 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks)
         * program could monitor the link itself if needed.
         */
 
-       if (bond->send_grat_arp) {
-               if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING,
-                               &bond->curr_active_slave->dev->state))
-                       dprintk("Needs to send gratuitous arp but not yet\n");
-               else {
-                       dprintk("sending delayed gratuitous arp on on %s\n",
-                               bond->curr_active_slave->dev->name);
-                       bond_send_gratuitous_arp(bond);
-                       bond->send_grat_arp--;
-               }
-       }
        read_lock(&bond->curr_slave_lock);
        oldcurrent = bond->curr_active_slave;
        read_unlock(&bond->curr_slave_lock);
@@ -2486,6 +2489,13 @@ void bond_mii_monitor(struct work_struct *work)
                read_unlock(&bond->lock);
                return;
        }
+
+       if (bond->send_grat_arp) {
+               read_lock(&bond->curr_slave_lock);
+               bond_send_gratuitous_arp(bond);
+               read_unlock(&bond->curr_slave_lock);
+       }
+
        if (__bond_mii_monitor(bond, 0)) {
                read_unlock(&bond->lock);
                rtnl_lock();
@@ -2651,6 +2661,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
 /*
  * Kick out a gratuitous ARP for an IP on the bonding master plus one
  * for each VLAN above us.
+ *
+ * Caller must hold curr_slave_lock for read or better
  */
 static void bond_send_gratuitous_arp(struct bonding *bond)
 {
@@ -2660,9 +2672,13 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
 
        dprintk("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name,
                                slave ? slave->dev->name : "NULL");
-       if (!slave)
+
+       if (!slave || !bond->send_grat_arp ||
+           test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
                return;
 
+       bond->send_grat_arp--;
+
        if (bond->master_ip) {
                bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip,
                                bond->master_ip, 0);
@@ -3166,6 +3182,12 @@ void bond_activebackup_arp_mon(struct work_struct *work)
        if (bond->slave_cnt == 0)
                goto re_arm;
 
+       if (bond->send_grat_arp) {
+               read_lock(&bond->curr_slave_lock);
+               bond_send_gratuitous_arp(bond);
+               read_unlock(&bond->curr_slave_lock);
+       }
+
        if (bond_ab_arp_inspect(bond, delta_in_ticks)) {
                read_unlock(&bond->lock);
                rtnl_lock();
@@ -3840,6 +3862,7 @@ static int bond_close(struct net_device *bond_dev)
 
        write_lock_bh(&bond->lock);
 
+       bond->send_grat_arp = 0;
 
        /* signal timers not to re-arm */
        bond->kill_timers = 1;
@@ -4057,6 +4080,10 @@ static void bond_set_multicast_list(struct net_device *bond_dev)
         * Do promisc before checking multicast_mode
         */
        if ((bond_dev->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC)) {
+               /*
+                * FIXME: Need to handle the error when one of the multi-slaves
+                * encounters error.
+                */
                bond_set_promiscuity(bond, 1);
        }
 
@@ -4066,6 +4093,10 @@ static void bond_set_multicast_list(struct net_device *bond_dev)
 
        /* set allmulti flag to slaves */
        if ((bond_dev->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI)) {
+               /*
+                * FIXME: Need to handle the error when one of the multi-slaves
+                * encounters error.
+                */
                bond_set_allmulti(bond, 1);
        }
 
@@ -4642,9 +4673,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);
+               netif_addr_lock_bh(bond_dev);
                bond_mc_list_destroy(bond);
-               netif_tx_unlock_bh(bond_dev);
+               netif_addr_unlock_bh(bond_dev);
                /* Release the bonded slaves */
                bond_release_all(bond_dev);
                bond_destroy(bond);
@@ -4742,11 +4773,11 @@ static int bond_check_params(struct bond_params *params)
                }
        }
 
-       if (max_bonds < 1 || max_bonds > INT_MAX) {
+       if (max_bonds < 0 || max_bonds > INT_MAX) {
                printk(KERN_WARNING DRV_NAME
                       ": Warning: max_bonds (%d) not in range %d-%d, so it "
                       "was reset to BOND_DEFAULT_MAX_BONDS (%d)\n",
-                      max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS);
+                      max_bonds, 0, INT_MAX, BOND_DEFAULT_MAX_BONDS);
                max_bonds = BOND_DEFAULT_MAX_BONDS;
        }
 
@@ -4945,7 +4976,7 @@ static int bond_check_params(struct bond_params *params)
 
                printk("\n");
 
-       } else {
+       } else if (max_bonds) {
                /* miimon and arp_interval not set, we need one so things
                 * work as expected, see bonding.txt for details
                 */
@@ -5010,6 +5041,22 @@ static int bond_check_params(struct bond_params *params)
 }
 
 static struct lock_class_key bonding_netdev_xmit_lock_key;
+static struct lock_class_key bonding_netdev_addr_lock_key;
+
+static void bond_set_lockdep_class_one(struct net_device *dev,
+                                      struct netdev_queue *txq,
+                                      void *_unused)
+{
+       lockdep_set_class(&txq->_xmit_lock,
+                         &bonding_netdev_xmit_lock_key);
+}
+
+static void bond_set_lockdep_class(struct net_device *dev)
+{
+       lockdep_set_class(&dev->addr_list_lock,
+                         &bonding_netdev_addr_lock_key);
+       netdev_for_each_tx_queue(dev, bond_set_lockdep_class_one, NULL);
+}
 
 /* Create a new bond based on the specified name and bonding parameters.
  * If name is NULL, obtain a suitable "bond%d" name for us.
@@ -5068,7 +5115,7 @@ int bond_create(char *name, struct bond_params *params)
                goto out_bond;
        }
 
-       lockdep_set_class(&bond_dev->_xmit_lock, &bonding_netdev_xmit_lock_key);
+       bond_set_lockdep_class(bond_dev);
 
        netif_carrier_off(bond_dev);