summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTaehee Yoo <ap420073@gmail.com>2019-10-21 14:47:53 -0400
committerDavid S. Miller <davem@davemloft.net>2019-10-24 17:53:48 -0400
commit089bca2caed0d0dea7da235ce1fe245808f5ec02 (patch)
tree89119557c37cb78c2b3174659e6b336c55346409
parent65de65d9033750d2cf1b336c9d6e9da3a8b5cc6e (diff)
bonding: use dynamic lockdep key instead of subclass
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: [ 307.992912] WARNING: possible recursive locking detected [ 307.993656] 5.4.0-rc3+ #96 Tainted: G W [ 307.994367] -------------------------------------------- [ 307.995092] ip/761 is trying to acquire lock: [ 307.995710] ffff8880513aac60 (&(&bond->stats_lock)->rlock#2/2){+.+.}, at: bond_get_stats+0xb8/0x500 [bonding] [ 307.997045] but task is already holding lock: [ 307.997923] ffff88805fcbac60 (&(&bond->stats_lock)->rlock#2/2){+.+.}, at: bond_get_stats+0xb8/0x500 [bonding] [ 307.999215] other info that might help us debug this: [ 308.000251] Possible unsafe locking scenario: [ 308.001137] CPU0 [ 308.001533] ---- [ 308.001915] lock(&(&bond->stats_lock)->rlock#2/2); [ 308.002609] lock(&(&bond->stats_lock)->rlock#2/2); [ 308.003302] *** DEADLOCK *** [ 308.004310] May be due to missing lock nesting notation [ 308.005319] 3 locks held by ip/761: [ 308.005830] #0: ffffffff9fcc42b0 (rtnl_mutex){+.+.}, at: rtnetlink_rcv_msg+0x466/0x8a0 [ 308.006894] #1: ffff88805fcbac60 (&(&bond->stats_lock)->rlock#2/2){+.+.}, at: bond_get_stats+0xb8/0x500 [bonding] [ 308.008243] #2: ffffffff9f9219c0 (rcu_read_lock){....}, at: bond_get_stats+0x9f/0x500 [bonding] [ 308.009422] stack backtrace: [ 308.010124] CPU: 0 PID: 761 Comm: ip Tainted: G W 5.4.0-rc3+ #96 [ 308.011097] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 [ 308.012179] Call Trace: [ 308.012601] dump_stack+0x7c/0xbb [ 308.013089] __lock_acquire+0x269d/0x3de0 [ 308.013669] ? register_lock_class+0x14d0/0x14d0 [ 308.014318] lock_acquire+0x164/0x3b0 [ 308.014858] ? bond_get_stats+0xb8/0x500 [bonding] [ 308.015520] _raw_spin_lock_nested+0x2e/0x60 [ 308.016129] ? bond_get_stats+0xb8/0x500 [bonding] [ 308.017215] bond_get_stats+0xb8/0x500 [bonding] [ 308.018454] ? bond_arp_rcv+0xf10/0xf10 [bonding] [ 308.019710] ? rcu_read_lock_held+0x90/0xa0 [ 308.020605] ? rcu_read_lock_sched_held+0xc0/0xc0 [ 308.021286] ? bond_get_stats+0x9f/0x500 [bonding] [ 308.021953] dev_get_stats+0x1ec/0x270 [ 308.022508] bond_get_stats+0x1d1/0x500 [bonding] Fixes: d3fff6c443fe ("net: add netdev_lockdep_set_classes() helper") Signed-off-by: Taehee Yoo <ap420073@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bonding/bond_main.c10
-rw-r--r--include/net/bonding.h1
2 files changed, 8 insertions, 3 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 92713b93f66f..6a6273590288 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3459,7 +3459,7 @@ static void bond_get_stats(struct net_device *bond_dev,
3459 struct list_head *iter; 3459 struct list_head *iter;
3460 struct slave *slave; 3460 struct slave *slave;
3461 3461
3462 spin_lock_nested(&bond->stats_lock, bond_get_nest_level(bond_dev)); 3462 spin_lock(&bond->stats_lock);
3463 memcpy(stats, &bond->bond_stats, sizeof(*stats)); 3463 memcpy(stats, &bond->bond_stats, sizeof(*stats));
3464 3464
3465 rcu_read_lock(); 3465 rcu_read_lock();
@@ -4297,8 +4297,6 @@ void bond_setup(struct net_device *bond_dev)
4297{ 4297{
4298 struct bonding *bond = netdev_priv(bond_dev); 4298 struct bonding *bond = netdev_priv(bond_dev);
4299 4299
4300 spin_lock_init(&bond->mode_lock);
4301 spin_lock_init(&bond->stats_lock);
4302 bond->params = bonding_defaults; 4300 bond->params = bonding_defaults;
4303 4301
4304 /* Initialize pointers */ 4302 /* Initialize pointers */
@@ -4367,6 +4365,7 @@ static void bond_uninit(struct net_device *bond_dev)
4367 4365
4368 list_del(&bond->bond_list); 4366 list_del(&bond->bond_list);
4369 4367
4368 lockdep_unregister_key(&bond->stats_lock_key);
4370 bond_debug_unregister(bond); 4369 bond_debug_unregister(bond);
4371} 4370}
4372 4371
@@ -4772,6 +4771,11 @@ static int bond_init(struct net_device *bond_dev)
4772 4771
4773 bond->nest_level = SINGLE_DEPTH_NESTING; 4772 bond->nest_level = SINGLE_DEPTH_NESTING;
4774 4773
4774 spin_lock_init(&bond->mode_lock);
4775 spin_lock_init(&bond->stats_lock);
4776 lockdep_register_key(&bond->stats_lock_key);
4777 lockdep_set_class(&bond->stats_lock, &bond->stats_lock_key);
4778
4775 list_add_tail(&bond->bond_list, &bn->dev_list); 4779 list_add_tail(&bond->bond_list, &bn->dev_list);
4776 4780
4777 bond_prepare_sysfs_group(bond); 4781 bond_prepare_sysfs_group(bond);
diff --git a/include/net/bonding.h b/include/net/bonding.h
index f7fe45689142..334909feb2bb 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -239,6 +239,7 @@ struct bonding {
239 struct dentry *debug_dir; 239 struct dentry *debug_dir;
240#endif /* CONFIG_DEBUG_FS */ 240#endif /* CONFIG_DEBUG_FS */
241 struct rtnl_link_stats64 bond_stats; 241 struct rtnl_link_stats64 bond_stats;
242 struct lock_class_key stats_lock_key;
242}; 243};
243 244
244#define bond_slave_get_rcu(dev) \ 245#define bond_slave_get_rcu(dev) \