Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'bonding_rcu'

Veaceslav Falico says:

====================
bonding: fix bond_3ad RCU usage

While digging through bond_3ad.c I've found that the RCU usage there is
just wrong - it's used as a kind of mutex/spinlock instead of RCU.

v3->v4: remove useless goto and wrap __get_first_agg() in proper RCU.

v2->v3: make bond_3ad_set_carrier() use RCU read lock for the whole
function, so that all other functions will be protected by RCU as well.
This way we can use _rcu variants everywhere.

v1->v2: use generic primitives instead of _rcu ones cause we can hold RTNL
lock without RCU one, which is still safe.

This patchset is on top of bond_3ad.c cleanup:
http://www.spinics.net/lists/netdev/msg265447.html
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+19 -18
+19 -18
drivers/net/bonding/bond_3ad.c
··· 143 143 * 144 144 * Return the aggregator of the first slave in @bond, or %NULL if it can't be 145 145 * found. 146 + * The caller must hold RCU or RTNL lock. 146 147 */ 147 148 static inline struct aggregator *__get_first_agg(struct port *port) 148 149 { 149 150 struct bonding *bond = __get_bond_by_port(port); 150 151 struct slave *first_slave; 152 + struct aggregator *agg; 151 153 152 154 /* If there's no bond for this port, or bond has no slaves */ 153 155 if (bond == NULL) ··· 157 155 158 156 rcu_read_lock(); 159 157 first_slave = bond_first_slave_rcu(bond); 158 + agg = first_slave ? &(SLAVE_AD_INFO(first_slave).aggregator) : NULL; 160 159 rcu_read_unlock(); 161 160 162 - return first_slave ? &(SLAVE_AD_INFO(first_slave).aggregator) : NULL; 161 + return agg; 163 162 } 164 163 165 164 /** ··· 678 675 /** 679 676 * __get_active_agg - get the current active aggregator 680 677 * @aggregator: the aggregator we're looking at 678 + * 679 + * Caller must hold RCU lock. 681 680 */ 682 681 static struct aggregator *__get_active_agg(struct aggregator *aggregator) 683 682 { ··· 687 682 struct list_head *iter; 688 683 struct slave *slave; 689 684 690 - rcu_read_lock(); 691 685 bond_for_each_slave_rcu(bond, slave, iter) 692 - if (SLAVE_AD_INFO(slave).aggregator.is_active) { 693 - rcu_read_unlock(); 686 + if (SLAVE_AD_INFO(slave).aggregator.is_active) 694 687 return &(SLAVE_AD_INFO(slave).aggregator); 695 - } 696 - rcu_read_unlock(); 697 688 698 689 return NULL; 699 690 } ··· 1497 1496 struct slave *slave; 1498 1497 struct port *port; 1499 1498 1499 + rcu_read_lock(); 1500 1500 origin = agg; 1501 1501 active = __get_active_agg(agg); 1502 1502 best = (active && agg_device_up(active)) ? active : NULL; 1503 1503 1504 - rcu_read_lock(); 1505 1504 bond_for_each_slave_rcu(bond, slave, iter) { 1506 1505 agg = &(SLAVE_AD_INFO(slave).aggregator); 1507 1506 ··· 2328 2327 { 2329 2328 struct aggregator *active; 2330 2329 struct slave *first_slave; 2330 + int ret = 1; 2331 2331 2332 2332 rcu_read_lock(); 2333 2333 first_slave = bond_first_slave_rcu(bond); 2334 - rcu_read_unlock(); 2335 - if (!first_slave) 2336 - return 0; 2334 + if (!first_slave) { 2335 + ret = 0; 2336 + goto out; 2337 + } 2337 2338 active = __get_active_agg(&(SLAVE_AD_INFO(first_slave).aggregator)); 2338 2339 if (active) { 2339 2340 /* are enough slaves available to consider link up? */ 2340 2341 if (active->num_of_ports < bond->params.min_links) { 2341 2342 if (netif_carrier_ok(bond->dev)) { 2342 2343 netif_carrier_off(bond->dev); 2343 - return 1; 2344 + goto out; 2344 2345 } 2345 2346 } else if (!netif_carrier_ok(bond->dev)) { 2346 2347 netif_carrier_on(bond->dev); 2347 - return 1; 2348 + goto out; 2348 2349 } 2349 - return 0; 2350 - } 2351 - 2352 - if (netif_carrier_ok(bond->dev)) { 2350 + } else if (netif_carrier_ok(bond->dev)) { 2353 2351 netif_carrier_off(bond->dev); 2354 - return 1; 2355 2352 } 2356 - return 0; 2353 + out: 2354 + rcu_read_unlock(); 2355 + return ret; 2357 2356 } 2358 2357 2359 2358 /**