diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 25 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 1 |
2 files changed, 13 insertions, 13 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ed361d62d702..862ed8ece14e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4057,8 +4057,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev { struct bonding *bond = bond_dev->priv; struct slave *slave, *start_at; - int i; - int res = 1; + int i, slave_no, res = 1; read_lock(&bond->lock); @@ -4066,29 +4065,29 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev goto out; } - read_lock(&bond->curr_slave_lock); - slave = start_at = bond->curr_active_slave; - read_unlock(&bond->curr_slave_lock); + /* + * Concurrent TX may collide on rr_tx_counter; we accept that + * as being rare enough not to justify using an atomic op here + */ + slave_no = bond->rr_tx_counter++ % bond->slave_cnt; - if (!slave) { - goto out; + bond_for_each_slave(bond, slave, i) { + slave_no--; + if (slave_no < 0) { + break; + } } + start_at = slave; bond_for_each_slave_from(bond, slave, i, start_at) { if (IS_UP(slave->dev) && (slave->link == BOND_LINK_UP) && (slave->state == BOND_STATE_ACTIVE)) { res = bond_dev_queue_xmit(bond, skb, slave->dev); - - write_lock(&bond->curr_slave_lock); - bond->curr_active_slave = slave->next; - write_unlock(&bond->curr_slave_lock); - break; } } - out: if (res) { /* no suitable interface, frame not sent */ diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index a8f2384f550d..d1ed14bf1ccb 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -197,6 +197,7 @@ struct bonding { int (*xmit_hash_policy)(struct sk_buff *, struct net_device *, int); __be32 master_ip; u16 flags; + u16 rr_tx_counter; struct ad_bond_info ad_info; struct alb_bond_info alb_info; struct bond_params params; |