diff options
Diffstat (limited to 'drivers/net/bonding/bond_main.c')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 163 |
1 files changed, 62 insertions, 101 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 36eab0c4fb33..c0456cc86610 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -591,33 +591,22 @@ static int bond_set_allmulti(struct bonding *bond, int inc) * device and retransmit an IGMP JOIN request to the current active * slave. */ -static void bond_resend_igmp_join_requests(struct bonding *bond) +static void bond_resend_igmp_join_requests_delayed(struct work_struct *work) { + struct bonding *bond = container_of(work, struct bonding, + mcast_work.work); + if (!rtnl_trylock()) { queue_delayed_work(bond->wq, &bond->mcast_work, 1); return; } call_netdevice_notifiers(NETDEV_RESEND_IGMP, bond->dev); - rtnl_unlock(); - /* We use curr_slave_lock to protect against concurrent access to - * igmp_retrans from multiple running instances of this function and - * bond_change_active_slave - */ - write_lock_bh(&bond->curr_slave_lock); if (bond->igmp_retrans > 1) { bond->igmp_retrans--; queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5); } - write_unlock_bh(&bond->curr_slave_lock); -} - -static void bond_resend_igmp_join_requests_delayed(struct work_struct *work) -{ - struct bonding *bond = container_of(work, struct bonding, - mcast_work.work); - - bond_resend_igmp_join_requests(bond); + rtnl_unlock(); } /* Flush bond's hardware addresses from slave @@ -697,14 +686,12 @@ static void bond_set_dev_addr(struct net_device *bond_dev, * * Perform special MAC address swapping for fail_over_mac settings * - * Called with RTNL, bond->lock for read, curr_slave_lock for write_bh. + * Called with RTNL, curr_slave_lock for write_bh. */ static void bond_do_fail_over_mac(struct bonding *bond, struct slave *new_active, struct slave *old_active) __releases(&bond->curr_slave_lock) - __releases(&bond->lock) - __acquires(&bond->lock) __acquires(&bond->curr_slave_lock) { u8 tmp_mac[ETH_ALEN]; @@ -715,9 +702,7 @@ static void bond_do_fail_over_mac(struct bonding *bond, case BOND_FOM_ACTIVE: if (new_active) { write_unlock_bh(&bond->curr_slave_lock); - read_unlock(&bond->lock); bond_set_dev_addr(bond->dev, new_active->dev); - read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); } break; @@ -731,7 +716,6 @@ static void bond_do_fail_over_mac(struct bonding *bond, return; write_unlock_bh(&bond->curr_slave_lock); - read_unlock(&bond->lock); if (old_active) { memcpy(tmp_mac, new_active->dev->dev_addr, ETH_ALEN); @@ -761,7 +745,6 @@ static void bond_do_fail_over_mac(struct bonding *bond, pr_err("%s: Error %d setting MAC of slave %s\n", bond->dev->name, -rv, new_active->dev->name); out: - read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); break; default: @@ -821,7 +804,11 @@ static struct slave *bond_find_best_slave(struct bonding *bond) static bool bond_should_notify_peers(struct bonding *bond) { - struct slave *slave = bond->curr_active_slave; + struct slave *slave; + + rcu_read_lock(); + slave = rcu_dereference(bond->curr_active_slave); + rcu_read_unlock(); pr_debug("bond_should_notify_peers: bond %s slave %s\n", bond->dev->name, slave ? slave->dev->name : "NULL"); @@ -846,8 +833,7 @@ static bool bond_should_notify_peers(struct bonding *bond) * because it is apparently the best available slave we have, even though its * updelay hasn't timed out yet. * - * If new_active is not NULL, caller must hold bond->lock for read and - * curr_slave_lock for write_bh. + * If new_active is not NULL, caller must hold curr_slave_lock for write_bh. */ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) { @@ -916,14 +902,12 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) } write_unlock_bh(&bond->curr_slave_lock); - read_unlock(&bond->lock); call_netdevice_notifiers(NETDEV_BONDING_FAILOVER, bond->dev); if (should_notify_peers) call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, bond->dev); - read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); } } @@ -949,7 +933,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) * - The primary_slave has got its link back. * - A slave has got its link back and there's no old curr_active_slave. * - * Caller must hold bond->lock for read and curr_slave_lock for write_bh. + * Caller must hold curr_slave_lock for write_bh. */ void bond_select_active_slave(struct bonding *bond) { @@ -1594,11 +1578,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_set_carrier(bond); if (USES_PRIMARY(bond->params.mode)) { - read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); bond_select_active_slave(bond); write_unlock_bh(&bond->curr_slave_lock); - read_unlock(&bond->lock); } pr_info("%s: enslaving %s as a%s interface with a%s link.\n", @@ -1618,19 +1600,13 @@ err_detach: bond_hw_addr_flush(bond_dev, slave_dev); vlan_vids_del_by_dev(slave_dev, bond_dev); - write_lock_bh(&bond->lock); if (bond->primary_slave == new_slave) bond->primary_slave = NULL; if (bond->curr_active_slave == new_slave) { - bond_change_active_slave(bond, NULL); - write_unlock_bh(&bond->lock); - read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); + bond_change_active_slave(bond, NULL); bond_select_active_slave(bond); write_unlock_bh(&bond->curr_slave_lock); - read_unlock(&bond->lock); - } else { - write_unlock_bh(&bond->lock); } slave_disable_netpoll(new_slave); @@ -1695,20 +1671,16 @@ static int __bond_release_one(struct net_device *bond_dev, } block_netpoll_tx(); - write_lock_bh(&bond->lock); slave = bond_get_slave_by_dev(bond, slave_dev); if (!slave) { /* not a slave of this bond */ pr_info("%s: %s not enslaved\n", bond_dev->name, slave_dev->name); - write_unlock_bh(&bond->lock); unblock_netpoll_tx(); return -EINVAL; } - write_unlock_bh(&bond->lock); - /* release the slave from its bond */ bond->slave_cnt--; @@ -1720,12 +1692,10 @@ static int __bond_release_one(struct net_device *bond_dev, write_lock_bh(&bond->lock); /* Inform AD package of unbinding of slave. */ - if (bond->params.mode == BOND_MODE_8023AD) { - /* must be called before the slave is - * detached from the list - */ + if (bond->params.mode == BOND_MODE_8023AD) bond_3ad_unbind_slave(slave); - } + + write_unlock_bh(&bond->lock); pr_info("%s: releasing %s interface %s\n", bond_dev->name, @@ -1748,8 +1718,11 @@ static int __bond_release_one(struct net_device *bond_dev, if (bond->primary_slave == slave) bond->primary_slave = NULL; - if (oldcurrent == slave) + if (oldcurrent == slave) { + write_lock_bh(&bond->curr_slave_lock); bond_change_active_slave(bond, NULL); + write_unlock_bh(&bond->curr_slave_lock); + } if (bond_is_lb(bond)) { /* Must be called only after the slave has been @@ -1757,9 +1730,7 @@ static int __bond_release_one(struct net_device *bond_dev, * has been cleared (if our_slave == old_current), * but before a new active slave is selected. */ - write_unlock_bh(&bond->lock); bond_alb_deinit_slave(bond, slave); - write_lock_bh(&bond->lock); } if (all) { @@ -1770,15 +1741,11 @@ static int __bond_release_one(struct net_device *bond_dev, * is no concern that another slave add/remove event * will interfere. */ - write_unlock_bh(&bond->lock); - read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); bond_select_active_slave(bond); write_unlock_bh(&bond->curr_slave_lock); - read_unlock(&bond->lock); - write_lock_bh(&bond->lock); } if (!bond_has_slaves(bond)) { @@ -1793,7 +1760,6 @@ static int __bond_release_one(struct net_device *bond_dev, } } - write_unlock_bh(&bond->lock); unblock_netpoll_tx(); synchronize_rcu(); @@ -1928,7 +1894,7 @@ static int bond_miimon_inspect(struct bonding *bond) ignore_updelay = !bond->curr_active_slave ? true : false; - bond_for_each_slave(bond, slave, iter) { + bond_for_each_slave_rcu(bond, slave, iter) { slave->new_link = BOND_LINK_NOCHANGE; link_state = bond_check_dev_link(bond, slave->dev, 0); @@ -2126,41 +2092,35 @@ void bond_mii_monitor(struct work_struct *work) bool should_notify_peers = false; unsigned long delay; - read_lock(&bond->lock); - delay = msecs_to_jiffies(bond->params.miimon); if (!bond_has_slaves(bond)) goto re_arm; + rcu_read_lock(); + should_notify_peers = bond_should_notify_peers(bond); if (bond_miimon_inspect(bond)) { - read_unlock(&bond->lock); + rcu_read_unlock(); /* 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); - read_unlock(&bond->lock); rtnl_unlock(); /* might sleep, hold no other locks */ - read_lock(&bond->lock); - } + } else + rcu_read_unlock(); re_arm: if (bond->params.miimon) queue_delayed_work(bond->wq, &bond->mii_work, delay); - read_unlock(&bond->lock); - if (should_notify_peers) { if (!rtnl_trylock()) return; @@ -2422,12 +2382,12 @@ void bond_loadbalance_arp_mon(struct work_struct *work) struct list_head *iter; int do_failover = 0; - read_lock(&bond->lock); - if (!bond_has_slaves(bond)) goto re_arm; - oldcurrent = bond->curr_active_slave; + rcu_read_lock(); + + oldcurrent = ACCESS_ONCE(bond->curr_active_slave); /* see if any of the previous devices are up now (i.e. they have * xmt and rcv traffic). the curr_active_slave does not come into * the picture unless it is null. also, slave->jiffies is not needed @@ -2436,7 +2396,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work) * TODO: what about up/down delay in arp mode? it wasn't here before * so it can wait */ - bond_for_each_slave(bond, slave, iter) { + bond_for_each_slave_rcu(bond, slave, iter) { unsigned long trans_start = dev_trans_start(slave->dev); if (slave->link != BOND_LINK_UP) { @@ -2498,7 +2458,14 @@ void bond_loadbalance_arp_mon(struct work_struct *work) bond_arp_send_all(bond, slave); } + rcu_read_unlock(); + if (do_failover) { + /* the bond_select_active_slave must hold RTNL + * and curr_slave_lock for write. + */ + if (!rtnl_trylock()) + goto re_arm; block_netpoll_tx(); write_lock_bh(&bond->curr_slave_lock); @@ -2506,14 +2473,13 @@ void bond_loadbalance_arp_mon(struct work_struct *work) write_unlock_bh(&bond->curr_slave_lock); unblock_netpoll_tx(); + rtnl_unlock(); } re_arm: if (bond->params.arp_interval) queue_delayed_work(bond->wq, &bond->arp_work, msecs_to_jiffies(bond->params.arp_interval)); - - read_unlock(&bond->lock); } /* @@ -2522,7 +2488,7 @@ re_arm: * place for the slave. Returns 0 if no changes are found, >0 if changes * to link states must be committed. * - * Called with bond->lock held for read. + * Called with rcu_read_lock hold. */ static int bond_ab_arp_inspect(struct bonding *bond) { @@ -2531,7 +2497,7 @@ static int bond_ab_arp_inspect(struct bonding *bond) struct slave *slave; int commit = 0; - bond_for_each_slave(bond, slave, iter) { + bond_for_each_slave_rcu(bond, slave, iter) { slave->new_link = BOND_LINK_NOCHANGE; last_rx = slave_last_rx(bond, slave); @@ -2593,7 +2559,7 @@ static int bond_ab_arp_inspect(struct bonding *bond) * Called to commit link state changes noted by inspection step of * active-backup mode ARP monitor. * - * Called with RTNL and bond->lock for read. + * Called with RTNL hold. */ static void bond_ab_arp_commit(struct bonding *bond) { @@ -2668,19 +2634,20 @@ do_failover: /* * Send ARP probes for active-backup mode ARP monitor. * - * Called with bond->lock held for read. + * Called with rcu_read_lock hold. */ static void bond_ab_arp_probe(struct bonding *bond) { - struct slave *slave, *before = NULL, *new_slave = NULL; + struct slave *slave, *before = NULL, *new_slave = NULL, + *curr_arp_slave = rcu_dereference(bond->current_arp_slave); struct list_head *iter; bool found = false; read_lock(&bond->curr_slave_lock); - if (bond->current_arp_slave && bond->curr_active_slave) + if (curr_arp_slave && bond->curr_active_slave) pr_info("PROBE: c_arp %s && cas %s BAD\n", - bond->current_arp_slave->dev->name, + curr_arp_slave->dev->name, bond->curr_active_slave->dev->name); if (bond->curr_active_slave) { @@ -2696,15 +2663,15 @@ static void bond_ab_arp_probe(struct bonding *bond) * for becoming the curr_active_slave */ - if (!bond->current_arp_slave) { - bond->current_arp_slave = bond_first_slave(bond); - if (!bond->current_arp_slave) + if (!curr_arp_slave) { + curr_arp_slave = bond_first_slave_rcu(bond); + if (!curr_arp_slave) return; } - bond_set_slave_inactive_flags(bond->current_arp_slave); + bond_set_slave_inactive_flags(curr_arp_slave); - bond_for_each_slave(bond, slave, iter) { + bond_for_each_slave_rcu(bond, slave, iter) { if (!found && !before && IS_UP(slave->dev)) before = slave; @@ -2727,7 +2694,7 @@ static void bond_ab_arp_probe(struct bonding *bond) pr_info("%s: backup interface %s is now down.\n", bond->dev->name, slave->dev->name); } - if (slave == bond->current_arp_slave) + if (slave == curr_arp_slave) found = true; } @@ -2741,8 +2708,7 @@ static void bond_ab_arp_probe(struct bonding *bond) bond_set_slave_active_flags(new_slave); bond_arp_send_all(bond, new_slave); new_slave->jiffies = jiffies; - bond->current_arp_slave = new_slave; - + rcu_assign_pointer(bond->current_arp_slave, new_slave); } void bond_activebackup_arp_mon(struct work_struct *work) @@ -2752,43 +2718,38 @@ void bond_activebackup_arp_mon(struct work_struct *work) bool should_notify_peers = false; int delta_in_ticks; - read_lock(&bond->lock); - delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); if (!bond_has_slaves(bond)) goto re_arm; + rcu_read_lock(); + should_notify_peers = bond_should_notify_peers(bond); if (bond_ab_arp_inspect(bond)) { - read_unlock(&bond->lock); + rcu_read_unlock(); /* 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); - read_unlock(&bond->lock); rtnl_unlock(); - read_lock(&bond->lock); + rcu_read_lock(); } bond_ab_arp_probe(bond); + rcu_read_unlock(); re_arm: if (bond->params.arp_interval) queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); - read_unlock(&bond->lock); - if (should_notify_peers) { if (!rtnl_trylock()) return; @@ -4199,9 +4160,9 @@ static int bond_check_params(struct bond_params *params) (arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[i]; i++) { /* not complete check, but should be good enough to catch mistakes */ - __be32 ip = in_aton(arp_ip_target[i]); - if (!isdigit(arp_ip_target[i][0]) || ip == 0 || - ip == htonl(INADDR_BROADCAST)) { + __be32 ip; + if (!in4_pton(arp_ip_target[i], -1, (u8 *)&ip, -1, NULL) || + IS_IP_TARGET_UNUSABLE_ADDRESS(ip)) { pr_warning("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n", arp_ip_target[i]); arp_interval = 0; |