aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bonding/bond_main.c
diff options
context:
space:
mode:
authorJay Vosburgh <fubar@us.ibm.com>2008-07-02 21:21:58 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-08-07 03:59:53 -0400
commitf0c76d61779b153dbfb955db3f144c62d02173c2 (patch)
treeb0e4af463171108e23c3701c05b1ca9c53e4c07b /drivers/net/bonding/bond_main.c
parentc16d118537cadb21d186e35aebad90a13cd78846 (diff)
bonding: refactor mii monitor
Refactor mii monitor. As with the previous ARP monitor refactor, the motivation for this is to handle locking rationally (in this case, removing conditional locking) and generally clean up the code. This patch breaks up the monolithic mii monitor into two phases: an inspection phase, followed by an optional commit phase. The commit phase is the only portion that requires RTNL or makes changes to state, and is only called when inspection finds something to change. Signed-off-by: Jay Vosburgh <fubar@us.ibm.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/bonding/bond_main.c')
-rw-r--r--drivers/net/bonding/bond_main.c394
1 files changed, 172 insertions, 222 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a641eeaa2a2f..c792138511e6 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2223,272 +2223,217 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
2223 2223
2224/*-------------------------------- Monitoring -------------------------------*/ 2224/*-------------------------------- Monitoring -------------------------------*/
2225 2225
2226/*
2227 * if !have_locks, return nonzero if a failover is necessary. if
2228 * have_locks, do whatever failover activities are needed.
2229 *
2230 * This is to separate the inspection and failover steps for locking
2231 * purposes; failover requires rtnl, but acquiring it for every
2232 * inspection is undesirable, so a wrapper first does inspection, and
2233 * the acquires the necessary locks and calls again to perform
2234 * failover if needed. Since all locks are dropped, a complete
2235 * restart is needed between calls.
2236 */
2237static int __bond_mii_monitor(struct bonding *bond, int have_locks)
2238{
2239 struct slave *slave, *oldcurrent;
2240 int do_failover = 0;
2241 int i;
2242
2243 if (bond->slave_cnt == 0)
2244 goto out;
2245 2226
2246 /* we will try to read the link status of each of our slaves, and 2227static int bond_miimon_inspect(struct bonding *bond)
2247 * set their IFF_RUNNING flag appropriately. For each slave not 2228{
2248 * supporting MII status, we won't do anything so that a user-space 2229 struct slave *slave;
2249 * program could monitor the link itself if needed. 2230 int i, link_state, commit = 0;
2250 */
2251
2252 read_lock(&bond->curr_slave_lock);
2253 oldcurrent = bond->curr_active_slave;
2254 read_unlock(&bond->curr_slave_lock);
2255 2231
2256 bond_for_each_slave(bond, slave, i) { 2232 bond_for_each_slave(bond, slave, i) {
2257 struct net_device *slave_dev = slave->dev; 2233 slave->new_link = BOND_LINK_NOCHANGE;
2258 int link_state;
2259 u16 old_speed = slave->speed;
2260 u8 old_duplex = slave->duplex;
2261 2234
2262 link_state = bond_check_dev_link(bond, slave_dev, 0); 2235 link_state = bond_check_dev_link(bond, slave->dev, 0);
2263 2236
2264 switch (slave->link) { 2237 switch (slave->link) {
2265 case BOND_LINK_UP: /* the link was up */ 2238 case BOND_LINK_UP:
2266 if (link_state == BMSR_LSTATUS) { 2239 if (link_state)
2267 if (!oldcurrent) { 2240 continue;
2268 if (!have_locks)
2269 return 1;
2270 do_failover = 1;
2271 }
2272 break;
2273 } else { /* link going down */
2274 slave->link = BOND_LINK_FAIL;
2275 slave->delay = bond->params.downdelay;
2276
2277 if (slave->link_failure_count < UINT_MAX) {
2278 slave->link_failure_count++;
2279 }
2280 2241
2281 if (bond->params.downdelay) { 2242 slave->link = BOND_LINK_FAIL;
2282 printk(KERN_INFO DRV_NAME 2243 slave->delay = bond->params.downdelay;
2283 ": %s: link status down for %s " 2244 if (slave->delay) {
2284 "interface %s, disabling it in " 2245 printk(KERN_INFO DRV_NAME
2285 "%d ms.\n", 2246 ": %s: link status down for %s"
2286 bond->dev->name, 2247 "interface %s, disabling it in %d ms.\n",
2287 IS_UP(slave_dev) 2248 bond->dev->name,
2288 ? ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) 2249 (bond->params.mode ==
2289 ? ((slave == oldcurrent) 2250 BOND_MODE_ACTIVEBACKUP) ?
2290 ? "active " : "backup ") 2251 ((slave->state == BOND_STATE_ACTIVE) ?
2291 : "") 2252 "active " : "backup ") : "",
2292 : "idle ", 2253 slave->dev->name,
2293 slave_dev->name, 2254 bond->params.downdelay * bond->params.miimon);
2294 bond->params.downdelay * bond->params.miimon);
2295 }
2296 } 2255 }
2297 /* no break ! fall through the BOND_LINK_FAIL test to 2256 /*FALLTHRU*/
2298 ensure proper action to be taken 2257 case BOND_LINK_FAIL:
2299 */ 2258 if (link_state) {
2300 case BOND_LINK_FAIL: /* the link has just gone down */ 2259 /*
2301 if (link_state != BMSR_LSTATUS) { 2260 * recovered before downdelay expired
2302 /* link stays down */ 2261 */
2303 if (slave->delay <= 0) { 2262 slave->link = BOND_LINK_UP;
2304 if (!have_locks)
2305 return 1;
2306
2307 /* link down for too long time */
2308 slave->link = BOND_LINK_DOWN;
2309
2310 /* in active/backup mode, we must
2311 * completely disable this interface
2312 */
2313 if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) ||
2314 (bond->params.mode == BOND_MODE_8023AD)) {
2315 bond_set_slave_inactive_flags(slave);
2316 }
2317
2318 printk(KERN_INFO DRV_NAME
2319 ": %s: link status definitely "
2320 "down for interface %s, "
2321 "disabling it\n",
2322 bond->dev->name,
2323 slave_dev->name);
2324
2325 /* notify ad that the link status has changed */
2326 if (bond->params.mode == BOND_MODE_8023AD) {
2327 bond_3ad_handle_link_change(slave, BOND_LINK_DOWN);
2328 }
2329
2330 if ((bond->params.mode == BOND_MODE_TLB) ||
2331 (bond->params.mode == BOND_MODE_ALB)) {
2332 bond_alb_handle_link_change(bond, slave, BOND_LINK_DOWN);
2333 }
2334
2335 if (slave == oldcurrent) {
2336 do_failover = 1;
2337 }
2338 } else {
2339 slave->delay--;
2340 }
2341 } else {
2342 /* link up again */
2343 slave->link = BOND_LINK_UP;
2344 slave->jiffies = jiffies; 2263 slave->jiffies = jiffies;
2345 printk(KERN_INFO DRV_NAME 2264 printk(KERN_INFO DRV_NAME
2346 ": %s: link status up again after %d " 2265 ": %s: link status up again after %d "
2347 "ms for interface %s.\n", 2266 "ms for interface %s.\n",
2348 bond->dev->name, 2267 bond->dev->name,
2349 (bond->params.downdelay - slave->delay) * bond->params.miimon, 2268 (bond->params.downdelay - slave->delay) *
2350 slave_dev->name); 2269 bond->params.miimon,
2270 slave->dev->name);
2271 continue;
2351 } 2272 }
2352 break;
2353 case BOND_LINK_DOWN: /* the link was down */
2354 if (link_state != BMSR_LSTATUS) {
2355 /* the link stays down, nothing more to do */
2356 break;
2357 } else { /* link going up */
2358 slave->link = BOND_LINK_BACK;
2359 slave->delay = bond->params.updelay;
2360 2273
2361 if (bond->params.updelay) { 2274 if (slave->delay <= 0) {
2362 /* if updelay == 0, no need to 2275 slave->new_link = BOND_LINK_DOWN;
2363 advertise about a 0 ms delay */ 2276 commit++;
2364 printk(KERN_INFO DRV_NAME 2277 continue;
2365 ": %s: link status up for "
2366 "interface %s, enabling it "
2367 "in %d ms.\n",
2368 bond->dev->name,
2369 slave_dev->name,
2370 bond->params.updelay * bond->params.miimon);
2371 }
2372 } 2278 }
2373 /* no break ! fall through the BOND_LINK_BACK state in
2374 case there's something to do.
2375 */
2376 case BOND_LINK_BACK: /* the link has just come back */
2377 if (link_state != BMSR_LSTATUS) {
2378 /* link down again */
2379 slave->link = BOND_LINK_DOWN;
2380 2279
2280 slave->delay--;
2281 break;
2282
2283 case BOND_LINK_DOWN:
2284 if (!link_state)
2285 continue;
2286
2287 slave->link = BOND_LINK_BACK;
2288 slave->delay = bond->params.updelay;
2289
2290 if (slave->delay) {
2291 printk(KERN_INFO DRV_NAME
2292 ": %s: link status up for "
2293 "interface %s, enabling it in %d ms.\n",
2294 bond->dev->name, slave->dev->name,
2295 bond->params.updelay *
2296 bond->params.miimon);
2297 }
2298 /*FALLTHRU*/
2299 case BOND_LINK_BACK:
2300 if (!link_state) {
2301 slave->link = BOND_LINK_DOWN;
2381 printk(KERN_INFO DRV_NAME 2302 printk(KERN_INFO DRV_NAME
2382 ": %s: link status down again after %d " 2303 ": %s: link status down again after %d "
2383 "ms for interface %s.\n", 2304 "ms for interface %s.\n",
2384 bond->dev->name, 2305 bond->dev->name,
2385 (bond->params.updelay - slave->delay) * bond->params.miimon, 2306 (bond->params.updelay - slave->delay) *
2386 slave_dev->name); 2307 bond->params.miimon,
2387 } else { 2308 slave->dev->name);
2388 /* link stays up */
2389 if (slave->delay == 0) {
2390 if (!have_locks)
2391 return 1;
2392
2393 /* now the link has been up for long time enough */
2394 slave->link = BOND_LINK_UP;
2395 slave->jiffies = jiffies;
2396
2397 if (bond->params.mode == BOND_MODE_8023AD) {
2398 /* prevent it from being the active one */
2399 slave->state = BOND_STATE_BACKUP;
2400 } else if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
2401 /* make it immediately active */
2402 slave->state = BOND_STATE_ACTIVE;
2403 } else if (slave != bond->primary_slave) {
2404 /* prevent it from being the active one */
2405 slave->state = BOND_STATE_BACKUP;
2406 }
2407 2309
2408 printk(KERN_INFO DRV_NAME 2310 continue;
2409 ": %s: link status definitely "
2410 "up for interface %s.\n",
2411 bond->dev->name,
2412 slave_dev->name);
2413
2414 /* notify ad that the link status has changed */
2415 if (bond->params.mode == BOND_MODE_8023AD) {
2416 bond_3ad_handle_link_change(slave, BOND_LINK_UP);
2417 }
2418
2419 if ((bond->params.mode == BOND_MODE_TLB) ||
2420 (bond->params.mode == BOND_MODE_ALB)) {
2421 bond_alb_handle_link_change(bond, slave, BOND_LINK_UP);
2422 }
2423
2424 if ((!oldcurrent) ||
2425 (slave == bond->primary_slave)) {
2426 do_failover = 1;
2427 }
2428 } else {
2429 slave->delay--;
2430 }
2431 } 2311 }
2312
2313 if (slave->delay <= 0) {
2314 slave->new_link = BOND_LINK_UP;
2315 commit++;
2316 continue;
2317 }
2318
2319 slave->delay--;
2432 break; 2320 break;
2433 default: 2321 }
2434 /* Should not happen */ 2322 }
2435 printk(KERN_ERR DRV_NAME
2436 ": %s: Error: %s Illegal value (link=%d)\n",
2437 bond->dev->name,
2438 slave->dev->name,
2439 slave->link);
2440 goto out;
2441 } /* end of switch (slave->link) */
2442 2323
2443 bond_update_speed_duplex(slave); 2324 return commit;
2325}
2444 2326
2445 if (bond->params.mode == BOND_MODE_8023AD) { 2327static void bond_miimon_commit(struct bonding *bond)
2446 if (old_speed != slave->speed) { 2328{
2447 bond_3ad_adapter_speed_changed(slave); 2329 struct slave *slave;
2448 } 2330 int i;
2331
2332 bond_for_each_slave(bond, slave, i) {
2333 switch (slave->new_link) {
2334 case BOND_LINK_NOCHANGE:
2335 continue;
2336
2337 case BOND_LINK_UP:
2338 slave->link = BOND_LINK_UP;
2339 slave->jiffies = jiffies;
2449 2340
2450 if (old_duplex != slave->duplex) { 2341 if (bond->params.mode == BOND_MODE_8023AD) {
2451 bond_3ad_adapter_duplex_changed(slave); 2342 /* prevent it from being the active one */
2343 slave->state = BOND_STATE_BACKUP;
2344 } else if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
2345 /* make it immediately active */
2346 slave->state = BOND_STATE_ACTIVE;
2347 } else if (slave != bond->primary_slave) {
2348 /* prevent it from being the active one */
2349 slave->state = BOND_STATE_BACKUP;
2452 } 2350 }
2453 }
2454 2351
2455 } /* end of for */ 2352 printk(KERN_INFO DRV_NAME
2353 ": %s: link status definitely "
2354 "up for interface %s.\n",
2355 bond->dev->name, slave->dev->name);
2456 2356
2457 if (do_failover) { 2357 /* notify ad that the link status has changed */
2458 ASSERT_RTNL(); 2358 if (bond->params.mode == BOND_MODE_8023AD)
2359 bond_3ad_handle_link_change(slave, BOND_LINK_UP);
2459 2360
2460 write_lock_bh(&bond->curr_slave_lock); 2361 if ((bond->params.mode == BOND_MODE_TLB) ||
2362 (bond->params.mode == BOND_MODE_ALB))
2363 bond_alb_handle_link_change(bond, slave,
2364 BOND_LINK_UP);
2461 2365
2462 bond_select_active_slave(bond); 2366 if (!bond->curr_active_slave ||
2367 (slave == bond->primary_slave))
2368 goto do_failover;
2463 2369
2464 write_unlock_bh(&bond->curr_slave_lock); 2370 continue;
2465 2371
2466 } else 2372 case BOND_LINK_DOWN:
2467 bond_set_carrier(bond); 2373 slave->link = BOND_LINK_DOWN;
2468 2374
2469out: 2375 if (bond->params.mode == BOND_MODE_ACTIVEBACKUP ||
2470 return 0; 2376 bond->params.mode == BOND_MODE_8023AD)
2377 bond_set_slave_inactive_flags(slave);
2378
2379 printk(KERN_INFO DRV_NAME
2380 ": %s: link status definitely down for "
2381 "interface %s, disabling it\n",
2382 bond->dev->name, slave->dev->name);
2383
2384 if (bond->params.mode == BOND_MODE_8023AD)
2385 bond_3ad_handle_link_change(slave,
2386 BOND_LINK_DOWN);
2387
2388 if (bond->params.mode == BOND_MODE_TLB ||
2389 bond->params.mode == BOND_MODE_ALB)
2390 bond_alb_handle_link_change(bond, slave,
2391 BOND_LINK_DOWN);
2392
2393 if (slave == bond->curr_active_slave)
2394 goto do_failover;
2395
2396 continue;
2397
2398 default:
2399 printk(KERN_ERR DRV_NAME
2400 ": %s: invalid new link %d on slave %s\n",
2401 bond->dev->name, slave->new_link,
2402 slave->dev->name);
2403 slave->new_link = BOND_LINK_NOCHANGE;
2404
2405 continue;
2406 }
2407
2408do_failover:
2409 ASSERT_RTNL();
2410 write_lock_bh(&bond->curr_slave_lock);
2411 bond_select_active_slave(bond);
2412 write_unlock_bh(&bond->curr_slave_lock);
2413 }
2414
2415 bond_set_carrier(bond);
2471} 2416}
2472 2417
2473/* 2418/*
2474 * bond_mii_monitor 2419 * bond_mii_monitor
2475 * 2420 *
2476 * Really a wrapper that splits the mii monitor into two phases: an 2421 * Really a wrapper that splits the mii monitor into two phases: an
2477 * inspection, then (if inspection indicates something needs to be 2422 * inspection, then (if inspection indicates something needs to be done)
2478 * done) an acquisition of appropriate locks followed by another pass 2423 * an acquisition of appropriate locks followed by a commit phase to
2479 * to implement whatever link state changes are indicated. 2424 * implement whatever link state changes are indicated.
2480 */ 2425 */
2481void bond_mii_monitor(struct work_struct *work) 2426void bond_mii_monitor(struct work_struct *work)
2482{ 2427{
2483 struct bonding *bond = container_of(work, struct bonding, 2428 struct bonding *bond = container_of(work, struct bonding,
2484 mii_work.work); 2429 mii_work.work);
2485 unsigned long delay;
2486 2430
2487 read_lock(&bond->lock); 2431 read_lock(&bond->lock);
2488 if (bond->kill_timers) { 2432 if (bond->kill_timers)
2489 read_unlock(&bond->lock); 2433 goto out;
2490 return; 2434
2491 } 2435 if (bond->slave_cnt == 0)
2436 goto re_arm;
2492 2437
2493 if (bond->send_grat_arp) { 2438 if (bond->send_grat_arp) {
2494 read_lock(&bond->curr_slave_lock); 2439 read_lock(&bond->curr_slave_lock);
@@ -2496,19 +2441,24 @@ void bond_mii_monitor(struct work_struct *work)
2496 read_unlock(&bond->curr_slave_lock); 2441 read_unlock(&bond->curr_slave_lock);
2497 } 2442 }
2498 2443
2499 if (__bond_mii_monitor(bond, 0)) { 2444 if (bond_miimon_inspect(bond)) {
2500 read_unlock(&bond->lock); 2445 read_unlock(&bond->lock);
2501 rtnl_lock(); 2446 rtnl_lock();
2502 read_lock(&bond->lock); 2447 read_lock(&bond->lock);
2503 __bond_mii_monitor(bond, 1); 2448
2449 bond_miimon_commit(bond);
2450
2504 read_unlock(&bond->lock); 2451 read_unlock(&bond->lock);
2505 rtnl_unlock(); /* might sleep, hold no other locks */ 2452 rtnl_unlock(); /* might sleep, hold no other locks */
2506 read_lock(&bond->lock); 2453 read_lock(&bond->lock);
2507 } 2454 }
2508 2455
2509 delay = msecs_to_jiffies(bond->params.miimon); 2456re_arm:
2457 if (bond->params.miimon)
2458 queue_delayed_work(bond->wq, &bond->mii_work,
2459 msecs_to_jiffies(bond->params.miimon));
2460out:
2510 read_unlock(&bond->lock); 2461 read_unlock(&bond->lock);
2511 queue_delayed_work(bond->wq, &bond->mii_work, delay);
2512} 2462}
2513 2463
2514static __be32 bond_glean_dev_ip(struct net_device *dev) 2464static __be32 bond_glean_dev_ip(struct net_device *dev)