aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorJay Vosburgh <fubar@us.ibm.com>2011-10-28 11:42:50 -0400
committerDavid S. Miller <davem@davemloft.net>2011-10-30 03:13:14 -0400
commite6d265e8504ab4a3368b8645d318b344ee88b280 (patch)
tree6fd2bc16819bae491e56be2658fc3298b7efa92c /drivers/net
parent10ee0faed92c8af4baebd633372136a6608a41ea (diff)
bonding: eliminate bond_close race conditions
This patch resolves two sets of race conditions. Mitsuo Hayasaka <mitsuo.hayasaka.hu@hitachi.com> reported the first, as follows: The bond_close() calls cancel_delayed_work() to cancel delayed works. It, however, cannot cancel works that were already queued in workqueue. The bond_open() initializes work->data, and proccess_one_work() refers get_work_cwq(work)->wq->flags. The get_work_cwq() returns NULL when work->data has been initialized. Thus, a panic occurs. He included a patch that converted the cancel_delayed_work calls in bond_close to flush_delayed_work_sync, which eliminated the above problem. His patch is incorporated, at least in principle, into this patch. In this patch, we use cancel_delayed_work_sync in place of flush_delayed_work_sync, and also convert bond_uninit in addition to bond_close. This conversion to _sync, however, opens new races between bond_close and three periodically executing workqueue functions: bond_mii_monitor, bond_alb_monitor and bond_activebackup_arp_mon. The race occurs because bond_close and bond_uninit are always called with RTNL held, and these workqueue functions may acquire RTNL to perform failover-related activities. If bond_close or bond_uninit is waiting in cancel_delayed_work_sync, deadlock occurs. These deadlocks are resolved by having the workqueue functions acquire RTNL conditionally. If the rtnl_trylock() fails, the functions reschedule and return immediately. For the cases that are attempting to perform link failover, a delay of 1 is used; for the other cases, the normal interval is used (as those activities are not as time critical). Additionally, the bond_mii_monitor function now stores the delay in a variable (mimicing the structure of activebackup_arp_mon). Lastly, all of the above renders the kill_timers sentinel moot, and therefore it has been removed. Tested-by: Mitsuo Hayasaka <mitsuo.hayasaka.hu@hitachi.com> Signed-off-by: Jay Vosburgh <fubar@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/bonding/bond_3ad.c8
-rw-r--r--drivers/net/bonding/bond_alb.c16
-rw-r--r--drivers/net/bonding/bond_main.c96
-rw-r--r--drivers/net/bonding/bonding.h1
4 files changed, 61 insertions, 60 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index b33c099d65a..0ae0d7c54cc 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2110,9 +2110,6 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
2110 2110
2111 read_lock(&bond->lock); 2111 read_lock(&bond->lock);
2112 2112
2113 if (bond->kill_timers)
2114 goto out;
2115
2116 //check if there are any slaves 2113 //check if there are any slaves
2117 if (bond->slave_cnt == 0) 2114 if (bond->slave_cnt == 0)
2118 goto re_arm; 2115 goto re_arm;
@@ -2161,9 +2158,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
2161 } 2158 }
2162 2159
2163re_arm: 2160re_arm:
2164 if (!bond->kill_timers) 2161 queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
2165 queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks); 2162
2166out:
2167 read_unlock(&bond->lock); 2163 read_unlock(&bond->lock);
2168} 2164}
2169 2165
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index d4fbd2e6261..106b88a0473 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1343,10 +1343,6 @@ void bond_alb_monitor(struct work_struct *work)
1343 1343
1344 read_lock(&bond->lock); 1344 read_lock(&bond->lock);
1345 1345
1346 if (bond->kill_timers) {
1347 goto out;
1348 }
1349
1350 if (bond->slave_cnt == 0) { 1346 if (bond->slave_cnt == 0) {
1351 bond_info->tx_rebalance_counter = 0; 1347 bond_info->tx_rebalance_counter = 0;
1352 bond_info->lp_counter = 0; 1348 bond_info->lp_counter = 0;
@@ -1401,10 +1397,13 @@ void bond_alb_monitor(struct work_struct *work)
1401 1397
1402 /* 1398 /*
1403 * dev_set_promiscuity requires rtnl and 1399 * dev_set_promiscuity requires rtnl and
1404 * nothing else. 1400 * nothing else. Avoid race with bond_close.
1405 */ 1401 */
1406 read_unlock(&bond->lock); 1402 read_unlock(&bond->lock);
1407 rtnl_lock(); 1403 if (!rtnl_trylock()) {
1404 read_lock(&bond->lock);
1405 goto re_arm;
1406 }
1408 1407
1409 bond_info->rlb_promisc_timeout_counter = 0; 1408 bond_info->rlb_promisc_timeout_counter = 0;
1410 1409
@@ -1440,9 +1439,8 @@ void bond_alb_monitor(struct work_struct *work)
1440 } 1439 }
1441 1440
1442re_arm: 1441re_arm:
1443 if (!bond->kill_timers) 1442 queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks);
1444 queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks); 1443
1445out:
1446 read_unlock(&bond->lock); 1444 read_unlock(&bond->lock);
1447} 1445}
1448 1446
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index c5944f1a4f9..c34cc1e7c6f 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -773,9 +773,6 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
773 773
774 read_lock(&bond->lock); 774 read_lock(&bond->lock);
775 775
776 if (bond->kill_timers)
777 goto out;
778
779 /* rejoin all groups on bond device */ 776 /* rejoin all groups on bond device */
780 __bond_resend_igmp_join_requests(bond->dev); 777 __bond_resend_igmp_join_requests(bond->dev);
781 778
@@ -789,9 +786,9 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
789 __bond_resend_igmp_join_requests(vlan_dev); 786 __bond_resend_igmp_join_requests(vlan_dev);
790 } 787 }
791 788
792 if ((--bond->igmp_retrans > 0) && !bond->kill_timers) 789 if (--bond->igmp_retrans > 0)
793 queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5); 790 queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
794out: 791
795 read_unlock(&bond->lock); 792 read_unlock(&bond->lock);
796} 793}
797 794
@@ -2517,10 +2514,11 @@ void bond_mii_monitor(struct work_struct *work)
2517 struct bonding *bond = container_of(work, struct bonding, 2514 struct bonding *bond = container_of(work, struct bonding,
2518 mii_work.work); 2515 mii_work.work);
2519 bool should_notify_peers = false; 2516 bool should_notify_peers = false;
2517 unsigned long delay;
2520 2518
2521 read_lock(&bond->lock); 2519 read_lock(&bond->lock);
2522 if (bond->kill_timers) 2520
2523 goto out; 2521 delay = msecs_to_jiffies(bond->params.miimon);
2524 2522
2525 if (bond->slave_cnt == 0) 2523 if (bond->slave_cnt == 0)
2526 goto re_arm; 2524 goto re_arm;
@@ -2529,7 +2527,15 @@ void bond_mii_monitor(struct work_struct *work)
2529 2527
2530 if (bond_miimon_inspect(bond)) { 2528 if (bond_miimon_inspect(bond)) {
2531 read_unlock(&bond->lock); 2529 read_unlock(&bond->lock);
2532 rtnl_lock(); 2530
2531 /* Race avoidance with bond_close cancel of workqueue */
2532 if (!rtnl_trylock()) {
2533 read_lock(&bond->lock);
2534 delay = 1;
2535 should_notify_peers = false;
2536 goto re_arm;
2537 }
2538
2533 read_lock(&bond->lock); 2539 read_lock(&bond->lock);
2534 2540
2535 bond_miimon_commit(bond); 2541 bond_miimon_commit(bond);
@@ -2540,14 +2546,18 @@ void bond_mii_monitor(struct work_struct *work)
2540 } 2546 }
2541 2547
2542re_arm: 2548re_arm:
2543 if (bond->params.miimon && !bond->kill_timers) 2549 if (bond->params.miimon)
2544 queue_delayed_work(bond->wq, &bond->mii_work, 2550 queue_delayed_work(bond->wq, &bond->mii_work, delay);
2545 msecs_to_jiffies(bond->params.miimon)); 2551
2546out:
2547 read_unlock(&bond->lock); 2552 read_unlock(&bond->lock);
2548 2553
2549 if (should_notify_peers) { 2554 if (should_notify_peers) {
2550 rtnl_lock(); 2555 if (!rtnl_trylock()) {
2556 read_lock(&bond->lock);
2557 bond->send_peer_notif++;
2558 read_unlock(&bond->lock);
2559 return;
2560 }
2551 netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS); 2561 netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS);
2552 rtnl_unlock(); 2562 rtnl_unlock();
2553 } 2563 }
@@ -2789,9 +2799,6 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
2789 2799
2790 delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); 2800 delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
2791 2801
2792 if (bond->kill_timers)
2793 goto out;
2794
2795 if (bond->slave_cnt == 0) 2802 if (bond->slave_cnt == 0)
2796 goto re_arm; 2803 goto re_arm;
2797 2804
@@ -2888,9 +2895,9 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
2888 } 2895 }
2889 2896
2890re_arm: 2897re_arm:
2891 if (bond->params.arp_interval && !bond->kill_timers) 2898 if (bond->params.arp_interval)
2892 queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); 2899 queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
2893out: 2900
2894 read_unlock(&bond->lock); 2901 read_unlock(&bond->lock);
2895} 2902}
2896 2903
@@ -3131,9 +3138,6 @@ void bond_activebackup_arp_mon(struct work_struct *work)
3131 3138
3132 read_lock(&bond->lock); 3139 read_lock(&bond->lock);
3133 3140
3134 if (bond->kill_timers)
3135 goto out;
3136
3137 delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); 3141 delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
3138 3142
3139 if (bond->slave_cnt == 0) 3143 if (bond->slave_cnt == 0)
@@ -3143,7 +3147,15 @@ void bond_activebackup_arp_mon(struct work_struct *work)
3143 3147
3144 if (bond_ab_arp_inspect(bond, delta_in_ticks)) { 3148 if (bond_ab_arp_inspect(bond, delta_in_ticks)) {
3145 read_unlock(&bond->lock); 3149 read_unlock(&bond->lock);
3146 rtnl_lock(); 3150
3151 /* Race avoidance with bond_close flush of workqueue */
3152 if (!rtnl_trylock()) {
3153 read_lock(&bond->lock);
3154 delta_in_ticks = 1;
3155 should_notify_peers = false;
3156 goto re_arm;
3157 }
3158
3147 read_lock(&bond->lock); 3159 read_lock(&bond->lock);
3148 3160
3149 bond_ab_arp_commit(bond, delta_in_ticks); 3161 bond_ab_arp_commit(bond, delta_in_ticks);
@@ -3156,13 +3168,18 @@ void bond_activebackup_arp_mon(struct work_struct *work)
3156 bond_ab_arp_probe(bond); 3168 bond_ab_arp_probe(bond);
3157 3169
3158re_arm: 3170re_arm:
3159 if (bond->params.arp_interval && !bond->kill_timers) 3171 if (bond->params.arp_interval)
3160 queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); 3172 queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
3161out: 3173
3162 read_unlock(&bond->lock); 3174 read_unlock(&bond->lock);
3163 3175
3164 if (should_notify_peers) { 3176 if (should_notify_peers) {
3165 rtnl_lock(); 3177 if (!rtnl_trylock()) {
3178 read_lock(&bond->lock);
3179 bond->send_peer_notif++;
3180 read_unlock(&bond->lock);
3181 return;
3182 }
3166 netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS); 3183 netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS);
3167 rtnl_unlock(); 3184 rtnl_unlock();
3168 } 3185 }
@@ -3424,8 +3441,6 @@ static int bond_open(struct net_device *bond_dev)
3424 struct slave *slave; 3441 struct slave *slave;
3425 int i; 3442 int i;
3426 3443
3427 bond->kill_timers = 0;
3428
3429 /* reset slave->backup and slave->inactive */ 3444 /* reset slave->backup and slave->inactive */
3430 read_lock(&bond->lock); 3445 read_lock(&bond->lock);
3431 if (bond->slave_cnt > 0) { 3446 if (bond->slave_cnt > 0) {
@@ -3494,33 +3509,30 @@ static int bond_close(struct net_device *bond_dev)
3494 3509
3495 bond->send_peer_notif = 0; 3510 bond->send_peer_notif = 0;
3496 3511
3497 /* signal timers not to re-arm */
3498 bond->kill_timers = 1;
3499
3500 write_unlock_bh(&bond->lock); 3512 write_unlock_bh(&bond->lock);
3501 3513
3502 if (bond->params.miimon) { /* link check interval, in milliseconds. */ 3514 if (bond->params.miimon) { /* link check interval, in milliseconds. */
3503 cancel_delayed_work(&bond->mii_work); 3515 cancel_delayed_work_sync(&bond->mii_work);
3504 } 3516 }
3505 3517
3506 if (bond->params.arp_interval) { /* arp interval, in milliseconds. */ 3518 if (bond->params.arp_interval) { /* arp interval, in milliseconds. */
3507 cancel_delayed_work(&bond->arp_work); 3519 cancel_delayed_work_sync(&bond->arp_work);
3508 } 3520 }
3509 3521
3510 switch (bond->params.mode) { 3522 switch (bond->params.mode) {
3511 case BOND_MODE_8023AD: 3523 case BOND_MODE_8023AD:
3512 cancel_delayed_work(&bond->ad_work); 3524 cancel_delayed_work_sync(&bond->ad_work);
3513 break; 3525 break;
3514 case BOND_MODE_TLB: 3526 case BOND_MODE_TLB:
3515 case BOND_MODE_ALB: 3527 case BOND_MODE_ALB:
3516 cancel_delayed_work(&bond->alb_work); 3528 cancel_delayed_work_sync(&bond->alb_work);
3517 break; 3529 break;
3518 default: 3530 default:
3519 break; 3531 break;
3520 } 3532 }
3521 3533
3522 if (delayed_work_pending(&bond->mcast_work)) 3534 if (delayed_work_pending(&bond->mcast_work))
3523 cancel_delayed_work(&bond->mcast_work); 3535 cancel_delayed_work_sync(&bond->mcast_work);
3524 3536
3525 if (bond_is_lb(bond)) { 3537 if (bond_is_lb(bond)) {
3526 /* Must be called only after all 3538 /* Must be called only after all
@@ -4367,26 +4379,22 @@ static void bond_setup(struct net_device *bond_dev)
4367 4379
4368static void bond_work_cancel_all(struct bonding *bond) 4380static void bond_work_cancel_all(struct bonding *bond)
4369{ 4381{
4370 write_lock_bh(&bond->lock);
4371 bond->kill_timers = 1;
4372 write_unlock_bh(&bond->lock);
4373
4374 if (bond->params.miimon && delayed_work_pending(&bond->mii_work)) 4382 if (bond->params.miimon && delayed_work_pending(&bond->mii_work))
4375 cancel_delayed_work(&bond->mii_work); 4383 cancel_delayed_work_sync(&bond->mii_work);
4376 4384
4377 if (bond->params.arp_interval && delayed_work_pending(&bond->arp_work)) 4385 if (bond->params.arp_interval && delayed_work_pending(&bond->arp_work))
4378 cancel_delayed_work(&bond->arp_work); 4386 cancel_delayed_work_sync(&bond->arp_work);
4379 4387
4380 if (bond->params.mode == BOND_MODE_ALB && 4388 if (bond->params.mode == BOND_MODE_ALB &&
4381 delayed_work_pending(&bond->alb_work)) 4389 delayed_work_pending(&bond->alb_work))
4382 cancel_delayed_work(&bond->alb_work); 4390 cancel_delayed_work_sync(&bond->alb_work);
4383 4391
4384 if (bond->params.mode == BOND_MODE_8023AD && 4392 if (bond->params.mode == BOND_MODE_8023AD &&
4385 delayed_work_pending(&bond->ad_work)) 4393 delayed_work_pending(&bond->ad_work))
4386 cancel_delayed_work(&bond->ad_work); 4394 cancel_delayed_work_sync(&bond->ad_work);
4387 4395
4388 if (delayed_work_pending(&bond->mcast_work)) 4396 if (delayed_work_pending(&bond->mcast_work))
4389 cancel_delayed_work(&bond->mcast_work); 4397 cancel_delayed_work_sync(&bond->mcast_work);
4390} 4398}
4391 4399
4392/* 4400/*
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 82fec5fc75d..1aecc37e5b4 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -222,7 +222,6 @@ struct bonding {
222 struct slave *); 222 struct slave *);
223 rwlock_t lock; 223 rwlock_t lock;
224 rwlock_t curr_slave_lock; 224 rwlock_t curr_slave_lock;
225 s8 kill_timers;
226 u8 send_peer_notif; 225 u8 send_peer_notif;
227 s8 setup_by_slave; 226 s8 setup_by_slave;
228 s8 igmp_retrans; 227 s8 igmp_retrans;