/*-------------------------------- Monitoring -------------------------------*/
 
-/* this function is called regularly to monitor each slave's link. */
-void bond_mii_monitor(struct work_struct *work)
+/*
+ * 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 bonding *bond = container_of(work, struct bonding,
-                                           mii_work.work);
        struct slave *slave, *oldcurrent;
        int do_failover = 0;
-       int delta_in_ticks;
        int i;
 
-       read_lock(&bond->lock);
-
-       delta_in_ticks = (bond->params.miimon * HZ) / 1000;
-
-       if (bond->kill_timers) {
+       if (bond->slave_cnt == 0)
                goto out;
-       }
-
-       if (bond->slave_cnt == 0) {
-               goto re_arm;
-       }
 
        /* we will try to read the link status of each of our slaves, and
         * set their IFF_RUNNING flag appropriately. For each slave not
                        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;
 
                        } 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;
        } else
                bond_set_carrier(bond);
 
-re_arm:
-       if (bond->params.miimon)
-               queue_delayed_work(bond->wq, &bond->mii_work, delta_in_ticks);
 out:
-       read_unlock(&bond->lock);
+       return 0;
 }
 
+/*
+ * 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.
+ */
+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_mii_monitor(bond, 0)) {
+               read_unlock(&bond->lock);
+               rtnl_lock();
+               read_lock(&bond->lock);
+               __bond_mii_monitor(bond, 1);
+               rtnl_unlock();
+       }
+
+       delay = ((bond->params.miimon * HZ) / 1000) ? : 1;
+       read_unlock(&bond->lock);
+       queue_delayed_work(bond->wq, &bond->mii_work, delay);
+}
 
 static __be32 bond_glean_dev_ip(struct net_device *dev)
 {