bonding: remove useless assignment
[pandora-kernel.git] / drivers / net / bonding / bond_main.c
index a7e731f..ef6af1c 100644 (file)
@@ -94,6 +94,7 @@ static int downdelay;
 static int use_carrier = 1;
 static char *mode;
 static char *primary;
+static char *primary_reselect;
 static char *lacp_rate;
 static char *ad_select;
 static char *xmit_hash_policy;
@@ -126,6 +127,14 @@ MODULE_PARM_DESC(mode, "Mode of operation : 0 for balance-rr, "
                       "6 for balance-alb");
 module_param(primary, charp, 0);
 MODULE_PARM_DESC(primary, "Primary network device to use");
+module_param(primary_reselect, charp, 0);
+MODULE_PARM_DESC(primary_reselect, "Reselect primary slave "
+                                  "once it comes up; "
+                                  "0 for always (default), "
+                                  "1 for only if speed of primary is "
+                                  "better, "
+                                  "2 for only on active slave "
+                                  "failure");
 module_param(lacp_rate, charp, 0);
 MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner "
                            "(slow/fast)");
@@ -200,6 +209,13 @@ const struct bond_parm_tbl fail_over_mac_tbl[] = {
 {      NULL,                   -1},
 };
 
+const struct bond_parm_tbl pri_reselect_tbl[] = {
+{      "always",               BOND_PRI_RESELECT_ALWAYS},
+{      "better",               BOND_PRI_RESELECT_BETTER},
+{      "failure",              BOND_PRI_RESELECT_FAILURE},
+{      NULL,                   -1},
+};
+
 struct bond_parm_tbl ad_select_tbl[] = {
 {      "stable",       BOND_AD_STABLE},
 {      "bandwidth",    BOND_AD_BANDWIDTH},
@@ -1070,6 +1086,25 @@ out:
 
 }
 
+static bool bond_should_change_active(struct bonding *bond)
+{
+       struct slave *prim = bond->primary_slave;
+       struct slave *curr = bond->curr_active_slave;
+
+       if (!prim || !curr || curr->link != BOND_LINK_UP)
+               return true;
+       if (bond->force_primary) {
+               bond->force_primary = false;
+               return true;
+       }
+       if (bond->params.primary_reselect == BOND_PRI_RESELECT_BETTER &&
+           (prim->speed < curr->speed ||
+            (prim->speed == curr->speed && prim->duplex <= curr->duplex)))
+               return false;
+       if (bond->params.primary_reselect == BOND_PRI_RESELECT_FAILURE)
+               return false;
+       return true;
+}
 
 /**
  * find_best_interface - select the best available slave to be the active one
@@ -1084,7 +1119,7 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
        int mintime = bond->params.updelay;
        int i;
 
-       new_active = old_active = bond->curr_active_slave;
+       new_active = bond->curr_active_slave;
 
        if (!new_active) { /* there were no active slaves left */
                if (bond->slave_cnt > 0)   /* found one slave */
@@ -1093,15 +1128,9 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
                        return NULL; /* still no slave, return NULL */
        }
 
-       /*
-        * first try the primary link; if arping, a link must tx/rx
-        * traffic before it can be considered the curr_active_slave.
-        * also, we would skip slaves between the curr_active_slave
-        * and primary_slave that may be up and able to arp
-        */
        if ((bond->primary_slave) &&
-           (!bond->params.arp_interval) &&
-           (IS_UP(bond->primary_slave->dev))) {
+           bond->primary_slave->link == BOND_LINK_UP &&
+           bond_should_change_active(bond)) {
                new_active = bond->primary_slave;
        }
 
@@ -1109,15 +1138,14 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
        old_active = new_active;
 
        bond_for_each_slave_from(bond, new_active, i, old_active) {
-               if (IS_UP(new_active->dev)) {
-                       if (new_active->link == BOND_LINK_UP) {
-                               return new_active;
-                       } else if (new_active->link == BOND_LINK_BACK) {
-                               /* link up, but waiting for stabilization */
-                               if (new_active->delay < mintime) {
-                                       mintime = new_active->delay;
-                                       bestslave = new_active;
-                               }
+               if (new_active->link == BOND_LINK_UP) {
+                       return new_active;
+               } else if (new_active->link == BOND_LINK_BACK &&
+                          IS_UP(new_active->dev)) {
+                       /* link up, but waiting for stabilization */
+                       if (new_active->delay < mintime) {
+                               mintime = new_active->delay;
+                               bestslave = new_active;
                        }
                }
        }
@@ -1211,7 +1239,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
                        write_unlock_bh(&bond->curr_slave_lock);
                        read_unlock(&bond->lock);
 
-                       netdev_bonding_change(bond->dev);
+                       netdev_bonding_change(bond->dev, NETDEV_BONDING_FAILOVER);
 
                        read_lock(&bond->lock);
                        write_lock_bh(&bond->curr_slave_lock);
@@ -1469,14 +1497,17 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
         */
        if (bond->slave_cnt == 0) {
                if (bond_dev->type != slave_dev->type) {
-                       dev_close(bond_dev);
                        pr_debug("%s: change device type from %d to %d\n",
                                bond_dev->name, bond_dev->type, slave_dev->type);
+
+                       netdev_bonding_change(bond_dev, NETDEV_BONDING_OLDTYPE);
+
                        if (slave_dev->type != ARPHRD_ETHER)
                                bond_setup_by_slave(bond_dev, slave_dev);
                        else
                                ether_setup(bond_dev);
-                       dev_open(bond_dev);
+
+                       netdev_bonding_change(bond_dev, NETDEV_BONDING_NEWTYPE);
                }
        } else if (bond_dev->type != slave_dev->type) {
                pr_err(DRV_NAME ": %s ether type (%d) is different "
@@ -1683,8 +1714,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) {
                /* if there is a primary slave, remember it */
-               if (strcmp(bond->params.primary, new_slave->dev->name) == 0)
+               if (strcmp(bond->params.primary, new_slave->dev->name) == 0) {
                        bond->primary_slave = new_slave;
+                       bond->force_primary = true;
+               }
        }
 
        write_lock_bh(&bond->curr_slave_lock);
@@ -2929,18 +2962,6 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
                }
        }
 
-       read_lock(&bond->curr_slave_lock);
-
-       /*
-        * Trigger a commit if the primary option setting has changed.
-        */
-       if (bond->primary_slave &&
-           (bond->primary_slave != bond->curr_active_slave) &&
-           (bond->primary_slave->link == BOND_LINK_UP))
-               commit++;
-
-       read_unlock(&bond->curr_slave_lock);
-
        return commit;
 }
 
@@ -2961,90 +2982,58 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks)
                        continue;
 
                case BOND_LINK_UP:
-                       write_lock_bh(&bond->curr_slave_lock);
-
-                       if (!bond->curr_active_slave &&
-                           time_before_eq(jiffies, dev_trans_start(slave->dev) +
-                                          delta_in_ticks)) {
+                       if ((!bond->curr_active_slave &&
+                            time_before_eq(jiffies,
+                                           dev_trans_start(slave->dev) +
+                                           delta_in_ticks)) ||
+                           bond->curr_active_slave != slave) {
                                slave->link = BOND_LINK_UP;
-                               bond_change_active_slave(bond, slave);
                                bond->current_arp_slave = NULL;
 
                                pr_info(DRV_NAME
-                                      ": %s: %s is up and now the "
-                                      "active interface\n",
-                                      bond->dev->name, slave->dev->name);
-
-                       } else if (bond->curr_active_slave != slave) {
-                               /* this slave has just come up but we
-                                * already have a current slave; this can
-                                * also happen if bond_enslave adds a new
-                                * slave that is up while we are searching
-                                * for a new slave
-                                */
-                               slave->link = BOND_LINK_UP;
-                               bond_set_slave_inactive_flags(slave);
-                               bond->current_arp_slave = NULL;
+                                       ": %s: link status definitely "
+                                       "up for interface %s.\n",
+                                       bond->dev->name, slave->dev->name);
 
-                               pr_info(DRV_NAME
-                                      ": %s: backup interface %s is now up\n",
-                                      bond->dev->name, slave->dev->name);
-                       }
+                               if (!bond->curr_active_slave ||
+                                   (slave == bond->primary_slave))
+                                       goto do_failover;
 
-                       write_unlock_bh(&bond->curr_slave_lock);
+                       }
 
-                       break;
+                       continue;
 
                case BOND_LINK_DOWN:
                        if (slave->link_failure_count < UINT_MAX)
                                slave->link_failure_count++;
 
                        slave->link = BOND_LINK_DOWN;
+                       bond_set_slave_inactive_flags(slave);
 
-                       if (slave == bond->curr_active_slave) {
-                               pr_info(DRV_NAME
-                                      ": %s: link status down for active "
-                                      "interface %s, disabling it\n",
-                                      bond->dev->name, slave->dev->name);
-
-                               bond_set_slave_inactive_flags(slave);
-
-                               write_lock_bh(&bond->curr_slave_lock);
-
-                               bond_select_active_slave(bond);
-                               if (bond->curr_active_slave)
-                                       bond->curr_active_slave->jiffies =
-                                               jiffies;
-
-                               write_unlock_bh(&bond->curr_slave_lock);
+                       pr_info(DRV_NAME
+                               ": %s: link status definitely down for "
+                               "interface %s, disabling it\n",
+                               bond->dev->name, slave->dev->name);
 
+                       if (slave == bond->curr_active_slave) {
                                bond->current_arp_slave = NULL;
-
-                       } else if (slave->state == BOND_STATE_BACKUP) {
-                               pr_info(DRV_NAME
-                                      ": %s: backup interface %s is now down\n",
-                                      bond->dev->name, slave->dev->name);
-
-                               bond_set_slave_inactive_flags(slave);
+                               goto do_failover;
                        }
-                       break;
+
+                       continue;
 
                default:
                        pr_err(DRV_NAME
                               ": %s: impossible: new_link %d on slave %s\n",
                               bond->dev->name, slave->new_link,
                               slave->dev->name);
+                       continue;
                }
-       }
 
-       /*
-        * No race with changes to primary via sysfs, as we hold rtnl.
-        */
-       if (bond->primary_slave &&
-           (bond->primary_slave != bond->curr_active_slave) &&
-           (bond->primary_slave->link == BOND_LINK_UP)) {
+do_failover:
+               ASSERT_RTNL();
                write_lock_bh(&bond->curr_slave_lock);
-               bond_change_active_slave(bond, bond->primary_slave);
+               bond_select_active_slave(bond);
                write_unlock_bh(&bond->curr_slave_lock);
        }
 
@@ -3250,11 +3239,14 @@ static void bond_info_show_master(struct seq_file *seq)
        }
 
        if (USES_PRIMARY(bond->params.mode)) {
-               seq_printf(seq, "Primary Slave: %s\n",
+               seq_printf(seq, "Primary Slave: %s",
                           (bond->primary_slave) ?
                           bond->primary_slave->dev->name : "None");
+               if (bond->primary_slave)
+                       seq_printf(seq, " (primary_reselect %s)",
+                  pri_reselect_tbl[bond->params.primary_reselect].modename);
 
-               seq_printf(seq, "Currently Active Slave: %s\n",
+               seq_printf(seq, "\nCurrently Active Slave: %s\n",
                           (curr) ? curr->dev->name : "None");
        }
 
@@ -4695,7 +4687,7 @@ int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl)
 
 static int bond_check_params(struct bond_params *params)
 {
-       int arp_validate_value, fail_over_mac_value;
+       int arp_validate_value, fail_over_mac_value, primary_reselect_value;
 
        /*
         * Convert string parameters.
@@ -4714,7 +4706,8 @@ static int bond_check_params(struct bond_params *params)
                if ((bond_mode != BOND_MODE_XOR) &&
                    (bond_mode != BOND_MODE_8023AD)) {
                        pr_info(DRV_NAME
-                              ": xor_mode param is irrelevant in mode %s\n",
+                               ": xmit_hash_policy param is irrelevant in"
+                               " mode %s\n",
                               bond_mode_name(bond_mode));
                } else {
                        xmit_hashtype = bond_parse_parm(xmit_hash_policy,
@@ -4994,6 +4987,20 @@ static int bond_check_params(struct bond_params *params)
                primary = NULL;
        }
 
+       if (primary && primary_reselect) {
+               primary_reselect_value = bond_parse_parm(primary_reselect,
+                                                        pri_reselect_tbl);
+               if (primary_reselect_value == -1) {
+                       pr_err(DRV_NAME
+                              ": Error: Invalid primary_reselect \"%s\"\n",
+                              primary_reselect ==
+                                       NULL ? "NULL" : primary_reselect);
+                       return -EINVAL;
+               }
+       } else {
+               primary_reselect_value = BOND_PRI_RESELECT_ALWAYS;
+       }
+
        if (fail_over_mac) {
                fail_over_mac_value = bond_parse_parm(fail_over_mac,
                                                      fail_over_mac_tbl);
@@ -5025,6 +5032,7 @@ static int bond_check_params(struct bond_params *params)
        params->use_carrier = use_carrier;
        params->lacp_fast = lacp_fast;
        params->primary[0] = 0;
+       params->primary_reselect = primary_reselect_value;
        params->fail_over_mac = fail_over_mac_value;
 
        if (primary) {