diff options
Diffstat (limited to 'drivers/net/bonding/bond_main.c')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 96 |
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) read_lock(&bond->lock); - if (bond->kill_timers) - goto out; - /* rejoin all groups on bond device */ __bond_resend_igmp_join_requests(bond->dev); @@ -789,9 +786,9 @@ static void bond_resend_igmp_join_requests(struct bonding *bond) __bond_resend_igmp_join_requests(vlan_dev); } - if ((--bond->igmp_retrans > 0) && !bond->kill_timers) + if (--bond->igmp_retrans > 0) queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5); -out: + read_unlock(&bond->lock); } @@ -2517,10 +2514,11 @@ void bond_mii_monitor(struct work_struct *work) struct bonding *bond = container_of(work, struct bonding, mii_work.work); bool should_notify_peers = false; + unsigned long delay; read_lock(&bond->lock); - if (bond->kill_timers) - goto out; + + delay = msecs_to_jiffies(bond->params.miimon); if (bond->slave_cnt == 0) goto re_arm; @@ -2529,7 +2527,15 @@ void bond_mii_monitor(struct work_struct *work) if (bond_miimon_inspect(bond)) { read_unlock(&bond->lock); - rtnl_lock(); + + /* Race avoidance with bond_close cancel of workqueue */ + if (!rtnl_trylock()) { + read_lock(&bond->lock); + delay = 1; + should_notify_peers = false; + goto re_arm; + } + read_lock(&bond->lock); bond_miimon_commit(bond); @@ -2540,14 +2546,18 @@ void bond_mii_monitor(struct work_struct *work) } re_arm: - if (bond->params.miimon && !bond->kill_timers) - queue_delayed_work(bond->wq, &bond->mii_work, - msecs_to_jiffies(bond->params.miimon)); -out: + if (bond->params.miimon) + queue_delayed_work(bond->wq, &bond->mii_work, delay); + read_unlock(&bond->lock); if (should_notify_peers) { - rtnl_lock(); + if (!rtnl_trylock()) { + read_lock(&bond->lock); + bond->send_peer_notif++; + read_unlock(&bond->lock); + return; + } netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS); rtnl_unlock(); } @@ -2789,9 +2799,6 @@ void bond_loadbalance_arp_mon(struct work_struct *work) delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); - if (bond->kill_timers) - goto out; - if (bond->slave_cnt == 0) goto re_arm; @@ -2888,9 +2895,9 @@ void bond_loadbalance_arp_mon(struct work_struct *work) } re_arm: - if (bond->params.arp_interval && !bond->kill_timers) + if (bond->params.arp_interval) queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); -out: + read_unlock(&bond->lock); } @@ -3131,9 +3138,6 @@ void bond_activebackup_arp_mon(struct work_struct *work) read_lock(&bond->lock); - if (bond->kill_timers) - goto out; - delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); if (bond->slave_cnt == 0) @@ -3143,7 +3147,15 @@ void bond_activebackup_arp_mon(struct work_struct *work) if (bond_ab_arp_inspect(bond, delta_in_ticks)) { read_unlock(&bond->lock); - rtnl_lock(); + + /* Race avoidance with bond_close flush of workqueue */ + if (!rtnl_trylock()) { + read_lock(&bond->lock); + delta_in_ticks = 1; + should_notify_peers = false; + goto re_arm; + } + read_lock(&bond->lock); bond_ab_arp_commit(bond, delta_in_ticks); @@ -3156,13 +3168,18 @@ void bond_activebackup_arp_mon(struct work_struct *work) bond_ab_arp_probe(bond); re_arm: - if (bond->params.arp_interval && !bond->kill_timers) + if (bond->params.arp_interval) queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); -out: + read_unlock(&bond->lock); if (should_notify_peers) { - rtnl_lock(); + if (!rtnl_trylock()) { + read_lock(&bond->lock); + bond->send_peer_notif++; + read_unlock(&bond->lock); + return; + } netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS); rtnl_unlock(); } @@ -3424,8 +3441,6 @@ static int bond_open(struct net_device *bond_dev) struct slave *slave; int i; - bond->kill_timers = 0; - /* reset slave->backup and slave->inactive */ read_lock(&bond->lock); if (bond->slave_cnt > 0) { @@ -3494,33 +3509,30 @@ static int bond_close(struct net_device *bond_dev) bond->send_peer_notif = 0; - /* signal timers not to re-arm */ - bond->kill_timers = 1; - write_unlock_bh(&bond->lock); if (bond->params.miimon) { /* link check interval, in milliseconds. */ - cancel_delayed_work(&bond->mii_work); + cancel_delayed_work_sync(&bond->mii_work); } if (bond->params.arp_interval) { /* arp interval, in milliseconds. */ - cancel_delayed_work(&bond->arp_work); + cancel_delayed_work_sync(&bond->arp_work); } switch (bond->params.mode) { case BOND_MODE_8023AD: - cancel_delayed_work(&bond->ad_work); + cancel_delayed_work_sync(&bond->ad_work); break; case BOND_MODE_TLB: case BOND_MODE_ALB: - cancel_delayed_work(&bond->alb_work); + cancel_delayed_work_sync(&bond->alb_work); break; default: break; } if (delayed_work_pending(&bond->mcast_work)) - cancel_delayed_work(&bond->mcast_work); + cancel_delayed_work_sync(&bond->mcast_work); if (bond_is_lb(bond)) { /* Must be called only after all @@ -4367,26 +4379,22 @@ static void bond_setup(struct net_device *bond_dev) static void bond_work_cancel_all(struct bonding *bond) { - write_lock_bh(&bond->lock); - bond->kill_timers = 1; - write_unlock_bh(&bond->lock); - if (bond->params.miimon && delayed_work_pending(&bond->mii_work)) - cancel_delayed_work(&bond->mii_work); + cancel_delayed_work_sync(&bond->mii_work); if (bond->params.arp_interval && delayed_work_pending(&bond->arp_work)) - cancel_delayed_work(&bond->arp_work); + cancel_delayed_work_sync(&bond->arp_work); if (bond->params.mode == BOND_MODE_ALB && delayed_work_pending(&bond->alb_work)) - cancel_delayed_work(&bond->alb_work); + cancel_delayed_work_sync(&bond->alb_work); if (bond->params.mode == BOND_MODE_8023AD && delayed_work_pending(&bond->ad_work)) - cancel_delayed_work(&bond->ad_work); + cancel_delayed_work_sync(&bond->ad_work); if (delayed_work_pending(&bond->mcast_work)) - cancel_delayed_work(&bond->mcast_work); + cancel_delayed_work_sync(&bond->mcast_work); } /* |