aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bonding
diff options
context:
space:
mode:
authordingtianhong <dingtianhong@huawei.com>2013-12-12 21:19:39 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-14 01:58:01 -0500
commit4cb4f97b7e361745281e843499ba58691112d2f8 (patch)
treeeb247661d99b945c070eb5ddd1875341d5b78446 /drivers/net/bonding
parentb2e7aceb00b2621431e220748f7158b131b89e7b (diff)
bonding: rebuild the lock use for bond_mii_monitor()
The bond_mii_monitor() still use bond lock to protect bond slave list, it is no effect, I have 2 way to fix the problem, move the RTNL to the top of the function, or add RCU to protect the bond slave list, according to the Jay Vosburgh's opinion, 10 times one second is a truely big performance loss if use RTNL to protect the whole monitor, so I would take the advice and use RCU to protect the bond slave list. The bond_has_slave() will not protect by anything, there will no things happen if the slave list is be changed, unless the bond was free, but it will not happened before the monitor, the bond will closed before be freed. The peers notify for the bond will calling curr_active_slave, so derefence the slave to make sure we will accessing the same slave if the curr_active_slave changed, as the rcu dereference need in read-side critical sector and bond_change_active_slave() will call it with no RCU hold, so add peer notify in rcu_read_lock which will be nested in monitor. Suggested-by: Jay Vosburgh <fubar@us.ibm.com> Suggested-by: Veaceslav Falico <vfalico@redhat.com> Signed-off-by: Ding Tianhong <dingtianhong@huawei.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r--drivers/net/bonding/bond_main.c24
1 files changed, 11 insertions, 13 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 04ae426fcc81..b34634a96710 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -815,7 +815,11 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
815 815
816static bool bond_should_notify_peers(struct bonding *bond) 816static bool bond_should_notify_peers(struct bonding *bond)
817{ 817{
818 struct slave *slave = bond->curr_active_slave; 818 struct slave *slave;
819
820 rcu_read_lock();
821 slave = rcu_dereference(bond->curr_active_slave);
822 rcu_read_unlock();
819 823
820 pr_debug("bond_should_notify_peers: bond %s slave %s\n", 824 pr_debug("bond_should_notify_peers: bond %s slave %s\n",
821 bond->dev->name, slave ? slave->dev->name : "NULL"); 825 bond->dev->name, slave ? slave->dev->name : "NULL");
@@ -1919,7 +1923,7 @@ static int bond_miimon_inspect(struct bonding *bond)
1919 1923
1920 ignore_updelay = !bond->curr_active_slave ? true : false; 1924 ignore_updelay = !bond->curr_active_slave ? true : false;
1921 1925
1922 bond_for_each_slave(bond, slave, iter) { 1926 bond_for_each_slave_rcu(bond, slave, iter) {
1923 slave->new_link = BOND_LINK_NOCHANGE; 1927 slave->new_link = BOND_LINK_NOCHANGE;
1924 1928
1925 link_state = bond_check_dev_link(bond, slave->dev, 0); 1929 link_state = bond_check_dev_link(bond, slave->dev, 0);
@@ -2117,41 +2121,35 @@ void bond_mii_monitor(struct work_struct *work)
2117 bool should_notify_peers = false; 2121 bool should_notify_peers = false;
2118 unsigned long delay; 2122 unsigned long delay;
2119 2123
2120 read_lock(&bond->lock);
2121
2122 delay = msecs_to_jiffies(bond->params.miimon); 2124 delay = msecs_to_jiffies(bond->params.miimon);
2123 2125
2124 if (!bond_has_slaves(bond)) 2126 if (!bond_has_slaves(bond))
2125 goto re_arm; 2127 goto re_arm;
2126 2128
2129 rcu_read_lock();
2130
2127 should_notify_peers = bond_should_notify_peers(bond); 2131 should_notify_peers = bond_should_notify_peers(bond);
2128 2132
2129 if (bond_miimon_inspect(bond)) { 2133 if (bond_miimon_inspect(bond)) {
2130 read_unlock(&bond->lock); 2134 rcu_read_unlock();
2131 2135
2132 /* Race avoidance with bond_close cancel of workqueue */ 2136 /* Race avoidance with bond_close cancel of workqueue */
2133 if (!rtnl_trylock()) { 2137 if (!rtnl_trylock()) {
2134 read_lock(&bond->lock);
2135 delay = 1; 2138 delay = 1;
2136 should_notify_peers = false; 2139 should_notify_peers = false;
2137 goto re_arm; 2140 goto re_arm;
2138 } 2141 }
2139 2142
2140 read_lock(&bond->lock);
2141
2142 bond_miimon_commit(bond); 2143 bond_miimon_commit(bond);
2143 2144
2144 read_unlock(&bond->lock);
2145 rtnl_unlock(); /* might sleep, hold no other locks */ 2145 rtnl_unlock(); /* might sleep, hold no other locks */
2146 read_lock(&bond->lock); 2146 } else
2147 } 2147 rcu_read_unlock();
2148 2148
2149re_arm: 2149re_arm:
2150 if (bond->params.miimon) 2150 if (bond->params.miimon)
2151 queue_delayed_work(bond->wq, &bond->mii_work, delay); 2151 queue_delayed_work(bond->wq, &bond->mii_work, delay);
2152 2152
2153 read_unlock(&bond->lock);
2154
2155 if (should_notify_peers) { 2153 if (should_notify_peers) {
2156 if (!rtnl_trylock()) 2154 if (!rtnl_trylock())
2157 return; 2155 return;