From 4620a92ecce4c43a844b026e5308e5b7ea793278 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Wed, 17 Oct 2007 17:37:48 -0700 Subject: [PATCH] --- yaml --- r: 72430 b: refs/heads/master c: 0b0eef66419e9abe6fd62bc958ab7cd0a18f858e h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/drivers/net/bonding/bond_main.c | 70 +++++++++++++++++++-------- 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/[refs] b/[refs] index 185872a0ef3b..04222815dc69 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: cf5f9044934658dd3ffc628a60cd37c70f8168b1 +refs/heads/master: 0b0eef66419e9abe6fd62bc958ab7cd0a18f858e diff --git a/trunk/drivers/net/bonding/bond_main.c b/trunk/drivers/net/bonding/bond_main.c index 862ed8ece14e..a3577271b1b8 100644 --- a/trunk/drivers/net/bonding/bond_main.c +++ b/trunk/drivers/net/bonding/bond_main.c @@ -2088,27 +2088,25 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in /*-------------------------------- 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 @@ -2175,6 +2173,9 @@ void bond_mii_monitor(struct work_struct *work) 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; @@ -2258,6 +2259,9 @@ void bond_mii_monitor(struct work_struct *work) } 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; @@ -2331,13 +2335,41 @@ void bond_mii_monitor(struct work_struct *work) } 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) {