Skip to content

Commit

Permalink
bonding: use dynamic lockdep key instead of subclass
Browse files Browse the repository at this point in the history
All bonding device has same lockdep key and subclass is initialized with
nest_level.
But actual nest_level value can be changed when a lower device is attached.
And at this moment, the subclass should be updated but it seems to be
unsafe.
So this patch makes bonding use dynamic lockdep key instead of the
subclass.

Test commands:
    ip link add bond0 type bond

    for i in {1..5}
    do
	    let A=$i-1
	    ip link add bond$i type bond
	    ip link set bond$i master bond$A
    done
    ip link set bond5 master bond0

Splat looks like:
[  327.477830] ============================================
[  327.477830] WARNING: possible recursive locking detected
[  327.477830] 5.3.0-rc7+ torvalds#322 Not tainted
[  327.477830] --------------------------------------------
[  327.477830] ip/1399 is trying to acquire lock:
[  327.477830] 00000000f604be63 (&(&bond->stats_lock)->rlock#2/2){+.+.}, at: bond_get_stats+0xb8/0x500 [bonding]
[  327.477830]
[  327.477830] but task is already holding lock:
[  327.477830] 00000000e9d31238 (&(&bond->stats_lock)->rlock#2/2){+.+.}, at: bond_get_stats+0xb8/0x500 [bonding]
[  327.477830]
[  327.477830] other info that might help us debug this:
[  327.477830]  Possible unsafe locking scenario:
[  327.477830]
[  327.477830]        CPU0
[  327.477830]        ----
[  327.477830]   lock(&(&bond->stats_lock)->rlock#2/2);
[  327.477830]   lock(&(&bond->stats_lock)->rlock#2/2);
[  327.477830]
[  327.477830]  *** DEADLOCK ***
[  327.477830]
[  327.477830]  May be due to missing lock nesting notation
[  327.477830]
[  327.477830] 3 locks held by ip/1399:
[  327.477830]  #0: 00000000a762c4e3 (rtnl_mutex){+.+.}, at: rtnetlink_rcv_msg+0x466/0x8a0
[  327.477830]  #1: 00000000e9d31238 (&(&bond->stats_lock)->rlock#2/2){+.+.}, at: bond_get_stats+0xb8/0x500 [bonding]
[  327.477830]  #2: 000000008f7ebff4 (rcu_read_lock){....}, at: bond_get_stats+0x9f/0x500 [bonding]
[  327.477830]
[  327.477830] stack backtrace:
[  327.477830] CPU: 0 PID: 1399 Comm: ip Not tainted 5.3.0-rc7+ torvalds#322
[  327.477830] Call Trace:
[  327.477830]  dump_stack+0x7c/0xbb
[  327.477830]  __lock_acquire+0x26a9/0x3de0
[  327.477830]  ? __change_page_attr_set_clr+0x133b/0x1d20
[  327.477830]  ? register_lock_class+0x14d0/0x14d0
[  327.477830]  lock_acquire+0x164/0x3b0
[  327.477830]  ? bond_get_stats+0xb8/0x500 [bonding]
[  327.666914]  _raw_spin_lock_nested+0x2e/0x60
[  327.666914]  ? bond_get_stats+0xb8/0x500 [bonding]
[  327.678302]  bond_get_stats+0xb8/0x500 [bonding]
[  327.678302]  ? bond_arp_rcv+0xf10/0xf10 [bonding]
[  327.678302]  ? register_lock_class+0x14d0/0x14d0
[  327.678302]  ? bond_get_stats+0xb8/0x500 [bonding]
[  327.678302]  dev_get_stats+0x1ec/0x270
[  327.678302]  bond_get_stats+0x1d1/0x500 [bonding]
[  327.678302]  ? lock_acquire+0x164/0x3b0
[  327.678302]  ? bond_arp_rcv+0xf10/0xf10 [bonding]
[  327.678302]  ? rtnl_is_locked+0x16/0x30
[  327.678302]  ? devlink_compat_switch_id_get+0x18/0x140
[  327.678302]  ? dev_get_alias+0xe2/0x190
[  327.731145]  ? dev_get_port_parent_id+0x12a/0x340
[  327.731145]  ? rtnl_phys_switch_id_fill+0x88/0xe0
[  327.731145]  dev_get_stats+0x1ec/0x270
[  327.731145]  rtnl_fill_stats+0x44/0xbe0
[  327.731145]  ? nla_put+0xc2/0x140
[  ... ]

Fixes: d3fff6c ("net: add netdev_lockdep_set_classes() helper")
Signed-off-by: Taehee Yoo <[email protected]>
  • Loading branch information
TaeheeYoo authored and intel-lab-lkp committed Sep 6, 2019
1 parent 06fbef6 commit 222892c
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 4 deletions.
60 changes: 56 additions & 4 deletions drivers/net/bonding/bond_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1856,6 +1856,32 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
return res;
}

static void bond_dev_set_lockdep_one(struct net_device *dev,
struct netdev_queue *txq,
void *_unused)
{
struct bonding *bond = netdev_priv(dev);

lockdep_set_class(&txq->_xmit_lock, &bond->xmit_lock_key);
}

static void bond_update_lock_key(struct net_device *dev)
{
struct bonding *bond = netdev_priv(dev);

lockdep_unregister_key(&bond->stats_lock_key);
lockdep_unregister_key(&bond->addr_lock_key);
lockdep_unregister_key(&bond->xmit_lock_key);

lockdep_register_key(&bond->stats_lock_key);
lockdep_register_key(&bond->addr_lock_key);
lockdep_register_key(&bond->xmit_lock_key);

lockdep_set_class(&bond->stats_lock, &bond->stats_lock_key);
lockdep_set_class(&dev->addr_list_lock, &bond->addr_lock_key);
netdev_for_each_tx_queue(dev, bond_dev_set_lockdep_one, NULL);
}

/* Try to release the slave device <slave> from the bond device <master>
* It is legal to access curr_active_slave without a lock because all the function
* is RTNL-locked. If "all" is true it means that the function is being called
Expand Down Expand Up @@ -2020,6 +2046,8 @@ static int __bond_release_one(struct net_device *bond_dev,
slave_dev->priv_flags &= ~IFF_BONDING_SLAVE;

bond_free_slave(slave);
if (netif_is_bond_master(slave_dev))
bond_update_lock_key(slave_dev);

return 0;
}
Expand Down Expand Up @@ -3454,7 +3482,7 @@ static void bond_get_stats(struct net_device *bond_dev,
struct list_head *iter;
struct slave *slave;

spin_lock_nested(&bond->stats_lock, bond_get_nest_level(bond_dev));
spin_lock(&bond->stats_lock);
memcpy(stats, &bond->bond_stats, sizeof(*stats));

rcu_read_lock();
Expand Down Expand Up @@ -4292,8 +4320,6 @@ void bond_setup(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);

spin_lock_init(&bond->mode_lock);
spin_lock_init(&bond->stats_lock);
bond->params = bonding_defaults;

/* Initialize pointers */
Expand Down Expand Up @@ -4362,6 +4388,9 @@ static void bond_uninit(struct net_device *bond_dev)

list_del(&bond->bond_list);

lockdep_unregister_key(&bond->stats_lock_key);
lockdep_unregister_key(&bond->addr_lock_key);
lockdep_unregister_key(&bond->xmit_lock_key);
bond_debug_unregister(bond);
}

Expand Down Expand Up @@ -4753,6 +4782,29 @@ static int bond_check_params(struct bond_params *params)
return 0;
}

static struct lock_class_key qdisc_tx_busylock_key;
static struct lock_class_key qdisc_running_key;

static void bond_dev_set_lockdep_class(struct net_device *dev)
{
struct bonding *bond = netdev_priv(dev);

dev->qdisc_tx_busylock = &qdisc_tx_busylock_key;
dev->qdisc_running_key = &qdisc_running_key;

spin_lock_init(&bond->mode_lock);

spin_lock_init(&bond->stats_lock);
lockdep_register_key(&bond->stats_lock_key);
lockdep_set_class(&bond->stats_lock, &bond->stats_lock_key);

lockdep_register_key(&bond->addr_lock_key);
lockdep_set_class(&dev->addr_list_lock, &bond->addr_lock_key);

lockdep_register_key(&bond->xmit_lock_key);
netdev_for_each_tx_queue(dev, bond_dev_set_lockdep_one, NULL);
}

/* Called from registration process */
static int bond_init(struct net_device *bond_dev)
{
Expand All @@ -4766,7 +4818,7 @@ static int bond_init(struct net_device *bond_dev)
return -ENOMEM;

bond->nest_level = SINGLE_DEPTH_NESTING;
netdev_lockdep_set_classes(bond_dev);
bond_dev_set_lockdep_class(bond_dev);

list_add_tail(&bond->bond_list, &bn->dev_list);

Expand Down
3 changes: 3 additions & 0 deletions include/net/bonding.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ struct bonding {
struct dentry *debug_dir;
#endif /* CONFIG_DEBUG_FS */
struct rtnl_link_stats64 bond_stats;
struct lock_class_key stats_lock_key;
struct lock_class_key xmit_lock_key;
struct lock_class_key addr_lock_key;
};

#define bond_slave_get_rcu(dev) \
Expand Down

0 comments on commit 222892c

Please sign in to comment.