]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/bonding/bond_main.c
bonding: refactor mii monitor
[karo-tx-linux.git] / drivers / net / bonding / bond_main.c
index a641eeaa2a2f488bdef9a074e431c187321135f7..c792138511e6b599a52d3740d6459630733b6969 100644 (file)
@@ -2223,272 +2223,217 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
 
 /*-------------------------------- Monitoring -------------------------------*/
 
-/*
- * if !have_locks, return nonzero if a failover is necessary.  if
- * have_locks, do whatever failover activities are needed.
- *
- * This is to separate the inspection and failover steps for locking
- * purposes; failover requires rtnl, but acquiring it for every
- * inspection is undesirable, so a wrapper first does inspection, and
- * the acquires the necessary locks and calls again to perform
- * failover if needed.  Since all locks are dropped, a complete
- * restart is needed between calls.
- */
-static int __bond_mii_monitor(struct bonding *bond, int have_locks)
-{
-       struct slave *slave, *oldcurrent;
-       int do_failover = 0;
-       int i;
-
-       if (bond->slave_cnt == 0)
-               goto out;
 
-       /* we will try to read the link status of each of our slaves, and
-        * set their IFF_RUNNING flag appropriately. For each slave not
-        * supporting MII status, we won't do anything so that a user-space
-        * program could monitor the link itself if needed.
-        */
-
-       read_lock(&bond->curr_slave_lock);
-       oldcurrent = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
+static int bond_miimon_inspect(struct bonding *bond)
+{
+       struct slave *slave;
+       int i, link_state, commit = 0;
 
        bond_for_each_slave(bond, slave, i) {
-               struct net_device *slave_dev = slave->dev;
-               int link_state;
-               u16 old_speed = slave->speed;
-               u8 old_duplex = slave->duplex;
+               slave->new_link = BOND_LINK_NOCHANGE;
 
-               link_state = bond_check_dev_link(bond, slave_dev, 0);
+               link_state = bond_check_dev_link(bond, slave->dev, 0);
 
                switch (slave->link) {
-               case BOND_LINK_UP:      /* the link was up */
-                       if (link_state == BMSR_LSTATUS) {
-                               if (!oldcurrent) {
-                                       if (!have_locks)
-                                               return 1;
-                                       do_failover = 1;
-                               }
-                               break;
-                       } else { /* link going down */
-                               slave->link  = BOND_LINK_FAIL;
-                               slave->delay = bond->params.downdelay;
-
-                               if (slave->link_failure_count < UINT_MAX) {
-                                       slave->link_failure_count++;
-                               }
+               case BOND_LINK_UP:
+                       if (link_state)
+                               continue;
 
-                               if (bond->params.downdelay) {
-                                       printk(KERN_INFO DRV_NAME
-                                              ": %s: link status down for %s "
-                                              "interface %s, disabling it in "
-                                              "%d ms.\n",
-                                              bond->dev->name,
-                                              IS_UP(slave_dev)
-                                              ? ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
-                                                 ? ((slave == oldcurrent)
-                                                    ? "active " : "backup ")
-                                                 : "")
-                                              : "idle ",
-                                              slave_dev->name,
-                                              bond->params.downdelay * bond->params.miimon);
-                               }
+                       slave->link = BOND_LINK_FAIL;
+                       slave->delay = bond->params.downdelay;
+                       if (slave->delay) {
+                               printk(KERN_INFO DRV_NAME
+                                      ": %s: link status down for %s"
+                                      "interface %s, disabling it in %d ms.\n",
+                                      bond->dev->name,
+                                      (bond->params.mode ==
+                                       BOND_MODE_ACTIVEBACKUP) ?
+                                      ((slave->state == BOND_STATE_ACTIVE) ?
+                                       "active " : "backup ") : "",
+                                      slave->dev->name,
+                                      bond->params.downdelay * bond->params.miimon);
                        }
-                       /* no break ! fall through the BOND_LINK_FAIL test to
-                          ensure proper action to be taken
-                       */
-               case BOND_LINK_FAIL:    /* the link has just gone down */
-                       if (link_state != BMSR_LSTATUS) {
-                               /* link stays down */
-                               if (slave->delay <= 0) {
-                                       if (!have_locks)
-                                               return 1;
-
-                                       /* link down for too long time */
-                                       slave->link = BOND_LINK_DOWN;
-
-                                       /* in active/backup mode, we must
-                                        * completely disable this interface
-                                        */
-                                       if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) ||
-                                           (bond->params.mode == BOND_MODE_8023AD)) {
-                                               bond_set_slave_inactive_flags(slave);
-                                       }
-
-                                       printk(KERN_INFO DRV_NAME
-                                              ": %s: link status definitely "
-                                              "down for interface %s, "
-                                              "disabling it\n",
-                                              bond->dev->name,
-                                              slave_dev->name);
-
-                                       /* notify ad that the link status has changed */
-                                       if (bond->params.mode == BOND_MODE_8023AD) {
-                                               bond_3ad_handle_link_change(slave, BOND_LINK_DOWN);
-                                       }
-
-                                       if ((bond->params.mode == BOND_MODE_TLB) ||
-                                           (bond->params.mode == BOND_MODE_ALB)) {
-                                               bond_alb_handle_link_change(bond, slave, BOND_LINK_DOWN);
-                                       }
-
-                                       if (slave == oldcurrent) {
-                                               do_failover = 1;
-                                       }
-                               } else {
-                                       slave->delay--;
-                               }
-                       } else {
-                               /* link up again */
-                               slave->link  = BOND_LINK_UP;
+                       /*FALLTHRU*/
+               case BOND_LINK_FAIL:
+                       if (link_state) {
+                               /*
+                                * recovered before downdelay expired
+                                */
+                               slave->link = BOND_LINK_UP;
                                slave->jiffies = jiffies;
                                printk(KERN_INFO DRV_NAME
                                       ": %s: link status up again after %d "
                                       "ms for interface %s.\n",
                                       bond->dev->name,
-                                      (bond->params.downdelay - slave->delay) * bond->params.miimon,
-                                      slave_dev->name);
+                                      (bond->params.downdelay - slave->delay) *
+                                      bond->params.miimon,
+                                      slave->dev->name);
+                               continue;
                        }
-                       break;
-               case BOND_LINK_DOWN:    /* the link was down */
-                       if (link_state != BMSR_LSTATUS) {
-                               /* the link stays down, nothing more to do */
-                               break;
-                       } else {        /* link going up */
-                               slave->link  = BOND_LINK_BACK;
-                               slave->delay = bond->params.updelay;
 
-                               if (bond->params.updelay) {
-                                       /* if updelay == 0, no need to
-                                          advertise about a 0 ms delay */
-                                       printk(KERN_INFO DRV_NAME
-                                              ": %s: link status up for "
-                                              "interface %s, enabling it "
-                                              "in %d ms.\n",
-                                              bond->dev->name,
-                                              slave_dev->name,
-                                              bond->params.updelay * bond->params.miimon);
-                               }
+                       if (slave->delay <= 0) {
+                               slave->new_link = BOND_LINK_DOWN;
+                               commit++;
+                               continue;
                        }
-                       /* no break ! fall through the BOND_LINK_BACK state in
-                          case there's something to do.
-                       */
-               case BOND_LINK_BACK:    /* the link has just come back */
-                       if (link_state != BMSR_LSTATUS) {
-                               /* link down again */
-                               slave->link  = BOND_LINK_DOWN;
 
+                       slave->delay--;
+                       break;
+
+               case BOND_LINK_DOWN:
+                       if (!link_state)
+                               continue;
+
+                       slave->link = BOND_LINK_BACK;
+                       slave->delay = bond->params.updelay;
+
+                       if (slave->delay) {
+                               printk(KERN_INFO DRV_NAME
+                                      ": %s: link status up for "
+                                      "interface %s, enabling it in %d ms.\n",
+                                      bond->dev->name, slave->dev->name,
+                                      bond->params.updelay *
+                                      bond->params.miimon);
+                       }
+                       /*FALLTHRU*/
+               case BOND_LINK_BACK:
+                       if (!link_state) {
+                               slave->link = BOND_LINK_DOWN;
                                printk(KERN_INFO DRV_NAME
                                       ": %s: link status down again after %d "
                                       "ms for interface %s.\n",
                                       bond->dev->name,
-                                      (bond->params.updelay - slave->delay) * bond->params.miimon,
-                                      slave_dev->name);
-                       } else {
-                               /* link stays up */
-                               if (slave->delay == 0) {
-                                       if (!have_locks)
-                                               return 1;
-
-                                       /* now the link has been up for long time enough */
-                                       slave->link = BOND_LINK_UP;
-                                       slave->jiffies = jiffies;
-
-                                       if (bond->params.mode == BOND_MODE_8023AD) {
-                                               /* prevent it from being the active one */
-                                               slave->state = BOND_STATE_BACKUP;
-                                       } else if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
-                                               /* make it immediately active */
-                                               slave->state = BOND_STATE_ACTIVE;
-                                       } else if (slave != bond->primary_slave) {
-                                               /* prevent it from being the active one */
-                                               slave->state = BOND_STATE_BACKUP;
-                                       }
+                                      (bond->params.updelay - slave->delay) *
+                                      bond->params.miimon,
+                                      slave->dev->name);
 
-                                       printk(KERN_INFO DRV_NAME
-                                              ": %s: link status definitely "
-                                              "up for interface %s.\n",
-                                              bond->dev->name,
-                                              slave_dev->name);
-
-                                       /* notify ad that the link status has changed */
-                                       if (bond->params.mode == BOND_MODE_8023AD) {
-                                               bond_3ad_handle_link_change(slave, BOND_LINK_UP);
-                                       }
-
-                                       if ((bond->params.mode == BOND_MODE_TLB) ||
-                                           (bond->params.mode == BOND_MODE_ALB)) {
-                                               bond_alb_handle_link_change(bond, slave, BOND_LINK_UP);
-                                       }
-
-                                       if ((!oldcurrent) ||
-                                           (slave == bond->primary_slave)) {
-                                               do_failover = 1;
-                                       }
-                               } else {
-                                       slave->delay--;
-                               }
+                               continue;
                        }
+
+                       if (slave->delay <= 0) {
+                               slave->new_link = BOND_LINK_UP;
+                               commit++;
+                               continue;
+                       }
+
+                       slave->delay--;
                        break;
-               default:
-                       /* Should not happen */
-                       printk(KERN_ERR DRV_NAME
-                              ": %s: Error: %s Illegal value (link=%d)\n",
-                              bond->dev->name,
-                              slave->dev->name,
-                              slave->link);
-                       goto out;
-               } /* end of switch (slave->link) */
+               }
+       }
 
-               bond_update_speed_duplex(slave);
+       return commit;
+}
 
-               if (bond->params.mode == BOND_MODE_8023AD) {
-                       if (old_speed != slave->speed) {
-                               bond_3ad_adapter_speed_changed(slave);
-                       }
+static void bond_miimon_commit(struct bonding *bond)
+{
+       struct slave *slave;
+       int i;
+
+       bond_for_each_slave(bond, slave, i) {
+               switch (slave->new_link) {
+               case BOND_LINK_NOCHANGE:
+                       continue;
+
+               case BOND_LINK_UP:
+                       slave->link = BOND_LINK_UP;
+                       slave->jiffies = jiffies;
 
-                       if (old_duplex != slave->duplex) {
-                               bond_3ad_adapter_duplex_changed(slave);
+                       if (bond->params.mode == BOND_MODE_8023AD) {
+                               /* prevent it from being the active one */
+                               slave->state = BOND_STATE_BACKUP;
+                       } else if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
+                               /* make it immediately active */
+                               slave->state = BOND_STATE_ACTIVE;
+                       } else if (slave != bond->primary_slave) {
+                               /* prevent it from being the active one */
+                               slave->state = BOND_STATE_BACKUP;
                        }
-               }
 
-       } /* end of for */
+                       printk(KERN_INFO DRV_NAME
+                              ": %s: link status definitely "
+                              "up for interface %s.\n",
+                              bond->dev->name, slave->dev->name);
 
-       if (do_failover) {
-               ASSERT_RTNL();
+                       /* notify ad that the link status has changed */
+                       if (bond->params.mode == BOND_MODE_8023AD)
+                               bond_3ad_handle_link_change(slave, BOND_LINK_UP);
 
-               write_lock_bh(&bond->curr_slave_lock);
+                       if ((bond->params.mode == BOND_MODE_TLB) ||
+                           (bond->params.mode == BOND_MODE_ALB))
+                               bond_alb_handle_link_change(bond, slave,
+                                                           BOND_LINK_UP);
 
-               bond_select_active_slave(bond);
+                       if (!bond->curr_active_slave ||
+                           (slave == bond->primary_slave))
+                               goto do_failover;
 
-               write_unlock_bh(&bond->curr_slave_lock);
+                       continue;
 
-       } else
-               bond_set_carrier(bond);
+               case BOND_LINK_DOWN:
+                       slave->link = BOND_LINK_DOWN;
 
-out:
-       return 0;
+                       if (bond->params.mode == BOND_MODE_ACTIVEBACKUP ||
+                           bond->params.mode == BOND_MODE_8023AD)
+                               bond_set_slave_inactive_flags(slave);
+
+                       printk(KERN_INFO DRV_NAME
+                              ": %s: link status definitely down for "
+                              "interface %s, disabling it\n",
+                              bond->dev->name, slave->dev->name);
+
+                       if (bond->params.mode == BOND_MODE_8023AD)
+                               bond_3ad_handle_link_change(slave,
+                                                           BOND_LINK_DOWN);
+
+                       if (bond->params.mode == BOND_MODE_TLB ||
+                           bond->params.mode == BOND_MODE_ALB)
+                               bond_alb_handle_link_change(bond, slave,
+                                                           BOND_LINK_DOWN);
+
+                       if (slave == bond->curr_active_slave)
+                               goto do_failover;
+
+                       continue;
+
+               default:
+                       printk(KERN_ERR DRV_NAME
+                              ": %s: invalid new link %d on slave %s\n",
+                              bond->dev->name, slave->new_link,
+                              slave->dev->name);
+                       slave->new_link = BOND_LINK_NOCHANGE;
+
+                       continue;
+               }
+
+do_failover:
+               ASSERT_RTNL();
+               write_lock_bh(&bond->curr_slave_lock);
+               bond_select_active_slave(bond);
+               write_unlock_bh(&bond->curr_slave_lock);
+       }
+
+       bond_set_carrier(bond);
 }
 
 /*
  * bond_mii_monitor
  *
  * Really a wrapper that splits the mii monitor into two phases: an
- * inspection, then (if inspection indicates something needs to be
- * done) an acquisition of appropriate locks followed by another pass
- * to implement whatever link state changes are indicated.
+ * inspection, then (if inspection indicates something needs to be done)
+ * an acquisition of appropriate locks followed by a commit phase to
+ * implement whatever link state changes are indicated.
  */
 void bond_mii_monitor(struct work_struct *work)
 {
        struct bonding *bond = container_of(work, struct bonding,
                                            mii_work.work);
-       unsigned long delay;
 
        read_lock(&bond->lock);
-       if (bond->kill_timers) {
-               read_unlock(&bond->lock);
-               return;
-       }
+       if (bond->kill_timers)
+               goto out;
+
+       if (bond->slave_cnt == 0)
+               goto re_arm;
 
        if (bond->send_grat_arp) {
                read_lock(&bond->curr_slave_lock);
@@ -2496,19 +2441,24 @@ void bond_mii_monitor(struct work_struct *work)
                read_unlock(&bond->curr_slave_lock);
        }
 
-       if (__bond_mii_monitor(bond, 0)) {
+       if (bond_miimon_inspect(bond)) {
                read_unlock(&bond->lock);
                rtnl_lock();
                read_lock(&bond->lock);
-               __bond_mii_monitor(bond, 1);
+
+               bond_miimon_commit(bond);
+
                read_unlock(&bond->lock);
                rtnl_unlock();  /* might sleep, hold no other locks */
                read_lock(&bond->lock);
        }
 
-       delay = msecs_to_jiffies(bond->params.miimon);
+re_arm:
+       if (bond->params.miimon)
+               queue_delayed_work(bond->wq, &bond->mii_work,
+                                  msecs_to_jiffies(bond->params.miimon));
+out:
        read_unlock(&bond->lock);
-       queue_delayed_work(bond->wq, &bond->mii_work, delay);
 }
 
 static __be32 bond_glean_dev_ip(struct net_device *dev)