Skip to content

Commit

Permalink
macsec: use dynamic lockdep key instead of subclass
Browse files Browse the repository at this point in the history
All macsec 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 macsec use dynamic lockdep key instead of the subclass.

Test commands:
    ip link add bond0 type bond
    ip link add dummy0 type dummy
    ip link add macsec0 link bond0 type macsec
    ip link add macsec1 link dummy0 type macsec
    ip link set bond0 mtu 1000
    ip link set macsec1 master bond0

    ip link set bond0 up
    ip link set macsec0 up
    ip link set dummy0 up
    ip link set macsec1 up

Splat looks like:
[  146.540123] ============================================
[  146.540123] WARNING: possible recursive locking detected
[  146.540123] 5.3.0-rc7+ torvalds#322 Not tainted
[  146.540123] --------------------------------------------
[  146.540123] ip/1340 is trying to acquire lock:
[  146.540123] 00000000446fd8bd (&macsec_netdev_addr_lock_key/1){+...}, at: dev_uc_sync_multiple+0xfa/0x1a0
[  146.540123]
[  146.540123] but task is already holding lock:
[  146.540123] 00000000a9ab6378 (&macsec_netdev_addr_lock_key/1){+...}, at: dev_set_rx_mode+0x19/0x30
[  146.540123]
[  146.540123] other info that might help us debug this:
[  146.540123]  Possible unsafe locking scenario:
[  146.540123]
[  146.540123]        CPU0
[  146.540123]        ----
[  146.540123]   lock(&macsec_netdev_addr_lock_key/1);
[  146.540123]   lock(&macsec_netdev_addr_lock_key/1);
[  146.623155]
[  146.623155]  *** DEADLOCK ***
[  146.623155]
[  146.623155]  May be due to missing lock nesting notation
[  146.623155]
[  146.623155] 4 locks held by ip/1340:
[  146.623155]  #0: 0000000026436ef0 (rtnl_mutex){+.+.}, at: rtnetlink_rcv_msg+0x466/0x8a0
[  146.623155]  #1: 00000000a9ab6378 (&macsec_netdev_addr_lock_key/1){+...}, at: dev_set_rx_mode+0x19/0x30
[  146.623155]  #2: 00000000a8947dd0 (&dev_addr_list_lock_key/3){+...}, at: dev_mc_sync+0xfa/0x1a0
[  146.623155]  #3: 00000000b62011e9 (rcu_read_lock){....}, at: bond_set_rx_mode+0x5/0x3c0 [bonding]
[  146.674970]
[  146.674970] stack backtrace:
[  146.687145] CPU: 0 PID: 1340 Comm: ip Not tainted 5.3.0-rc7+ torvalds#322
[  146.693024] Call Trace:
[  146.693024]  dump_stack+0x7c/0xbb
[  146.693024]  __lock_acquire+0x26a9/0x3de0
[  146.693024]  ? register_lock_class+0x14d0/0x14d0
[  146.693024]  ? register_lock_class+0x14d0/0x14d0
[  146.693024]  lock_acquire+0x164/0x3b0
[  146.693024]  ? dev_uc_sync_multiple+0xfa/0x1a0
[  146.693024]  _raw_spin_lock_nested+0x2e/0x60
[  146.693024]  ? dev_uc_sync_multiple+0xfa/0x1a0
[  146.693024]  dev_uc_sync_multiple+0xfa/0x1a0
[  146.693024]  bond_set_rx_mode+0x269/0x3c0 [bonding]
[  146.751163]  ? bond_init+0x6f0/0x6f0 [bonding]
[  146.757006]  ? do_raw_spin_trylock+0xa9/0x170
[  146.757006]  dev_mc_sync+0x15a/0x1a0
[  146.757006]  macsec_dev_set_rx_mode+0x3a/0x50 [macsec]
[  146.757006]  dev_set_rx_mode+0x21/0x30
[  146.757006]  __dev_open+0x202/0x310
[  146.757006]  ? dev_set_rx_mode+0x30/0x30
[  146.757006]  ? mark_held_locks+0xa5/0xe0
[  146.757006]  ? __local_bh_enable_ip+0xe9/0x1b0
[  146.757006]  __dev_change_flags+0x3c3/0x500
[  146.757006]  ? dev_set_allmulti+0x10/0x10
[  146.757006]  ? sched_clock_local+0xd4/0x140
[  146.757006]  ? check_chain_key+0x236/0x5d0
[  146.757006]  dev_change_flags+0x7a/0x160
[  146.757006]  do_setlink+0xa26/0x2f20
[  146.757006]  ? sched_clock_local+0xd4/0x140
[  ... ]

Fixes: e200387 ("macsec: fix lockdep splats when nesting devices")
Signed-off-by: Taehee Yoo <[email protected]>
  • Loading branch information
TaeheeYoo authored and intel-lab-lkp committed Sep 6, 2019
1 parent 9706d9e commit 11c0996
Showing 1 changed file with 32 additions and 5 deletions.
37 changes: 32 additions & 5 deletions drivers/net/macsec.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ struct macsec_dev {
struct pcpu_secy_stats __percpu *stats;
struct list_head secys;
struct gro_cells gro_cells;
struct lock_class_key xmit_lock_key;
struct lock_class_key addr_lock_key;
unsigned int nest_level;
};

Expand Down Expand Up @@ -2749,7 +2751,32 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,

#define MACSEC_FEATURES \
(NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST)
static struct lock_class_key macsec_netdev_addr_lock_key;

static void macsec_dev_set_lockdep_one(struct net_device *dev,
struct netdev_queue *txq,
void *_unused)
{
struct macsec_dev *macsec = macsec_priv(dev);

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

static struct lock_class_key qdisc_tx_busylock_key;
static struct lock_class_key qdisc_running_key;

static void macsec_dev_set_lockdep_class(struct net_device *dev)
{
struct macsec_dev *macsec = macsec_priv(dev);

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

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

lockdep_register_key(&macsec->xmit_lock_key);
netdev_for_each_tx_queue(dev, macsec_dev_set_lockdep_one, NULL);
}

static int macsec_dev_init(struct net_device *dev)
{
Expand Down Expand Up @@ -2780,6 +2807,7 @@ static int macsec_dev_init(struct net_device *dev)
if (is_zero_ether_addr(dev->broadcast))
memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len);

macsec_dev_set_lockdep_class(dev);
return 0;
}

Expand All @@ -2789,6 +2817,9 @@ static void macsec_dev_uninit(struct net_device *dev)

gro_cells_destroy(&macsec->gro_cells);
free_percpu(dev->tstats);

lockdep_unregister_key(&macsec->addr_lock_key);
lockdep_unregister_key(&macsec->xmit_lock_key);
}

static netdev_features_t macsec_fix_features(struct net_device *dev,
Expand Down Expand Up @@ -3263,10 +3294,6 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
dev_hold(real_dev);

macsec->nest_level = dev_get_nest_level(real_dev) + 1;
netdev_lockdep_set_classes(dev);
lockdep_set_class_and_subclass(&dev->addr_list_lock,
&macsec_netdev_addr_lock_key,
macsec_get_nest_level(dev));

err = netdev_upper_dev_link(real_dev, dev, extack);
if (err < 0)
Expand Down

0 comments on commit 11c0996

Please sign in to comment.