diff options
-rw-r--r-- | drivers/net/bonding/bond_3ad.c | 10 | ||||
-rw-r--r-- | drivers/net/bonding/bond_alb.c | 58 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 30 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 14 |
4 files changed, 78 insertions, 34 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index ea3e64e22e22..187b1b7772ef 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c | |||
@@ -2344,7 +2344,7 @@ int __bond_3ad_get_active_agg_info(struct bonding *bond, | |||
2344 | struct slave *slave; | 2344 | struct slave *slave; |
2345 | struct port *port; | 2345 | struct port *port; |
2346 | 2346 | ||
2347 | bond_for_each_slave(bond, slave, iter) { | 2347 | bond_for_each_slave_rcu(bond, slave, iter) { |
2348 | port = &(SLAVE_AD_INFO(slave).port); | 2348 | port = &(SLAVE_AD_INFO(slave).port); |
2349 | if (port->aggregator && port->aggregator->is_active) { | 2349 | if (port->aggregator && port->aggregator->is_active) { |
2350 | aggregator = port->aggregator; | 2350 | aggregator = port->aggregator; |
@@ -2369,9 +2369,9 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info) | |||
2369 | { | 2369 | { |
2370 | int ret; | 2370 | int ret; |
2371 | 2371 | ||
2372 | read_lock(&bond->lock); | 2372 | rcu_read_lock(); |
2373 | ret = __bond_3ad_get_active_agg_info(bond, ad_info); | 2373 | ret = __bond_3ad_get_active_agg_info(bond, ad_info); |
2374 | read_unlock(&bond->lock); | 2374 | rcu_read_unlock(); |
2375 | 2375 | ||
2376 | return ret; | 2376 | return ret; |
2377 | } | 2377 | } |
@@ -2388,7 +2388,6 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) | |||
2388 | int res = 1; | 2388 | int res = 1; |
2389 | int agg_id; | 2389 | int agg_id; |
2390 | 2390 | ||
2391 | read_lock(&bond->lock); | ||
2392 | if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { | 2391 | if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { |
2393 | pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n", | 2392 | pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n", |
2394 | dev->name); | 2393 | dev->name); |
@@ -2406,7 +2405,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) | |||
2406 | slave_agg_no = bond_xmit_hash(bond, skb, slaves_in_agg); | 2405 | slave_agg_no = bond_xmit_hash(bond, skb, slaves_in_agg); |
2407 | first_ok_slave = NULL; | 2406 | first_ok_slave = NULL; |
2408 | 2407 | ||
2409 | bond_for_each_slave(bond, slave, iter) { | 2408 | bond_for_each_slave_rcu(bond, slave, iter) { |
2410 | agg = SLAVE_AD_INFO(slave).port.aggregator; | 2409 | agg = SLAVE_AD_INFO(slave).port.aggregator; |
2411 | if (!agg || agg->aggregator_identifier != agg_id) | 2410 | if (!agg || agg->aggregator_identifier != agg_id) |
2412 | continue; | 2411 | continue; |
@@ -2436,7 +2435,6 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) | |||
2436 | res = bond_dev_queue_xmit(bond, skb, first_ok_slave->dev); | 2435 | res = bond_dev_queue_xmit(bond, skb, first_ok_slave->dev); |
2437 | 2436 | ||
2438 | out: | 2437 | out: |
2439 | read_unlock(&bond->lock); | ||
2440 | if (res) { | 2438 | if (res) { |
2441 | /* no suitable interface, frame not sent */ | 2439 | /* no suitable interface, frame not sent */ |
2442 | kfree_skb(skb); | 2440 | kfree_skb(skb); |
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 576cceae026a..02872405d35d 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c | |||
@@ -230,7 +230,7 @@ static struct slave *tlb_get_least_loaded_slave(struct bonding *bond) | |||
230 | max_gap = LLONG_MIN; | 230 | max_gap = LLONG_MIN; |
231 | 231 | ||
232 | /* Find the slave with the largest gap */ | 232 | /* Find the slave with the largest gap */ |
233 | bond_for_each_slave(bond, slave, iter) { | 233 | bond_for_each_slave_rcu(bond, slave, iter) { |
234 | if (SLAVE_IS_OK(slave)) { | 234 | if (SLAVE_IS_OK(slave)) { |
235 | long long gap = compute_gap(slave); | 235 | long long gap = compute_gap(slave); |
236 | 236 | ||
@@ -412,6 +412,39 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond) | |||
412 | return rx_slave; | 412 | return rx_slave; |
413 | } | 413 | } |
414 | 414 | ||
415 | /* Caller must hold rcu_read_lock() for read */ | ||
416 | static struct slave *__rlb_next_rx_slave(struct bonding *bond) | ||
417 | { | ||
418 | struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); | ||
419 | struct slave *before = NULL, *rx_slave = NULL, *slave; | ||
420 | struct list_head *iter; | ||
421 | bool found = false; | ||
422 | |||
423 | bond_for_each_slave_rcu(bond, slave, iter) { | ||
424 | if (!SLAVE_IS_OK(slave)) | ||
425 | continue; | ||
426 | if (!found) { | ||
427 | if (!before || before->speed < slave->speed) | ||
428 | before = slave; | ||
429 | } else { | ||
430 | if (!rx_slave || rx_slave->speed < slave->speed) | ||
431 | rx_slave = slave; | ||
432 | } | ||
433 | if (slave == bond_info->rx_slave) | ||
434 | found = true; | ||
435 | } | ||
436 | /* we didn't find anything after the current or we have something | ||
437 | * better before and up to the current slave | ||
438 | */ | ||
439 | if (!rx_slave || (before && rx_slave->speed < before->speed)) | ||
440 | rx_slave = before; | ||
441 | |||
442 | if (rx_slave) | ||
443 | bond_info->rx_slave = rx_slave; | ||
444 | |||
445 | return rx_slave; | ||
446 | } | ||
447 | |||
415 | /* teach the switch the mac of a disabled slave | 448 | /* teach the switch the mac of a disabled slave |
416 | * on the primary for fault tolerance | 449 | * on the primary for fault tolerance |
417 | * | 450 | * |
@@ -628,12 +661,14 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon | |||
628 | { | 661 | { |
629 | struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); | 662 | struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); |
630 | struct arp_pkt *arp = arp_pkt(skb); | 663 | struct arp_pkt *arp = arp_pkt(skb); |
631 | struct slave *assigned_slave; | 664 | struct slave *assigned_slave, *curr_active_slave; |
632 | struct rlb_client_info *client_info; | 665 | struct rlb_client_info *client_info; |
633 | u32 hash_index = 0; | 666 | u32 hash_index = 0; |
634 | 667 | ||
635 | _lock_rx_hashtbl(bond); | 668 | _lock_rx_hashtbl(bond); |
636 | 669 | ||
670 | curr_active_slave = rcu_dereference(bond->curr_active_slave); | ||
671 | |||
637 | hash_index = _simple_hash((u8 *)&arp->ip_dst, sizeof(arp->ip_dst)); | 672 | hash_index = _simple_hash((u8 *)&arp->ip_dst, sizeof(arp->ip_dst)); |
638 | client_info = &(bond_info->rx_hashtbl[hash_index]); | 673 | client_info = &(bond_info->rx_hashtbl[hash_index]); |
639 | 674 | ||
@@ -658,14 +693,14 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon | |||
658 | * that the new client can be assigned to this entry. | 693 | * that the new client can be assigned to this entry. |
659 | */ | 694 | */ |
660 | if (bond->curr_active_slave && | 695 | if (bond->curr_active_slave && |
661 | client_info->slave != bond->curr_active_slave) { | 696 | client_info->slave != curr_active_slave) { |
662 | client_info->slave = bond->curr_active_slave; | 697 | client_info->slave = curr_active_slave; |
663 | rlb_update_client(client_info); | 698 | rlb_update_client(client_info); |
664 | } | 699 | } |
665 | } | 700 | } |
666 | } | 701 | } |
667 | /* assign a new slave */ | 702 | /* assign a new slave */ |
668 | assigned_slave = rlb_next_rx_slave(bond); | 703 | assigned_slave = __rlb_next_rx_slave(bond); |
669 | 704 | ||
670 | if (assigned_slave) { | 705 | if (assigned_slave) { |
671 | if (!(client_info->assigned && | 706 | if (!(client_info->assigned && |
@@ -728,7 +763,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) | |||
728 | /* Don't modify or load balance ARPs that do not originate locally | 763 | /* Don't modify or load balance ARPs that do not originate locally |
729 | * (e.g.,arrive via a bridge). | 764 | * (e.g.,arrive via a bridge). |
730 | */ | 765 | */ |
731 | if (!bond_slave_has_mac(bond, arp->mac_src)) | 766 | if (!bond_slave_has_mac_rcu(bond, arp->mac_src)) |
732 | return NULL; | 767 | return NULL; |
733 | 768 | ||
734 | if (arp->op_code == htons(ARPOP_REPLY)) { | 769 | if (arp->op_code == htons(ARPOP_REPLY)) { |
@@ -1343,11 +1378,6 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) | |||
1343 | skb_reset_mac_header(skb); | 1378 | skb_reset_mac_header(skb); |
1344 | eth_data = eth_hdr(skb); | 1379 | eth_data = eth_hdr(skb); |
1345 | 1380 | ||
1346 | /* make sure that the curr_active_slave do not change during tx | ||
1347 | */ | ||
1348 | read_lock(&bond->lock); | ||
1349 | read_lock(&bond->curr_slave_lock); | ||
1350 | |||
1351 | switch (ntohs(skb->protocol)) { | 1381 | switch (ntohs(skb->protocol)) { |
1352 | case ETH_P_IP: { | 1382 | case ETH_P_IP: { |
1353 | const struct iphdr *iph = ip_hdr(skb); | 1383 | const struct iphdr *iph = ip_hdr(skb); |
@@ -1429,12 +1459,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) | |||
1429 | 1459 | ||
1430 | if (!tx_slave) { | 1460 | if (!tx_slave) { |
1431 | /* unbalanced or unassigned, send through primary */ | 1461 | /* unbalanced or unassigned, send through primary */ |
1432 | tx_slave = bond->curr_active_slave; | 1462 | tx_slave = rcu_dereference(bond->curr_active_slave); |
1433 | bond_info->unbalanced_load += skb->len; | 1463 | bond_info->unbalanced_load += skb->len; |
1434 | } | 1464 | } |
1435 | 1465 | ||
1436 | if (tx_slave && SLAVE_IS_OK(tx_slave)) { | 1466 | if (tx_slave && SLAVE_IS_OK(tx_slave)) { |
1437 | if (tx_slave != bond->curr_active_slave) { | 1467 | if (tx_slave != rcu_dereference(bond->curr_active_slave)) { |
1438 | memcpy(eth_data->h_source, | 1468 | memcpy(eth_data->h_source, |
1439 | tx_slave->dev->dev_addr, | 1469 | tx_slave->dev->dev_addr, |
1440 | ETH_ALEN); | 1470 | ETH_ALEN); |
@@ -1449,8 +1479,6 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) | |||
1449 | } | 1479 | } |
1450 | } | 1480 | } |
1451 | 1481 | ||
1452 | read_unlock(&bond->curr_slave_lock); | ||
1453 | read_unlock(&bond->lock); | ||
1454 | if (res) { | 1482 | if (res) { |
1455 | /* no suitable interface, frame not sent */ | 1483 | /* no suitable interface, frame not sent */ |
1456 | kfree_skb(skb); | 1484 | kfree_skb(skb); |
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index e9249527e7e7..03bed0ca935e 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c | |||
@@ -179,7 +179,9 @@ static ssize_t bonding_show_slaves(struct device *d, | |||
179 | struct slave *slave; | 179 | struct slave *slave; |
180 | int res = 0; | 180 | int res = 0; |
181 | 181 | ||
182 | read_lock(&bond->lock); | 182 | if (!rtnl_trylock()) |
183 | return restart_syscall(); | ||
184 | |||
183 | bond_for_each_slave(bond, slave, iter) { | 185 | bond_for_each_slave(bond, slave, iter) { |
184 | if (res > (PAGE_SIZE - IFNAMSIZ)) { | 186 | if (res > (PAGE_SIZE - IFNAMSIZ)) { |
185 | /* not enough space for another interface name */ | 187 | /* not enough space for another interface name */ |
@@ -190,7 +192,9 @@ static ssize_t bonding_show_slaves(struct device *d, | |||
190 | } | 192 | } |
191 | res += sprintf(buf + res, "%s ", slave->dev->name); | 193 | res += sprintf(buf + res, "%s ", slave->dev->name); |
192 | } | 194 | } |
193 | read_unlock(&bond->lock); | 195 | |
196 | rtnl_unlock(); | ||
197 | |||
194 | if (res) | 198 | if (res) |
195 | buf[res-1] = '\n'; /* eat the leftover space */ | 199 | buf[res-1] = '\n'; /* eat the leftover space */ |
196 | 200 | ||
@@ -626,6 +630,9 @@ static ssize_t bonding_store_arp_targets(struct device *d, | |||
626 | unsigned long *targets_rx; | 630 | unsigned long *targets_rx; |
627 | int ind, i, j, ret = -EINVAL; | 631 | int ind, i, j, ret = -EINVAL; |
628 | 632 | ||
633 | if (!rtnl_trylock()) | ||
634 | return restart_syscall(); | ||
635 | |||
629 | targets = bond->params.arp_targets; | 636 | targets = bond->params.arp_targets; |
630 | newtarget = in_aton(buf + 1); | 637 | newtarget = in_aton(buf + 1); |
631 | /* look for adds */ | 638 | /* look for adds */ |
@@ -699,6 +706,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, | |||
699 | 706 | ||
700 | ret = count; | 707 | ret = count; |
701 | out: | 708 | out: |
709 | rtnl_unlock(); | ||
702 | return ret; | 710 | return ret; |
703 | } | 711 | } |
704 | static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); | 712 | static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); |
@@ -1467,7 +1475,6 @@ static ssize_t bonding_show_queue_id(struct device *d, | |||
1467 | if (!rtnl_trylock()) | 1475 | if (!rtnl_trylock()) |
1468 | return restart_syscall(); | 1476 | return restart_syscall(); |
1469 | 1477 | ||
1470 | read_lock(&bond->lock); | ||
1471 | bond_for_each_slave(bond, slave, iter) { | 1478 | bond_for_each_slave(bond, slave, iter) { |
1472 | if (res > (PAGE_SIZE - IFNAMSIZ - 6)) { | 1479 | if (res > (PAGE_SIZE - IFNAMSIZ - 6)) { |
1473 | /* not enough space for another interface_name:queue_id pair */ | 1480 | /* not enough space for another interface_name:queue_id pair */ |
@@ -1479,9 +1486,9 @@ static ssize_t bonding_show_queue_id(struct device *d, | |||
1479 | res += sprintf(buf + res, "%s:%d ", | 1486 | res += sprintf(buf + res, "%s:%d ", |
1480 | slave->dev->name, slave->queue_id); | 1487 | slave->dev->name, slave->queue_id); |
1481 | } | 1488 | } |
1482 | read_unlock(&bond->lock); | ||
1483 | if (res) | 1489 | if (res) |
1484 | buf[res-1] = '\n'; /* eat the leftover space */ | 1490 | buf[res-1] = '\n'; /* eat the leftover space */ |
1491 | |||
1485 | rtnl_unlock(); | 1492 | rtnl_unlock(); |
1486 | 1493 | ||
1487 | return res; | 1494 | return res; |
@@ -1530,8 +1537,6 @@ static ssize_t bonding_store_queue_id(struct device *d, | |||
1530 | if (!sdev) | 1537 | if (!sdev) |
1531 | goto err_no_cmd; | 1538 | goto err_no_cmd; |
1532 | 1539 | ||
1533 | read_lock(&bond->lock); | ||
1534 | |||
1535 | /* Search for thes slave and check for duplicate qids */ | 1540 | /* Search for thes slave and check for duplicate qids */ |
1536 | update_slave = NULL; | 1541 | update_slave = NULL; |
1537 | bond_for_each_slave(bond, slave, iter) { | 1542 | bond_for_each_slave(bond, slave, iter) { |
@@ -1542,23 +1547,20 @@ static ssize_t bonding_store_queue_id(struct device *d, | |||
1542 | */ | 1547 | */ |
1543 | update_slave = slave; | 1548 | update_slave = slave; |
1544 | else if (qid && qid == slave->queue_id) { | 1549 | else if (qid && qid == slave->queue_id) { |
1545 | goto err_no_cmd_unlock; | 1550 | goto err_no_cmd; |
1546 | } | 1551 | } |
1547 | } | 1552 | } |
1548 | 1553 | ||
1549 | if (!update_slave) | 1554 | if (!update_slave) |
1550 | goto err_no_cmd_unlock; | 1555 | goto err_no_cmd; |
1551 | 1556 | ||
1552 | /* Actually set the qids for the slave */ | 1557 | /* Actually set the qids for the slave */ |
1553 | update_slave->queue_id = qid; | 1558 | update_slave->queue_id = qid; |
1554 | 1559 | ||
1555 | read_unlock(&bond->lock); | ||
1556 | out: | 1560 | out: |
1557 | rtnl_unlock(); | 1561 | rtnl_unlock(); |
1558 | return ret; | 1562 | return ret; |
1559 | 1563 | ||
1560 | err_no_cmd_unlock: | ||
1561 | read_unlock(&bond->lock); | ||
1562 | err_no_cmd: | 1564 | err_no_cmd: |
1563 | pr_info("invalid input for queue_id set for %s.\n", | 1565 | pr_info("invalid input for queue_id set for %s.\n", |
1564 | bond->dev->name); | 1566 | bond->dev->name); |
@@ -1591,6 +1593,9 @@ static ssize_t bonding_store_slaves_active(struct device *d, | |||
1591 | struct list_head *iter; | 1593 | struct list_head *iter; |
1592 | struct slave *slave; | 1594 | struct slave *slave; |
1593 | 1595 | ||
1596 | if (!rtnl_trylock()) | ||
1597 | return restart_syscall(); | ||
1598 | |||
1594 | if (sscanf(buf, "%d", &new_value) != 1) { | 1599 | if (sscanf(buf, "%d", &new_value) != 1) { |
1595 | pr_err("%s: no all_slaves_active value specified.\n", | 1600 | pr_err("%s: no all_slaves_active value specified.\n", |
1596 | bond->dev->name); | 1601 | bond->dev->name); |
@@ -1610,7 +1615,6 @@ static ssize_t bonding_store_slaves_active(struct device *d, | |||
1610 | goto out; | 1615 | goto out; |
1611 | } | 1616 | } |
1612 | 1617 | ||
1613 | read_lock(&bond->lock); | ||
1614 | bond_for_each_slave(bond, slave, iter) { | 1618 | bond_for_each_slave(bond, slave, iter) { |
1615 | if (!bond_is_active_slave(slave)) { | 1619 | if (!bond_is_active_slave(slave)) { |
1616 | if (new_value) | 1620 | if (new_value) |
@@ -1619,8 +1623,8 @@ static ssize_t bonding_store_slaves_active(struct device *d, | |||
1619 | slave->inactive = 1; | 1623 | slave->inactive = 1; |
1620 | } | 1624 | } |
1621 | } | 1625 | } |
1622 | read_unlock(&bond->lock); | ||
1623 | out: | 1626 | out: |
1627 | rtnl_unlock(); | ||
1624 | return ret; | 1628 | return ret; |
1625 | } | 1629 | } |
1626 | static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR, | 1630 | static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR, |
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 0bd04fbda8e9..bb5c731e2560 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h | |||
@@ -464,6 +464,20 @@ static inline struct slave *bond_slave_has_mac(struct bonding *bond, | |||
464 | return NULL; | 464 | return NULL; |
465 | } | 465 | } |
466 | 466 | ||
467 | /* Caller must hold rcu_read_lock() for read */ | ||
468 | static inline struct slave *bond_slave_has_mac_rcu(struct bonding *bond, | ||
469 | const u8 *mac) | ||
470 | { | ||
471 | struct list_head *iter; | ||
472 | struct slave *tmp; | ||
473 | |||
474 | bond_for_each_slave_rcu(bond, tmp, iter) | ||
475 | if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr)) | ||
476 | return tmp; | ||
477 | |||
478 | return NULL; | ||
479 | } | ||
480 | |||
467 | /* Check if the ip is present in arp ip list, or first free slot if ip == 0 | 481 | /* Check if the ip is present in arp ip list, or first free slot if ip == 0 |
468 | * Returns -1 if not found, index if found | 482 | * Returns -1 if not found, index if found |
469 | */ | 483 | */ |