diff options
author | Veaceslav Falico <vfalico@redhat.com> | 2014-01-10 11:59:43 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-01-13 22:22:27 -0800 |
commit | c1bc9644ecd1f663f918d42b33b41a508683b0ee (patch) | |
tree | d020bd6c841fbd0f368618a3e88db5417d46e3bf | |
parent | 853dc21bfe15f545347b5c82aad02735d552110d (diff) | |
download | talos-obmc-linux-c1bc9644ecd1f663f918d42b33b41a508683b0ee.tar.gz talos-obmc-linux-c1bc9644ecd1f663f918d42b33b41a508683b0ee.zip |
bonding: fix bond_3ad_set_carrier() RCU usage
Currently, its usage is just plainly wrong. It first gets a slave under
RCU, and, after releasing the RCU lock, continues to use it - whilst it can
be freed.
Fix this by ensuring that bond_3ad_set_carrier() holds RCU till it uses its
slave (or its agg).
Fixes: be79bd048ab ("bonding: add RCU for bond_3ad_state_machine_handler()")
CC: dingtianhong@huawei.com
CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/bonding/bond_3ad.c | 22 |
1 files changed, 11 insertions, 11 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 29db1caee764..da0d7c54d352 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2327,32 +2327,32 @@ int bond_3ad_set_carrier(struct bonding *bond) { struct aggregator *active; struct slave *first_slave; + int ret = 1; rcu_read_lock(); first_slave = bond_first_slave_rcu(bond); - rcu_read_unlock(); - if (!first_slave) - return 0; + if (!first_slave) { + ret = 0; + goto out; + } active = __get_active_agg(&(SLAVE_AD_INFO(first_slave).aggregator)); if (active) { /* are enough slaves available to consider link up? */ if (active->num_of_ports < bond->params.min_links) { if (netif_carrier_ok(bond->dev)) { netif_carrier_off(bond->dev); - return 1; + goto out; } } else if (!netif_carrier_ok(bond->dev)) { netif_carrier_on(bond->dev); - return 1; + goto out; } - return 0; - } - - if (netif_carrier_ok(bond->dev)) { + } else if (netif_carrier_ok(bond->dev)) { netif_carrier_off(bond->dev); - return 1; } - return 0; +out: + rcu_read_unlock(); + return ret; } /** |