Skip to content

Commit f2ebd47

Browse files
Veaceslav Falicodavem330
authored andcommitted
bonding: restructure locking of bond_ab_arp_probe()
Currently we're calling it from under RCU context, however we're using some functions that require rtnl to be held. Fix this by restructuring the locking - don't call it under any locks, aquire rcu_read_lock() if we're sending _only_ (i.e. we have the active slave present), and use rtnl locking otherwise - if we need to modify (in)active flags of a slave. 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>
1 parent 98b90f2 commit f2ebd47

File tree

1 file changed

+36
-21
lines changed

1 file changed

+36
-21
lines changed

drivers/net/bonding/bond_main.c

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2599,41 +2599,51 @@ static void bond_ab_arp_commit(struct bonding *bond)
25992599

26002600
/*
26012601
* Send ARP probes for active-backup mode ARP monitor.
2602-
*
2603-
* Called with rcu_read_lock hold.
26042602
*/
2605-
static void bond_ab_arp_probe(struct bonding *bond)
2603+
static bool bond_ab_arp_probe(struct bonding *bond)
26062604
{
26072605
struct slave *slave, *before = NULL, *new_slave = NULL,
2608-
*curr_arp_slave = rcu_dereference(bond->current_arp_slave),
2609-
*curr_active_slave = rcu_dereference(bond->curr_active_slave);
2606+
*curr_arp_slave, *curr_active_slave;
26102607
struct list_head *iter;
26112608
bool found = false;
26122609

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+
26132614
if (curr_arp_slave && curr_active_slave)
26142615
pr_info("PROBE: c_arp %s && cas %s BAD\n",
26152616
curr_arp_slave->dev->name,
26162617
curr_active_slave->dev->name);
26172618

26182619
if (curr_active_slave) {
26192620
bond_arp_send_all(bond, curr_active_slave);
2620-
return;
2621+
rcu_read_unlock();
2622+
return true;
26212623
}
2624+
rcu_read_unlock();
26222625

26232626
/* if we don't have a curr_active_slave, search for the next available
26242627
* backup slave from the current_arp_slave and make it the candidate
26252628
* for becoming the curr_active_slave
26262629
*/
26272630

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+
26282636
if (!curr_arp_slave) {
2629-
curr_arp_slave = bond_first_slave_rcu(bond);
2630-
if (!curr_arp_slave)
2631-
return;
2637+
curr_arp_slave = bond_first_slave(bond);
2638+
if (!curr_arp_slave) {
2639+
rtnl_unlock();
2640+
return true;
2641+
}
26322642
}
26332643

26342644
bond_set_slave_inactive_flags(curr_arp_slave);
26352645

2636-
bond_for_each_slave_rcu(bond, slave, iter) {
2646+
bond_for_each_slave(bond, slave, iter) {
26372647
if (!found && !before && IS_UP(slave->dev))
26382648
before = slave;
26392649

@@ -2663,21 +2673,26 @@ static void bond_ab_arp_probe(struct bonding *bond)
26632673
if (!new_slave && before)
26642674
new_slave = before;
26652675

2666-
if (!new_slave)
2667-
return;
2676+
if (!new_slave) {
2677+
rtnl_unlock();
2678+
return true;
2679+
}
26682680

26692681
new_slave->link = BOND_LINK_BACK;
26702682
bond_set_slave_active_flags(new_slave);
26712683
bond_arp_send_all(bond, new_slave);
26722684
new_slave->jiffies = jiffies;
26732685
rcu_assign_pointer(bond->current_arp_slave, new_slave);
2686+
rtnl_unlock();
2687+
2688+
return true;
26742689
}
26752690

26762691
static void bond_activebackup_arp_mon(struct work_struct *work)
26772692
{
26782693
struct bonding *bond = container_of(work, struct bonding,
26792694
arp_work.work);
2680-
bool should_notify_peers = false;
2695+
bool should_notify_peers = false, should_commit = false;
26812696
int delta_in_ticks;
26822697

26832698
delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
@@ -2686,12 +2701,11 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
26862701
goto re_arm;
26872702

26882703
rcu_read_lock();
2689-
26902704
should_notify_peers = bond_should_notify_peers(bond);
2705+
should_commit = bond_ab_arp_inspect(bond);
2706+
rcu_read_unlock();
26912707

2692-
if (bond_ab_arp_inspect(bond)) {
2693-
rcu_read_unlock();
2694-
2708+
if (should_commit) {
26952709
/* Race avoidance with bond_close flush of workqueue */
26962710
if (!rtnl_trylock()) {
26972711
delta_in_ticks = 1;
@@ -2700,13 +2714,14 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
27002714
}
27012715

27022716
bond_ab_arp_commit(bond);
2703-
27042717
rtnl_unlock();
2705-
rcu_read_lock();
27062718
}
27072719

2708-
bond_ab_arp_probe(bond);
2709-
rcu_read_unlock();
2720+
if (!bond_ab_arp_probe(bond)) {
2721+
/* rtnl locking failed, re-arm */
2722+
delta_in_ticks = 1;
2723+
should_notify_peers = false;
2724+
}
27102725

27112726
re_arm:
27122727
if (bond->params.arp_interval)

0 commit comments

Comments
 (0)