aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bonding/bond_main.c
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/bonding/bond_main.c
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/bonding/bond_main.c')
-rw-r--r--drivers/net/bonding/bond_main.c96
1 files changed, 52 insertions, 44 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index c5944f1a4f9d..c34cc1e7c6f6 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/*