aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bonding/bond_3ad.c
diff options
context:
space:
mode:
authordingtianhong <dingtianhong@huawei.com>2013-12-12 21:20:12 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-14 01:58:02 -0500
commitbe79bd048abe9fb6aee049ea903d1e70b44d6480 (patch)
tree870e169f08b09ea475e4883f38740420bebf4e1a /drivers/net/bonding/bond_3ad.c
parentc8517035445834350b8d498723b68f4e81286110 (diff)
bonding: add RCU for bond_3ad_state_machine_handler()
The bond_3ad_state_machine_handler() use the bond lock to protect the bond slave list and slave port together, but it is not enough, the bond slave list was link and unlink in RTNL, not bond lock, so I add RCU to protect the slave list from leaving. The bond lock is still used here, because when the slave has been removed from the list by the time the state machine runs, it appears to be possible for both function to manupulate the same aggregator->lag_ports by finding the aggregator via two different ports that are both members of that aggregator (i.e., port A of the agg is being unbound, and port B of the agg is runing its state machine). If I remove the bond lock, there are nothing to mutex changes to aggregator->lag_ports between bond_3ad_state_machine_handler and bond_3ad_unbind_slave, So the bond lock is the simplest way to protect aggregator->lag_ports. There was a lot of function need RCU protect, I have two choice to make the function in RCU-safe, (1) create new similar functions and make the bond slave list in RCU. (2) modify the existed functions and make them in read-side critical section, because the RCU read-side critical sections may be nested. I choose (2) because it is no need to create more similar functions. The nots in the function is still too old, clean up the nots. Suggested-by: Nikolay Aleksandrov <nikolay@redhat.com> 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/bond_3ad.c')
-rw-r--r--drivers/net/bonding/bond_3ad.c54
1 files changed, 33 insertions, 21 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 187b1b7772ef..58c2249a3324 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -147,11 +147,12 @@ static inline struct aggregator *__get_first_agg(struct port *port)
147 struct bonding *bond = __get_bond_by_port(port); 147 struct bonding *bond = __get_bond_by_port(port);
148 struct slave *first_slave; 148 struct slave *first_slave;
149 149
150 // If there's no bond for this port, or bond has no slaves 150 /* If there's no bond for this port, or bond has no slaves */
151 if (bond == NULL) 151 if (bond == NULL)
152 return NULL; 152 return NULL;
153 first_slave = bond_first_slave(bond); 153 rcu_read_lock();
154 154 first_slave = bond_first_slave_rcu(bond);
155 rcu_read_unlock();
155 return first_slave ? &(SLAVE_AD_INFO(first_slave).aggregator) : NULL; 156 return first_slave ? &(SLAVE_AD_INFO(first_slave).aggregator) : NULL;
156} 157}
157 158
@@ -702,9 +703,13 @@ static struct aggregator *__get_active_agg(struct aggregator *aggregator)
702 struct list_head *iter; 703 struct list_head *iter;
703 struct slave *slave; 704 struct slave *slave;
704 705
705 bond_for_each_slave(bond, slave, iter) 706 rcu_read_lock();
706 if (SLAVE_AD_INFO(slave).aggregator.is_active) 707 bond_for_each_slave_rcu(bond, slave, iter)
708 if (SLAVE_AD_INFO(slave).aggregator.is_active) {
709 rcu_read_unlock();
707 return &(SLAVE_AD_INFO(slave).aggregator); 710 return &(SLAVE_AD_INFO(slave).aggregator);
711 }
712 rcu_read_unlock();
708 713
709 return NULL; 714 return NULL;
710} 715}
@@ -1471,7 +1476,8 @@ static void ad_agg_selection_logic(struct aggregator *agg)
1471 active = __get_active_agg(agg); 1476 active = __get_active_agg(agg);
1472 best = (active && agg_device_up(active)) ? active : NULL; 1477 best = (active && agg_device_up(active)) ? active : NULL;
1473 1478
1474 bond_for_each_slave(bond, slave, iter) { 1479 rcu_read_lock();
1480 bond_for_each_slave_rcu(bond, slave, iter) {
1475 agg = &(SLAVE_AD_INFO(slave).aggregator); 1481 agg = &(SLAVE_AD_INFO(slave).aggregator);
1476 1482
1477 agg->is_active = 0; 1483 agg->is_active = 0;
@@ -1505,7 +1511,7 @@ static void ad_agg_selection_logic(struct aggregator *agg)
1505 active->is_active = 1; 1511 active->is_active = 1;
1506 } 1512 }
1507 1513
1508 // if there is new best aggregator, activate it 1514 /* if there is new best aggregator, activate it */
1509 if (best) { 1515 if (best) {
1510 pr_debug("best Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", 1516 pr_debug("best Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
1511 best->aggregator_identifier, best->num_of_ports, 1517 best->aggregator_identifier, best->num_of_ports,
@@ -1516,7 +1522,7 @@ static void ad_agg_selection_logic(struct aggregator *agg)
1516 best->lag_ports, best->slave, 1522 best->lag_ports, best->slave,
1517 best->slave ? best->slave->dev->name : "NULL"); 1523 best->slave ? best->slave->dev->name : "NULL");
1518 1524
1519 bond_for_each_slave(bond, slave, iter) { 1525 bond_for_each_slave_rcu(bond, slave, iter) {
1520 agg = &(SLAVE_AD_INFO(slave).aggregator); 1526 agg = &(SLAVE_AD_INFO(slave).aggregator);
1521 1527
1522 pr_debug("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", 1528 pr_debug("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
@@ -1526,10 +1532,11 @@ static void ad_agg_selection_logic(struct aggregator *agg)
1526 agg->is_individual, agg->is_active); 1532 agg->is_individual, agg->is_active);
1527 } 1533 }
1528 1534
1529 // check if any partner replys 1535 /* check if any partner replys */
1530 if (best->is_individual) { 1536 if (best->is_individual) {
1531 pr_warning("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n", 1537 pr_warning("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
1532 best->slave ? best->slave->bond->dev->name : "NULL"); 1538 best->slave ?
1539 best->slave->bond->dev->name : "NULL");
1533 } 1540 }
1534 1541
1535 best->is_active = 1; 1542 best->is_active = 1;
@@ -1541,7 +1548,7 @@ static void ad_agg_selection_logic(struct aggregator *agg)
1541 best->partner_oper_aggregator_key, 1548 best->partner_oper_aggregator_key,
1542 best->is_individual, best->is_active); 1549 best->is_individual, best->is_active);
1543 1550
1544 // disable the ports that were related to the former active_aggregator 1551 /* disable the ports that were related to the former active_aggregator */
1545 if (active) { 1552 if (active) {
1546 for (port = active->lag_ports; port; 1553 for (port = active->lag_ports; port;
1547 port = port->next_port_in_aggregator) { 1554 port = port->next_port_in_aggregator) {
@@ -1565,6 +1572,8 @@ static void ad_agg_selection_logic(struct aggregator *agg)
1565 } 1572 }
1566 } 1573 }
1567 1574
1575 rcu_read_unlock();
1576
1568 bond_3ad_set_carrier(bond); 1577 bond_3ad_set_carrier(bond);
1569} 1578}
1570 1579
@@ -2069,17 +2078,18 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
2069 struct port *port; 2078 struct port *port;
2070 2079
2071 read_lock(&bond->lock); 2080 read_lock(&bond->lock);
2081 rcu_read_lock();
2072 2082
2073 //check if there are any slaves 2083 /* check if there are any slaves */
2074 if (!bond_has_slaves(bond)) 2084 if (!bond_has_slaves(bond))
2075 goto re_arm; 2085 goto re_arm;
2076 2086
2077 // check if agg_select_timer timer after initialize is timed out 2087 /* check if agg_select_timer timer after initialize is timed out */
2078 if (BOND_AD_INFO(bond).agg_select_timer && !(--BOND_AD_INFO(bond).agg_select_timer)) { 2088 if (BOND_AD_INFO(bond).agg_select_timer && !(--BOND_AD_INFO(bond).agg_select_timer)) {
2079 slave = bond_first_slave(bond); 2089 slave = bond_first_slave_rcu(bond);
2080 port = slave ? &(SLAVE_AD_INFO(slave).port) : NULL; 2090 port = slave ? &(SLAVE_AD_INFO(slave).port) : NULL;
2081 2091
2082 // select the active aggregator for the bond 2092 /* select the active aggregator for the bond */
2083 if (port) { 2093 if (port) {
2084 if (!port->slave) { 2094 if (!port->slave) {
2085 pr_warning("%s: Warning: bond's first port is uninitialized\n", 2095 pr_warning("%s: Warning: bond's first port is uninitialized\n",
@@ -2093,8 +2103,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
2093 bond_3ad_set_carrier(bond); 2103 bond_3ad_set_carrier(bond);
2094 } 2104 }
2095 2105
2096 // for each port run the state machines 2106 /* for each port run the state machines */
2097 bond_for_each_slave(bond, slave, iter) { 2107 bond_for_each_slave_rcu(bond, slave, iter) {
2098 port = &(SLAVE_AD_INFO(slave).port); 2108 port = &(SLAVE_AD_INFO(slave).port);
2099 if (!port->slave) { 2109 if (!port->slave) {
2100 pr_warning("%s: Warning: Found an uninitialized port\n", 2110 pr_warning("%s: Warning: Found an uninitialized port\n",
@@ -2114,7 +2124,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
2114 ad_mux_machine(port); 2124 ad_mux_machine(port);
2115 ad_tx_machine(port); 2125 ad_tx_machine(port);
2116 2126
2117 // turn off the BEGIN bit, since we already handled it 2127 /* turn off the BEGIN bit, since we already handled it */
2118 if (port->sm_vars & AD_PORT_BEGIN) 2128 if (port->sm_vars & AD_PORT_BEGIN)
2119 port->sm_vars &= ~AD_PORT_BEGIN; 2129 port->sm_vars &= ~AD_PORT_BEGIN;
2120 2130
@@ -2122,9 +2132,9 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
2122 } 2132 }
2123 2133
2124re_arm: 2134re_arm:
2125 queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks); 2135 rcu_read_unlock();
2126
2127 read_unlock(&bond->lock); 2136 read_unlock(&bond->lock);
2137 queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
2128} 2138}
2129 2139
2130/** 2140/**
@@ -2303,7 +2313,9 @@ int bond_3ad_set_carrier(struct bonding *bond)
2303 struct aggregator *active; 2313 struct aggregator *active;
2304 struct slave *first_slave; 2314 struct slave *first_slave;
2305 2315
2306 first_slave = bond_first_slave(bond); 2316 rcu_read_lock();
2317 first_slave = bond_first_slave_rcu(bond);
2318 rcu_read_unlock();
2307 if (!first_slave) 2319 if (!first_slave)
2308 return 0; 2320 return 0;
2309 active = __get_active_agg(&(SLAVE_AD_INFO(first_slave).aggregator)); 2321 active = __get_active_agg(&(SLAVE_AD_INFO(first_slave).aggregator));