Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/davem/net...
[safe/jmp/linux-2.6] / drivers / net / bonding / bond_main.c
index 16cfe9e..2f4329e 100644 (file)
@@ -31,8 +31,6 @@
  *
  */
 
-//#define BONDING_DEBUG 1
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -156,7 +154,6 @@ LIST_HEAD(bond_dev_list);
 static struct proc_dir_entry *bond_proc_dir = NULL;
 #endif
 
-extern struct rw_semaphore bonding_rwsem;
 static __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
 static int arp_ip_count        = 0;
 static int bond_mode   = BOND_MODE_ROUNDROBIN;
@@ -164,13 +161,13 @@ static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2;
 static int lacp_fast   = 0;
 
 
-struct bond_parm_tbl bond_lacp_tbl[] = {
+const struct bond_parm_tbl bond_lacp_tbl[] = {
 {      "slow",         AD_LACP_SLOW},
 {      "fast",         AD_LACP_FAST},
 {      NULL,           -1},
 };
 
-struct bond_parm_tbl bond_mode_tbl[] = {
+const struct bond_parm_tbl bond_mode_tbl[] = {
 {      "balance-rr",           BOND_MODE_ROUNDROBIN},
 {      "active-backup",        BOND_MODE_ACTIVEBACKUP},
 {      "balance-xor",          BOND_MODE_XOR},
@@ -181,14 +178,14 @@ struct bond_parm_tbl bond_mode_tbl[] = {
 {      NULL,                   -1},
 };
 
-struct bond_parm_tbl xmit_hashtype_tbl[] = {
+const struct bond_parm_tbl xmit_hashtype_tbl[] = {
 {      "layer2",               BOND_XMIT_POLICY_LAYER2},
 {      "layer3+4",             BOND_XMIT_POLICY_LAYER34},
 {      "layer2+3",             BOND_XMIT_POLICY_LAYER23},
 {      NULL,                   -1},
 };
 
-struct bond_parm_tbl arp_validate_tbl[] = {
+const struct bond_parm_tbl arp_validate_tbl[] = {
 {      "none",                 BOND_ARP_VALIDATE_NONE},
 {      "active",               BOND_ARP_VALIDATE_ACTIVE},
 {      "backup",               BOND_ARP_VALIDATE_BACKUP},
@@ -196,7 +193,7 @@ struct bond_parm_tbl arp_validate_tbl[] = {
 {      NULL,                   -1},
 };
 
-struct bond_parm_tbl fail_over_mac_tbl[] = {
+const struct bond_parm_tbl fail_over_mac_tbl[] = {
 {      "none",                 BOND_FOM_NONE},
 {      "active",               BOND_FOM_ACTIVE},
 {      "follow",               BOND_FOM_FOLLOW},
@@ -219,24 +216,20 @@ static void bond_deinit(struct net_device *bond_dev);
 
 static const char *bond_mode_name(int mode)
 {
-       switch (mode) {
-       case BOND_MODE_ROUNDROBIN :
-               return "load balancing (round-robin)";
-       case BOND_MODE_ACTIVEBACKUP :
-               return "fault-tolerance (active-backup)";
-       case BOND_MODE_XOR :
-               return "load balancing (xor)";
-       case BOND_MODE_BROADCAST :
-               return "fault-tolerance (broadcast)";
-       case BOND_MODE_8023AD:
-               return "IEEE 802.3ad Dynamic link aggregation";
-       case BOND_MODE_TLB:
-               return "transmit load balancing";
-       case BOND_MODE_ALB:
-               return "adaptive load balancing";
-       default:
+       static const char *names[] = {
+               [BOND_MODE_ROUNDROBIN] = "load balancing (round-robin)",
+               [BOND_MODE_ACTIVEBACKUP] = "fault-tolerance (active-backup)",
+               [BOND_MODE_XOR] = "load balancing (xor)",
+               [BOND_MODE_BROADCAST] = "fault-tolerance (broadcast)",
+               [BOND_MODE_8023AD]= "IEEE 802.3ad Dynamic link aggregation",
+               [BOND_MODE_TLB] = "transmit load balancing",
+               [BOND_MODE_ALB] = "adaptive load balancing",
+       };
+
+       if (mode < 0 || mode > BOND_MODE_ALB)
                return "unknown";
-       }
+
+       return names[mode];
 }
 
 /*---------------------------------- VLAN -----------------------------------*/
@@ -252,7 +245,7 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id)
 {
        struct vlan_entry *vlan;
 
-       dprintk("bond: %s, vlan id %d\n",
+       pr_debug("bond: %s, vlan id %d\n",
                (bond ? bond->dev->name: "None"), vlan_id);
 
        vlan = kzalloc(sizeof(struct vlan_entry), GFP_KERNEL);
@@ -269,7 +262,7 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id)
 
        write_unlock_bh(&bond->lock);
 
-       dprintk("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name);
+       pr_debug("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name);
 
        return 0;
 }
@@ -286,7 +279,7 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id)
        struct vlan_entry *vlan;
        int res = -ENODEV;
 
-       dprintk("bond: %s, vlan id %d\n", bond->dev->name, vlan_id);
+       pr_debug("bond: %s, vlan id %d\n", bond->dev->name, vlan_id);
 
        write_lock_bh(&bond->lock);
 
@@ -297,7 +290,7 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id)
                        if (bond_is_lb(bond))
                                bond_alb_clear_vlan(bond, vlan_id);
 
-                       dprintk("removed VLAN ID %d from bond %s\n", vlan_id,
+                       pr_debug("removed VLAN ID %d from bond %s\n", vlan_id,
                                bond->dev->name);
 
                        kfree(vlan);
@@ -317,7 +310,7 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id)
                }
        }
 
-       dprintk("couldn't find VLAN ID %d in bond %s\n", vlan_id,
+       pr_debug("couldn't find VLAN ID %d in bond %s\n", vlan_id,
                bond->dev->name);
 
 out:
@@ -341,13 +334,13 @@ static int bond_has_challenged_slaves(struct bonding *bond)
 
        bond_for_each_slave(bond, slave, i) {
                if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) {
-                       dprintk("found VLAN challenged slave - %s\n",
+                       pr_debug("found VLAN challenged slave - %s\n",
                                slave->dev->name);
                        return 1;
                }
        }
 
-       dprintk("no VLAN challenged slaves found\n");
+       pr_debug("no VLAN challenged slaves found\n");
        return 0;
 }
 
@@ -702,6 +695,18 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de
        if (bond->params.use_carrier)
                return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0;
 
+       /* Try to get link status using Ethtool first. */
+       if (slave_dev->ethtool_ops) {
+               if (slave_dev->ethtool_ops->get_link) {
+                       u32 link;
+
+                       link = slave_dev->ethtool_ops->get_link(slave_dev);
+
+                       return link ? BMSR_LSTATUS : 0;
+               }
+       }
+
+       /* Ethtool can't be used, fallback to MII ioclts. */
        ioctl = slave_ops->ndo_do_ioctl;
        if (ioctl) {
                /* TODO: set pointer to correct ioctl on a per team member */
@@ -728,20 +733,6 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de
        }
 
        /*
-        * Some drivers cache ETHTOOL_GLINK for a period of time so we only
-        * attempt to get link status from it if the above MII ioctls fail.
-        */
-       if (slave_dev->ethtool_ops) {
-               if (slave_dev->ethtool_ops->get_link) {
-                       u32 link;
-
-                       link = slave_dev->ethtool_ops->get_link(slave_dev);
-
-                       return link ? BMSR_LSTATUS : 0;
-               }
-       }
-
-       /*
         * If reporting, report that either there's no dev->do_ioctl,
         * or both SIOCGMIIREG and get_link failed (meaning that we
         * cannot report link status).  If not reporting, pretend
@@ -1009,6 +1000,10 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct
 static void bond_do_fail_over_mac(struct bonding *bond,
                                  struct slave *new_active,
                                  struct slave *old_active)
+       __releases(&bond->curr_slave_lock)
+       __releases(&bond->lock)
+       __acquires(&bond->lock)
+       __acquires(&bond->curr_slave_lock)
 {
        u8 tmp_mac[ETH_ALEN];
        struct sockaddr saddr;
@@ -1323,9 +1318,9 @@ static void bond_detach_slave(struct bonding *bond, struct slave *slave)
 static int bond_sethwaddr(struct net_device *bond_dev,
                          struct net_device *slave_dev)
 {
-       dprintk("bond_dev=%p\n", bond_dev);
-       dprintk("slave_dev=%p\n", slave_dev);
-       dprintk("slave_dev->addr_len=%d\n", slave_dev->addr_len);
+       pr_debug("bond_dev=%p\n", bond_dev);
+       pr_debug("slave_dev=%p\n", slave_dev);
+       pr_debug("slave_dev->addr_len=%d\n", slave_dev->addr_len);
        memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len);
        return 0;
 }
@@ -1416,14 +1411,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        /* already enslaved */
        if (slave_dev->flags & IFF_SLAVE) {
-               dprintk("Error, Device was already enslaved\n");
+               pr_debug("Error, Device was already enslaved\n");
                return -EBUSY;
        }
 
        /* vlan challenged mutual exclusion */
        /* no need to lock since we're protected by rtnl_lock */
        if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) {
-               dprintk("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
+               pr_debug("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
                if (!list_empty(&bond->vlan_list)) {
                        printk(KERN_ERR DRV_NAME
                               ": %s: Error: cannot enslave VLAN "
@@ -1441,7 +1436,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                        bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
                }
        } else {
-               dprintk("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
+               pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
                if (bond->slave_cnt == 0) {
                        /* First slave, and it is not VLAN challenged,
                         * so remove the block of adding VLANs over the bond.
@@ -1529,20 +1524,20 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                addr.sa_family = slave_dev->type;
                res = dev_set_mac_address(slave_dev, &addr);
                if (res) {
-                       dprintk("Error %d calling set_mac_address\n", res);
+                       pr_debug("Error %d calling set_mac_address\n", res);
                        goto err_free;
                }
        }
 
        res = netdev_set_master(slave_dev, bond_dev);
        if (res) {
-               dprintk("Error %d calling netdev_set_master\n", res);
+               pr_debug("Error %d calling netdev_set_master\n", res);
                goto err_restore_mac;
        }
        /* open the slave since the application closed it */
        res = dev_open(slave_dev);
        if (res) {
-               dprintk("Openning slave %s failed\n", slave_dev->name);
+               pr_debug("Openning slave %s failed\n", slave_dev->name);
                goto err_unset_master;
        }
 
@@ -1647,18 +1642,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        if (!bond->params.miimon ||
            (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS)) {
                if (bond->params.updelay) {
-                       dprintk("Initial state of slave_dev is "
+                       pr_debug("Initial state of slave_dev is "
                                "BOND_LINK_BACK\n");
                        new_slave->link  = BOND_LINK_BACK;
                        new_slave->delay = bond->params.updelay;
                } else {
-                       dprintk("Initial state of slave_dev is "
+                       pr_debug("Initial state of slave_dev is "
                                "BOND_LINK_UP\n");
                        new_slave->link  = BOND_LINK_UP;
                }
                new_slave->jiffies = jiffies;
        } else {
-               dprintk("Initial state of slave_dev is "
+               pr_debug("Initial state of slave_dev is "
                        "BOND_LINK_DOWN\n");
                new_slave->link  = BOND_LINK_DOWN;
        }
@@ -1717,9 +1712,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        case BOND_MODE_ALB:
                new_slave->state = BOND_STATE_ACTIVE;
                bond_set_slave_inactive_flags(new_slave);
+               bond_select_active_slave(bond);
                break;
        default:
-               dprintk("This slave is always active in trunk mode\n");
+               pr_debug("This slave is always active in trunk mode\n");
 
                /* always active in trunk mode */
                new_slave->state = BOND_STATE_ACTIVE;
@@ -2215,33 +2211,24 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
-       int i, found = 0;
-
-       if (info->slave_id < 0) {
-               return -ENODEV;
-       }
+       int i, res = -ENODEV;
 
        read_lock(&bond->lock);
 
        bond_for_each_slave(bond, slave, i) {
                if (i == (int)info->slave_id) {
-                       found = 1;
+                       res = 0;
+                       strcpy(info->slave_name, slave->dev->name);
+                       info->link = slave->link;
+                       info->state = slave->state;
+                       info->link_failure_count = slave->link_failure_count;
                        break;
                }
        }
 
        read_unlock(&bond->lock);
 
-       if (found) {
-               strcpy(info->slave_name, slave->dev->name);
-               info->link = slave->link;
-               info->state = slave->state;
-               info->link_failure_count = slave->link_failure_count;
-       } else {
-               return -ENODEV;
-       }
-
-       return 0;
+       return res;
 }
 
 /*-------------------------------- Monitoring -------------------------------*/
@@ -2251,6 +2238,9 @@ static int bond_miimon_inspect(struct bonding *bond)
 {
        struct slave *slave;
        int i, link_state, commit = 0;
+       bool ignore_updelay;
+
+       ignore_updelay = !bond->curr_active_slave ? true : false;
 
        bond_for_each_slave(bond, slave, i) {
                slave->new_link = BOND_LINK_NOCHANGE;
@@ -2315,6 +2305,7 @@ static int bond_miimon_inspect(struct bonding *bond)
                                       ": %s: link status up for "
                                       "interface %s, enabling it in %d ms.\n",
                                       bond->dev->name, slave->dev->name,
+                                      ignore_updelay ? 0 :
                                       bond->params.updelay *
                                       bond->params.miimon);
                        }
@@ -2333,9 +2324,13 @@ static int bond_miimon_inspect(struct bonding *bond)
                                continue;
                        }
 
+                       if (ignore_updelay)
+                               slave->delay = 0;
+
                        if (slave->delay <= 0) {
                                slave->new_link = BOND_LINK_UP;
                                commit++;
+                               ignore_updelay = false;
                                continue;
                        }
 
@@ -2410,8 +2405,7 @@ static void bond_miimon_commit(struct bonding *bond)
                                bond_3ad_handle_link_change(slave,
                                                            BOND_LINK_DOWN);
 
-                       if (bond->params.mode == BOND_MODE_TLB ||
-                           bond->params.mode == BOND_MODE_ALB)
+                       if (bond_is_lb(bond))
                                bond_alb_handle_link_change(bond, slave,
                                                            BOND_LINK_DOWN);
 
@@ -2540,7 +2534,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_
 {
        struct sk_buff *skb;
 
-       dprintk("arp %d on slave %s: dst %x src %x vid %d\n", arp_op,
+       pr_debug("arp %d on slave %s: dst %x src %x vid %d\n", arp_op,
               slave_dev->name, dest_ip, src_ip, vlan_id);
               
        skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip,
@@ -2572,10 +2566,10 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
 
        for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) {
                if (!targets[i])
-                       continue;
-               dprintk("basa: target %x\n", targets[i]);
+                       break;
+               pr_debug("basa: target %x\n", targets[i]);
                if (list_empty(&bond->vlan_list)) {
-                       dprintk("basa: empty vlan: arp_send\n");
+                       pr_debug("basa: empty vlan: arp_send\n");
                        bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
                                      bond->master_ip, 0);
                        continue;
@@ -2605,7 +2599,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
                 */
                if (rt->u.dst.dev == bond->dev) {
                        ip_rt_put(rt);
-                       dprintk("basa: rtdev == bond->dev: arp_send\n");
+                       pr_debug("basa: rtdev == bond->dev: arp_send\n");
                        bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
                                      bond->master_ip, 0);
                        continue;
@@ -2616,7 +2610,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
                        vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
                        if (vlan_dev == rt->u.dst.dev) {
                                vlan_id = vlan->vlan_id;
-                               dprintk("basa: vlan match on %s %d\n",
+                               pr_debug("basa: vlan match on %s %d\n",
                                       vlan_dev->name, vlan_id);
                                break;
                        }
@@ -2651,7 +2645,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
        struct vlan_entry *vlan;
        struct net_device *vlan_dev;
 
-       dprintk("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name,
+       pr_debug("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name,
                                slave ? slave->dev->name : "NULL");
 
        if (!slave || !bond->send_grat_arp ||
@@ -2679,9 +2673,8 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
        int i;
        __be32 *targets = bond->params.arp_targets;
 
-       targets = bond->params.arp_targets;
        for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
-               dprintk("bva: sip %pI4 tip %pI4 t[%d] %pI4 bhti(tip) %d\n",
+               pr_debug("bva: sip %pI4 tip %pI4 t[%d] %pI4 bhti(tip) %d\n",
                        &sip, &tip, i, &targets[i], bond_has_this_ip(bond, tip));
                if (sip == targets[i]) {
                        if (bond_has_this_ip(bond, tip))
@@ -2708,7 +2701,7 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
        bond = netdev_priv(dev);
        read_lock(&bond->lock);
 
-       dprintk("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n",
+       pr_debug("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n",
                bond->dev->name, skb->dev ? skb->dev->name : "NULL",
                orig_dev ? orig_dev->name : "NULL");
 
@@ -2734,7 +2727,7 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
        arp_ptr += 4 + dev->addr_len;
        memcpy(&tip, arp_ptr, 4);
 
-       dprintk("bond_arp_rcv: %s %s/%d av %d sv %d sip %pI4 tip %pI4\n",
+       pr_debug("bond_arp_rcv: %s %s/%d av %d sv %d sip %pI4 tip %pI4\n",
                bond->dev->name, slave->dev->name, slave->state,
                bond->params.arp_validate, slave_do_arp_validate(bond, slave),
                &sip, &tip);
@@ -2801,7 +2794,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
         */
        bond_for_each_slave(bond, slave, i) {
                if (slave->link != BOND_LINK_UP) {
-                       if (time_before_eq(jiffies, slave->dev->trans_start + delta_in_ticks) &&
+                       if (time_before_eq(jiffies, dev_trans_start(slave->dev) + delta_in_ticks) &&
                            time_before_eq(jiffies, slave->dev->last_rx + delta_in_ticks)) {
 
                                slave->link  = BOND_LINK_UP;
@@ -2833,7 +2826,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
                         * when the source ip is 0, so don't take the link down
                         * if we don't know our ip yet
                         */
-                       if (time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) ||
+                       if (time_after_eq(jiffies, dev_trans_start(slave->dev) + 2*delta_in_ticks) ||
                            (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks))) {
 
                                slave->link  = BOND_LINK_DOWN;
@@ -2944,7 +2937,7 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
                 *    the bond has an IP address)
                 */
                if ((slave->state == BOND_STATE_ACTIVE) &&
-                   (time_after_eq(jiffies, slave->dev->trans_start +
+                   (time_after_eq(jiffies, dev_trans_start(slave->dev) +
                                    2 * delta_in_ticks) ||
                      (time_after_eq(jiffies, slave_last_rx(bond, slave)
                                     + 2 * delta_in_ticks)))) {
@@ -2988,7 +2981,7 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks)
                        write_lock_bh(&bond->curr_slave_lock);
 
                        if (!bond->curr_active_slave &&
-                           time_before_eq(jiffies, slave->dev->trans_start +
+                           time_before_eq(jiffies, dev_trans_start(slave->dev) +
                                           delta_in_ticks)) {
                                slave->link = BOND_LINK_UP;
                                bond_change_active_slave(bond, slave);
@@ -3200,6 +3193,8 @@ out:
 #ifdef CONFIG_PROC_FS
 
 static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(&dev_base_lock)
+       __acquires(&bond->lock)
 {
        struct bonding *bond = seq->private;
        loff_t off = 0;
@@ -3239,6 +3234,8 @@ static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void bond_info_seq_stop(struct seq_file *seq, void *v)
+       __releases(&bond->lock)
+       __releases(&dev_base_lock)
 {
        struct bonding *bond = seq->private;
 
@@ -3301,7 +3298,7 @@ static void bond_info_show_master(struct seq_file *seq)
 
                for(i = 0; (i < BOND_MAX_ARP_TARGETS) ;i++) {
                        if (!bond->params.arp_targets[i])
-                               continue;
+                               break;
                        if (printed)
                                seq_printf(seq, ",");
                        seq_printf(seq, " %pI4", &bond->params.arp_targets[i]);
@@ -3376,7 +3373,7 @@ static int bond_info_seq_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static struct seq_operations bond_info_seq_ops = {
+static const struct seq_operations bond_info_seq_ops = {
        .start = bond_info_seq_start,
        .next  = bond_info_seq_next,
        .stop  = bond_info_seq_stop,
@@ -3442,25 +3439,12 @@ static void bond_remove_proc_entry(struct bonding *bond)
  */
 static void bond_create_proc_dir(void)
 {
-       int len = strlen(DRV_NAME);
-
-       for (bond_proc_dir = init_net.proc_net->subdir; bond_proc_dir;
-            bond_proc_dir = bond_proc_dir->next) {
-               if ((bond_proc_dir->namelen == len) &&
-                   !memcmp(bond_proc_dir->name, DRV_NAME, len)) {
-                       break;
-               }
-       }
-
        if (!bond_proc_dir) {
                bond_proc_dir = proc_mkdir(DRV_NAME, init_net.proc_net);
-               if (bond_proc_dir) {
-                       bond_proc_dir->owner = THIS_MODULE;
-               } else {
+               if (!bond_proc_dir)
                        printk(KERN_WARNING DRV_NAME
                                ": Warning: cannot create /proc/net/%s\n",
                                DRV_NAME);
-               }
        }
 }
 
@@ -3469,31 +3453,33 @@ static void bond_create_proc_dir(void)
  */
 static void bond_destroy_proc_dir(void)
 {
-       struct proc_dir_entry *de;
-
-       if (!bond_proc_dir) {
-               return;
-       }
-
-       /* verify that the /proc dir is empty */
-       for (de = bond_proc_dir->subdir; de; de = de->next) {
-               /* ignore . and .. */
-               if (*(de->name) != '.') {
-                       break;
-               }
-       }
-
-       if (de) {
-               if (bond_proc_dir->owner == THIS_MODULE) {
-                       bond_proc_dir->owner = NULL;
-               }
-       } else {
+       if (bond_proc_dir) {
                remove_proc_entry(DRV_NAME, init_net.proc_net);
                bond_proc_dir = NULL;
        }
 }
+
+#else /* !CONFIG_PROC_FS */
+
+static int bond_create_proc_entry(struct bonding *bond)
+{
+}
+
+static void bond_remove_proc_entry(struct bonding *bond)
+{
+}
+
+static void bond_create_proc_dir(void)
+{
+}
+
+static void bond_destroy_proc_dir(void)
+{
+}
+
 #endif /* CONFIG_PROC_FS */
 
+
 /*-------------------------- netdev event handling --------------------------*/
 
 /*
@@ -3501,10 +3487,8 @@ static void bond_destroy_proc_dir(void)
  */
 static int bond_event_changename(struct bonding *bond)
 {
-#ifdef CONFIG_PROC_FS
        bond_remove_proc_entry(bond);
        bond_create_proc_entry(bond);
-#endif
        down_write(&(bonding_rwsem));
         bond_destroy_sysfs_entry(bond);
         bond_create_sysfs_entry(bond);
@@ -3544,11 +3528,26 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave
                }
                break;
        case NETDEV_CHANGE:
-               /*
-                * TODO: is this what we get if somebody
-                * sets up a hierarchical bond, then rmmod's
-                * one of the slave bonding devices?
-                */
+               if (bond->params.mode == BOND_MODE_8023AD || bond_is_lb(bond)) {
+                       struct slave *slave;
+
+                       slave = bond_get_slave_by_dev(bond, slave_dev);
+                       if (slave) {
+                               u16 old_speed = slave->speed;
+                               u16 old_duplex = slave->duplex;
+
+                               bond_update_speed_duplex(slave);
+
+                               if (bond_is_lb(bond))
+                                       break;
+
+                               if (old_speed != slave->speed)
+                                       bond_3ad_adapter_speed_changed(slave);
+                               if (old_duplex != slave->duplex)
+                                       bond_3ad_adapter_duplex_changed(slave);
+                       }
+               }
+
                break;
        case NETDEV_DOWN:
                /*
@@ -3599,7 +3598,7 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v
        if (dev_net(event_dev) != &init_net)
                return NOTIFY_DONE;
 
-       dprintk("event_dev: %s, event: %lx\n",
+       pr_debug("event_dev: %s, event: %lx\n",
                (event_dev ? event_dev->name : "None"),
                event);
 
@@ -3607,12 +3606,12 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v
                return NOTIFY_DONE;
 
        if (event_dev->flags & IFF_MASTER) {
-               dprintk("IFF_MASTER\n");
+               pr_debug("IFF_MASTER\n");
                return bond_master_netdev_event(event, event_dev);
        }
 
        if (event_dev->flags & IFF_SLAVE) {
-               dprintk("IFF_SLAVE\n");
+               pr_debug("IFF_SLAVE\n");
                return bond_slave_netdev_event(event, event_dev);
        }
 
@@ -3941,7 +3940,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
        struct mii_ioctl_data *mii = NULL;
        int res = 0;
 
-       dprintk("bond_ioctl: master=%s, cmd=%d\n",
+       pr_debug("bond_ioctl: master=%s, cmd=%d\n",
                bond_dev->name, cmd);
 
        switch (cmd) {
@@ -4019,12 +4018,12 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
        down_write(&(bonding_rwsem));
        slave_dev = dev_get_by_name(&init_net, ifr->ifr_slave);
 
-       dprintk("slave_dev=%p: \n", slave_dev);
+       pr_debug("slave_dev=%p: \n", slave_dev);
 
        if (!slave_dev) {
                res = -ENODEV;
        } else {
-               dprintk("slave_dev->name=%s: \n", slave_dev->name);
+               pr_debug("slave_dev->name=%s: \n", slave_dev->name);
                switch (cmd) {
                case BOND_ENSLAVE_OLD:
                case SIOCBONDENSLAVE:
@@ -4120,7 +4119,7 @@ static int bond_neigh_setup(struct net_device *dev, struct neigh_parms *parms)
                const struct net_device_ops *slave_ops
                        = slave->dev->netdev_ops;
                if (slave_ops->ndo_neigh_setup)
-                       return slave_ops->ndo_neigh_setup(dev, parms);
+                       return slave_ops->ndo_neigh_setup(slave->dev, parms);
        }
        return 0;
 }
@@ -4135,7 +4134,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
        int res = 0;
        int i;
 
-       dprintk("bond=%p, name=%s, new_mtu=%d\n", bond,
+       pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond,
                (bond_dev ? bond_dev->name : "None"), new_mtu);
 
        /* Can't hold bond->lock with bh disabled here since
@@ -4154,8 +4153,8 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
         */
 
        bond_for_each_slave(bond, slave, i) {
-               dprintk("s %p s->p %p c_m %p\n", slave,
-                       slave->prev, slave->dev->change_mtu);
+               pr_debug("s %p s->p %p c_m %p\n", slave,
+                       slave->prev, slave->dev->netdev_ops->ndo_change_mtu);
 
                res = dev_set_mtu(slave->dev, new_mtu);
 
@@ -4168,7 +4167,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
                         * means changing their mtu from timer context, which
                         * is probably not a good idea.
                         */
-                       dprintk("err %d %s\n", res, slave->dev->name);
+                       pr_debug("err %d %s\n", res, slave->dev->name);
                        goto unwind;
                }
        }
@@ -4185,7 +4184,7 @@ unwind:
 
                tmp_res = dev_set_mtu(slave->dev, bond_dev->mtu);
                if (tmp_res) {
-                       dprintk("unwind err %d dev %s\n", tmp_res,
+                       pr_debug("unwind err %d dev %s\n", tmp_res,
                                slave->dev->name);
                }
        }
@@ -4212,7 +4211,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
                return bond_alb_set_mac_address(bond_dev, addr);
 
 
-       dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None"));
+       pr_debug("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None"));
 
        /*
         * If fail_over_mac is set to active, do nothing and return
@@ -4242,11 +4241,11 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
 
        bond_for_each_slave(bond, slave, i) {
                const struct net_device_ops *slave_ops = slave->dev->netdev_ops;
-               dprintk("slave %p %s\n", slave, slave->dev->name);
+               pr_debug("slave %p %s\n", slave, slave->dev->name);
 
                if (slave_ops->ndo_set_mac_address == NULL) {
                        res = -EOPNOTSUPP;
-                       dprintk("EOPNOTSUPP %s\n", slave->dev->name);
+                       pr_debug("EOPNOTSUPP %s\n", slave->dev->name);
                        goto unwind;
                }
 
@@ -4258,7 +4257,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
                         * breakage anyway until ARP finish
                         * updating, so...
                         */
-                       dprintk("err %d %s\n", res, slave->dev->name);
+                       pr_debug("err %d %s\n", res, slave->dev->name);
                        goto unwind;
                }
        }
@@ -4278,7 +4277,7 @@ unwind:
 
                tmp_res = dev_set_mac_address(slave->dev, &tmp_sa);
                if (tmp_res) {
-                       dprintk("unwind err %d dev %s\n", tmp_res,
+                       pr_debug("unwind err %d dev %s\n", tmp_res,
                                slave->dev->name);
                }
        }
@@ -4597,7 +4596,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
 {
        struct bonding *bond = netdev_priv(bond_dev);
 
-       dprintk("Begin bond_init for %s\n", bond_dev->name);
+       pr_debug("Begin bond_init for %s\n", bond_dev->name);
 
        /* initialize rwlocks */
        rwlock_init(&bond->lock);
@@ -4655,9 +4654,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
                               NETIF_F_HW_VLAN_RX |
                               NETIF_F_HW_VLAN_FILTER);
 
-#ifdef CONFIG_PROC_FS
        bond_create_proc_entry(bond);
-#endif
        list_add_tail(&bond->bond_list, &bond_dev_list);
 
        return 0;
@@ -4695,9 +4692,7 @@ static void bond_deinit(struct net_device *bond_dev)
 
        bond_work_cancel_all(bond);
 
-#ifdef CONFIG_PROC_FS
        bond_remove_proc_entry(bond);
-#endif
 }
 
 /* Unregister and free all bond devices.
@@ -4716,9 +4711,7 @@ static void bond_free_all(void)
                bond_destroy(bond);
        }
 
-#ifdef CONFIG_PROC_FS
        bond_destroy_proc_dir();
-#endif
 }
 
 /*------------------------- Module initialization ---------------------------*/
@@ -4729,9 +4722,9 @@ static void bond_free_all(void)
  * some mode names are substrings of other names, and calls from sysfs
  * may have whitespace in the name (trailing newlines, for example).
  */
-int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl)
+int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl)
 {
-       int mode = -1, i, rv;
+       int modeint = -1, i, rv;
        char *p, modestr[BOND_MAX_MODENAME_LEN + 1] = { 0, };
 
        for (p = (char *)buf; *p; p++)
@@ -4741,13 +4734,13 @@ int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl)
        if (*p)
                rv = sscanf(buf, "%20s", modestr);
        else
-               rv = sscanf(buf, "%d", &mode);
+               rv = sscanf(buf, "%d", &modeint);
 
        if (!rv)
                return -1;
 
        for (i = 0; tbl[i].modename; i++) {
-               if (mode == tbl[i].mode)
+               if (modeint == tbl[i].mode)
                        return tbl[i].mode;
                if (strcmp(modestr, tbl[i].modename) == 0)
                        return tbl[i].mode;
@@ -5154,6 +5147,7 @@ int bond_create(char *name, struct bond_params *params)
                goto out_rtnl;
        }
 
+       bond_dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
        if (!name) {
                res = dev_alloc_name(bond_dev, "bond%d");
                if (res < 0)
@@ -5182,16 +5176,15 @@ int bond_create(char *name, struct bond_params *params)
        up_write(&bonding_rwsem);
        rtnl_unlock(); /* allows sysfs registration of net device */
        res = bond_create_sysfs_entry(netdev_priv(bond_dev));
-       if (res < 0) {
-               rtnl_lock();
-               down_write(&bonding_rwsem);
-               bond_deinit(bond_dev);
-               unregister_netdevice(bond_dev);
-               goto out_rtnl;
-       }
+       if (res < 0)
+               goto out_unreg;
 
        return 0;
 
+out_unreg:
+       rtnl_lock();
+       down_write(&bonding_rwsem);
+       unregister_netdevice(bond_dev);
 out_bond:
        bond_deinit(bond_dev);
 out_netdev:
@@ -5206,7 +5199,6 @@ static int __init bonding_init(void)
 {
        int i;
        int res;
-       struct bonding *bond;
 
        printk(KERN_INFO "%s", version);
 
@@ -5215,9 +5207,7 @@ static int __init bonding_init(void)
                goto out;
        }
 
-#ifdef CONFIG_PROC_FS
        bond_create_proc_dir();
-#endif
 
        init_rwsem(&bonding_rwsem);
 
@@ -5237,13 +5227,6 @@ static int __init bonding_init(void)
 
        goto out;
 err:
-       list_for_each_entry(bond, &bond_dev_list, bond_list) {
-               bond_work_cancel_all(bond);
-               destroy_workqueue(bond->wq);
-       }
-
-       bond_destroy_sysfs();
-
        rtnl_lock();
        bond_free_all();
        rtnl_unlock();