diff options
author | David S. Miller <davem@davemloft.net> | 2014-01-27 16:12:50 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-01-27 16:12:50 -0500 |
commit | 66dd1c077a3f3c130d1b3f0abad364f56a3ed493 (patch) | |
tree | 097d2f21d367ae28eaa40fc5d1ee9519f8932687 | |
parent | bb9fbe2ddd6d6111c5fe5987fa1e71da7d2ab854 (diff) | |
parent | f2ebd477f141bc09b10fb8deb612a4d9b8999bba (diff) |
Merge branch 'bonding'
Veaceslav Falico says:
====================
bonding: fix locking in bond_ab_arp_prob
After the latest patches, on every call of bond_ab_arp_probe() without an
active slave I see the following warning:
[ 7.912314] RTNL: assertion failed at net/core/dev.c (4494)
...
[ 7.922495] [<ffffffff817acc6f>] dump_stack+0x51/0x72
[ 7.923714] [<ffffffff8168795e>] netdev_master_upper_dev_get+0x6e/0x70
[ 7.924940] [<ffffffff816a2a66>] rtnl_link_fill+0x116/0x260
[ 7.926143] [<ffffffff817acc6f>] ? dump_stack+0x51/0x72
[ 7.927333] [<ffffffff816a350c>] rtnl_fill_ifinfo+0x95c/0xb90
[ 7.928529] [<ffffffff8167af2b>] ? __kmalloc_reserve+0x3b/0xa0
[ 7.929681] [<ffffffff8167bfcf>] ? __alloc_skb+0x9f/0x1e0
[ 7.930827] [<ffffffff816a3b64>] rtmsg_ifinfo+0x84/0x100
[ 7.931960] [<ffffffffa00bca07>] bond_ab_arp_probe+0x1a7/0x370 [bonding]
[ 7.933133] [<ffffffffa00bcd78>] bond_activebackup_arp_mon+0x1a8/0x2f0 [bonding]
...
It happens because in bond_ab_arp_probe() we change the flags of a slave
without holding the RTNL lock.
To fix this - remove the useless curr_active_lock, RCUify it and lock RTNL
while changing the slave's flags. Also, remove bond_ab_arp_probe() from
under any locks in bond_ab_arp_mon().
====================
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/bonding/bond_main.c | 67 |
1 files changed, 39 insertions, 28 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a7db819bca92..dd75615d85f2 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -2599,45 +2599,51 @@ 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 | struct list_head *iter; | 2607 | struct list_head *iter; |
2610 | bool found = false; | 2608 | bool found = false; |
2611 | 2609 | ||
2612 | read_lock(&bond->curr_slave_lock); | 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 | ||
2614 | if (curr_arp_slave && bond->curr_active_slave) | 2614 | if (curr_arp_slave && curr_active_slave) |
2615 | pr_info("PROBE: c_arp %s && cas %s BAD\n", | 2615 | pr_info("PROBE: c_arp %s && cas %s BAD\n", |
2616 | curr_arp_slave->dev->name, | 2616 | curr_arp_slave->dev->name, |
2617 | bond->curr_active_slave->dev->name); | 2617 | curr_active_slave->dev->name); |
2618 | 2618 | ||
2619 | if (bond->curr_active_slave) { | 2619 | if (curr_active_slave) { |
2620 | bond_arp_send_all(bond, bond->curr_active_slave); | 2620 | bond_arp_send_all(bond, curr_active_slave); |
2621 | read_unlock(&bond->curr_slave_lock); | 2621 | rcu_read_unlock(); |
2622 | return; | 2622 | return true; |
2623 | } | 2623 | } |
2624 | 2624 | rcu_read_unlock(); | |
2625 | read_unlock(&bond->curr_slave_lock); | ||
2626 | 2625 | ||
2627 | /* 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 |
2628 | * 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 |
2629 | * for becoming the curr_active_slave | 2628 | * for becoming the curr_active_slave |
2630 | */ | 2629 | */ |
2631 | 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 | |||
2632 | if (!curr_arp_slave) { | 2636 | if (!curr_arp_slave) { |
2633 | curr_arp_slave = bond_first_slave_rcu(bond); | 2637 | curr_arp_slave = bond_first_slave(bond); |
2634 | if (!curr_arp_slave) | 2638 | if (!curr_arp_slave) { |
2635 | return; | 2639 | rtnl_unlock(); |
2640 | return true; | ||
2641 | } | ||
2636 | } | 2642 | } |
2637 | 2643 | ||
2638 | bond_set_slave_inactive_flags(curr_arp_slave); | 2644 | bond_set_slave_inactive_flags(curr_arp_slave); |
2639 | 2645 | ||
2640 | bond_for_each_slave_rcu(bond, slave, iter) { | 2646 | bond_for_each_slave(bond, slave, iter) { |
2641 | if (!found && !before && IS_UP(slave->dev)) | 2647 | if (!found && !before && IS_UP(slave->dev)) |
2642 | before = slave; | 2648 | before = slave; |
2643 | 2649 | ||
@@ -2667,21 +2673,26 @@ static void bond_ab_arp_probe(struct bonding *bond) | |||
2667 | if (!new_slave && before) | 2673 | if (!new_slave && before) |
2668 | new_slave = before; | 2674 | new_slave = before; |
2669 | 2675 | ||
2670 | if (!new_slave) | 2676 | if (!new_slave) { |
2671 | return; | 2677 | rtnl_unlock(); |
2678 | return true; | ||
2679 | } | ||
2672 | 2680 | ||
2673 | new_slave->link = BOND_LINK_BACK; | 2681 | new_slave->link = BOND_LINK_BACK; |
2674 | bond_set_slave_active_flags(new_slave); | 2682 | bond_set_slave_active_flags(new_slave); |
2675 | bond_arp_send_all(bond, new_slave); | 2683 | bond_arp_send_all(bond, new_slave); |
2676 | new_slave->jiffies = jiffies; | 2684 | new_slave->jiffies = jiffies; |
2677 | 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; | ||
2678 | } | 2689 | } |
2679 | 2690 | ||
2680 | static void bond_activebackup_arp_mon(struct work_struct *work) | 2691 | static void bond_activebackup_arp_mon(struct work_struct *work) |
2681 | { | 2692 | { |
2682 | struct bonding *bond = container_of(work, struct bonding, | 2693 | struct bonding *bond = container_of(work, struct bonding, |
2683 | arp_work.work); | 2694 | arp_work.work); |
2684 | bool should_notify_peers = false; | 2695 | bool should_notify_peers = false, should_commit = false; |
2685 | int delta_in_ticks; | 2696 | int delta_in_ticks; |
2686 | 2697 | ||
2687 | delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); | 2698 | delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); |
@@ -2690,12 +2701,11 @@ static void bond_activebackup_arp_mon(struct work_struct *work) | |||
2690 | goto re_arm; | 2701 | goto re_arm; |
2691 | 2702 | ||
2692 | rcu_read_lock(); | 2703 | rcu_read_lock(); |
2693 | |||
2694 | 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(); | ||
2695 | 2707 | ||
2696 | if (bond_ab_arp_inspect(bond)) { | 2708 | if (should_commit) { |
2697 | rcu_read_unlock(); | ||
2698 | |||
2699 | /* Race avoidance with bond_close flush of workqueue */ | 2709 | /* Race avoidance with bond_close flush of workqueue */ |
2700 | if (!rtnl_trylock()) { | 2710 | if (!rtnl_trylock()) { |
2701 | delta_in_ticks = 1; | 2711 | delta_in_ticks = 1; |
@@ -2704,13 +2714,14 @@ static void bond_activebackup_arp_mon(struct work_struct *work) | |||
2704 | } | 2714 | } |
2705 | 2715 | ||
2706 | bond_ab_arp_commit(bond); | 2716 | bond_ab_arp_commit(bond); |
2707 | |||
2708 | rtnl_unlock(); | 2717 | rtnl_unlock(); |
2709 | rcu_read_lock(); | ||
2710 | } | 2718 | } |
2711 | 2719 | ||
2712 | bond_ab_arp_probe(bond); | 2720 | if (!bond_ab_arp_probe(bond)) { |
2713 | rcu_read_unlock(); | 2721 | /* rtnl locking failed, re-arm */ |
2722 | delta_in_ticks = 1; | ||
2723 | should_notify_peers = false; | ||
2724 | } | ||
2714 | 2725 | ||
2715 | re_arm: | 2726 | re_arm: |
2716 | if (bond->params.arp_interval) | 2727 | if (bond->params.arp_interval) |