diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 57 |
1 files changed, 36 insertions, 21 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 27e6fddb2206..dd75615d85f2 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -2599,17 +2599,18 @@ do_failover: | |||
2599 | 2599 | ||
2600 | /* | 2600 | /* |
2601 | * Send ARP probes for active-backup mode ARP monitor. | 2601 | * Send ARP probes for active-backup mode ARP monitor. |
2602 | * | ||
2603 | * Called with rcu_read_lock hold. | ||
2604 | */ | 2602 | */ |
2605 | static void bond_ab_arp_probe(struct bonding *bond) | 2603 | static bool bond_ab_arp_probe(struct bonding *bond) |
2606 | { | 2604 | { |
2607 | struct slave *slave, *before = NULL, *new_slave = NULL, | 2605 | struct slave *slave, *before = NULL, *new_slave = NULL, |
2608 | *curr_arp_slave = rcu_dereference(bond->current_arp_slave), | 2606 | *curr_arp_slave, *curr_active_slave; |
2609 | *curr_active_slave = rcu_dereference(bond->curr_active_slave); | ||
2610 | struct list_head *iter; | 2607 | struct list_head *iter; |
2611 | bool found = false; | 2608 | bool found = false; |
2612 | 2609 | ||
2610 | rcu_read_lock(); | ||
2611 | curr_arp_slave = rcu_dereference(bond->current_arp_slave); | ||
2612 | curr_active_slave = rcu_dereference(bond->curr_active_slave); | ||
2613 | |||
2613 | if (curr_arp_slave && curr_active_slave) | 2614 | if (curr_arp_slave && curr_active_slave) |
2614 | pr_info("PROBE: c_arp %s && cas %s BAD\n", | 2615 | pr_info("PROBE: c_arp %s && cas %s BAD\n", |
2615 | curr_arp_slave->dev->name, | 2616 | curr_arp_slave->dev->name, |
@@ -2617,23 +2618,32 @@ static void bond_ab_arp_probe(struct bonding *bond) | |||
2617 | 2618 | ||
2618 | if (curr_active_slave) { | 2619 | if (curr_active_slave) { |
2619 | bond_arp_send_all(bond, curr_active_slave); | 2620 | bond_arp_send_all(bond, curr_active_slave); |
2620 | return; | 2621 | rcu_read_unlock(); |
2622 | return true; | ||
2621 | } | 2623 | } |
2624 | rcu_read_unlock(); | ||
2622 | 2625 | ||
2623 | /* if we don't have a curr_active_slave, search for the next available | 2626 | /* if we don't have a curr_active_slave, search for the next available |
2624 | * backup slave from the current_arp_slave and make it the candidate | 2627 | * backup slave from the current_arp_slave and make it the candidate |
2625 | * for becoming the curr_active_slave | 2628 | * for becoming the curr_active_slave |
2626 | */ | 2629 | */ |
2627 | 2630 | ||
2631 | if (!rtnl_trylock()) | ||
2632 | return false; | ||
2633 | /* curr_arp_slave might have gone away */ | ||
2634 | curr_arp_slave = ACCESS_ONCE(bond->current_arp_slave); | ||
2635 | |||
2628 | if (!curr_arp_slave) { | 2636 | if (!curr_arp_slave) { |
2629 | curr_arp_slave = bond_first_slave_rcu(bond); | 2637 | curr_arp_slave = bond_first_slave(bond); |
2630 | if (!curr_arp_slave) | 2638 | if (!curr_arp_slave) { |
2631 | return; | 2639 | rtnl_unlock(); |
2640 | return true; | ||
2641 | } | ||
2632 | } | 2642 | } |
2633 | 2643 | ||
2634 | bond_set_slave_inactive_flags(curr_arp_slave); | 2644 | bond_set_slave_inactive_flags(curr_arp_slave); |
2635 | 2645 | ||
2636 | bond_for_each_slave_rcu(bond, slave, iter) { | 2646 | bond_for_each_slave(bond, slave, iter) { |
2637 | if (!found && !before && IS_UP(slave->dev)) | 2647 | if (!found && !before && IS_UP(slave->dev)) |
2638 | before = slave; | 2648 | before = slave; |
2639 | 2649 | ||
@@ -2663,21 +2673,26 @@ static void bond_ab_arp_probe(struct bonding *bond) | |||
2663 | if (!new_slave && before) | 2673 | if (!new_slave && before) |
2664 | new_slave = before; | 2674 | new_slave = before; |
2665 | 2675 | ||
2666 | if (!new_slave) | 2676 | if (!new_slave) { |
2667 | return; | 2677 | rtnl_unlock(); |
2678 | return true; | ||
2679 | } | ||
2668 | 2680 | ||
2669 | new_slave->link = BOND_LINK_BACK; | 2681 | new_slave->link = BOND_LINK_BACK; |
2670 | bond_set_slave_active_flags(new_slave); | 2682 | bond_set_slave_active_flags(new_slave); |
2671 | bond_arp_send_all(bond, new_slave); | 2683 | bond_arp_send_all(bond, new_slave); |
2672 | new_slave->jiffies = jiffies; | 2684 | new_slave->jiffies = jiffies; |
2673 | rcu_assign_pointer(bond->current_arp_slave, new_slave); | 2685 | rcu_assign_pointer(bond->current_arp_slave, new_slave); |
2686 | rtnl_unlock(); | ||
2687 | |||
2688 | return true; | ||
2674 | } | 2689 | } |
2675 | 2690 | ||
2676 | static void bond_activebackup_arp_mon(struct work_struct *work) | 2691 | static void bond_activebackup_arp_mon(struct work_struct *work) |
2677 | { | 2692 | { |
2678 | struct bonding *bond = container_of(work, struct bonding, | 2693 | struct bonding *bond = container_of(work, struct bonding, |
2679 | arp_work.work); | 2694 | arp_work.work); |
2680 | bool should_notify_peers = false; | 2695 | bool should_notify_peers = false, should_commit = false; |
2681 | int delta_in_ticks; | 2696 | int delta_in_ticks; |
2682 | 2697 | ||
2683 | delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); | 2698 | delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); |
@@ -2686,12 +2701,11 @@ static void bond_activebackup_arp_mon(struct work_struct *work) | |||
2686 | goto re_arm; | 2701 | goto re_arm; |
2687 | 2702 | ||
2688 | rcu_read_lock(); | 2703 | rcu_read_lock(); |
2689 | |||
2690 | should_notify_peers = bond_should_notify_peers(bond); | 2704 | should_notify_peers = bond_should_notify_peers(bond); |
2705 | should_commit = bond_ab_arp_inspect(bond); | ||
2706 | rcu_read_unlock(); | ||
2691 | 2707 | ||
2692 | if (bond_ab_arp_inspect(bond)) { | 2708 | if (should_commit) { |
2693 | rcu_read_unlock(); | ||
2694 | |||
2695 | /* Race avoidance with bond_close flush of workqueue */ | 2709 | /* Race avoidance with bond_close flush of workqueue */ |
2696 | if (!rtnl_trylock()) { | 2710 | if (!rtnl_trylock()) { |
2697 | delta_in_ticks = 1; | 2711 | delta_in_ticks = 1; |
@@ -2700,13 +2714,14 @@ static void bond_activebackup_arp_mon(struct work_struct *work) | |||
2700 | } | 2714 | } |
2701 | 2715 | ||
2702 | bond_ab_arp_commit(bond); | 2716 | bond_ab_arp_commit(bond); |
2703 | |||
2704 | rtnl_unlock(); | 2717 | rtnl_unlock(); |
2705 | rcu_read_lock(); | ||
2706 | } | 2718 | } |
2707 | 2719 | ||
2708 | bond_ab_arp_probe(bond); | 2720 | if (!bond_ab_arp_probe(bond)) { |
2709 | rcu_read_unlock(); | 2721 | /* rtnl locking failed, re-arm */ |
2722 | delta_in_ticks = 1; | ||
2723 | should_notify_peers = false; | ||
2724 | } | ||
2710 | 2725 | ||
2711 | re_arm: | 2726 | re_arm: |
2712 | if (bond->params.arp_interval) | 2727 | if (bond->params.arp_interval) |