bonding: process the err returned by dev_set_allmulti properly in bond_enslave
[pandora-kernel.git] / drivers / net / bonding / bond_main.c
index 2589e57..18ebffa 100644 (file)
@@ -861,6 +861,23 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
        }
 }
 
+static struct slave *bond_get_old_active(struct bonding *bond,
+                                        struct slave *new_active)
+{
+       struct slave *slave;
+       int i;
+
+       bond_for_each_slave(bond, slave, i) {
+               if (slave == new_active)
+                       continue;
+
+               if (!compare_ether_addr(bond->dev->dev_addr, slave->dev->dev_addr))
+                       return slave;
+       }
+
+       return NULL;
+}
+
 /*
  * bond_do_fail_over_mac
  *
@@ -898,6 +915,9 @@ static void bond_do_fail_over_mac(struct bonding *bond,
                write_unlock_bh(&bond->curr_slave_lock);
                read_unlock(&bond->lock);
 
+               if (!old_active)
+                       old_active = bond_get_old_active(bond, new_active);
+
                if (old_active) {
                        memcpy(tmp_mac, new_active->dev->dev_addr, ETH_ALEN);
                        memcpy(saddr.sa_data, old_active->dev->dev_addr,
@@ -1684,8 +1704,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                /* set allmulti level to new slave */
                if (bond_dev->flags & IFF_ALLMULTI) {
                        res = dev_set_allmulti(slave_dev, 1);
-                       if (res)
+                       if (res) {
+                               if (bond_dev->flags & IFF_PROMISC)
+                                       dev_set_promiscuity(slave_dev, -1);
                                goto err_close;
+                       }
                }
 
                netif_addr_lock_bh(bond_dev);
@@ -1866,6 +1889,7 @@ err_detach:
        write_unlock_bh(&bond->lock);
 
 err_close:
+       slave_dev->priv_flags &= ~IFF_BONDING;
        dev_close(slave_dev);
 
 err_unset_master:
@@ -1910,6 +1934,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave, *oldcurrent;
        struct sockaddr addr;
+       int old_flags = bond_dev->flags;
        u32 old_features = bond_dev->features;
 
        /* slave is not a slave or master is not master of this slave */
@@ -2040,12 +2065,18 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
         * already taken care of above when we detached the slave
         */
        if (!USES_PRIMARY(bond->params.mode)) {
-               /* unset promiscuity level from slave */
-               if (bond_dev->flags & IFF_PROMISC)
+               /* unset promiscuity level from slave
+                * NOTE: The NETDEV_CHANGEADDR call above may change the value
+                * of the IFF_PROMISC flag in the bond_dev, but we need the
+                * value of that flag before that change, as that was the value
+                * when this slave was attached, so we cache at the start of the
+                * function and use it here. Same goes for ALLMULTI below
+                */
+               if (old_flags & IFF_PROMISC)
                        dev_set_promiscuity(slave_dev, -1);
 
                /* unset allmulti level from slave */
-               if (bond_dev->flags & IFF_ALLMULTI)
+               if (old_flags & IFF_ALLMULTI)
                        dev_set_allmulti(slave_dev, -1);
 
                /* flush master's mc_list from slave */
@@ -4906,6 +4937,7 @@ static int __init bonding_init(void)
 out:
        return res;
 err:
+       bond_destroy_debugfs();
        rtnl_link_unregister(&bond_link_ops);
 err_link:
        unregister_pernet_subsys(&bond_net_ops);