Skip to content

Commit 6960d13

Browse files
ihuguetdavem330
authored andcommitted
atlantic: fix deadlock at aq_nic_stop
NIC is stopped with rtnl_lock held, and during the stop it cancels the 'service_task' work and free irqs. However, if CONFIG_MACSEC is set, rtnl_lock is acquired both from aq_nic_service_task and aq_linkstate_threaded_isr. Then a deadlock happens if aq_nic_stop tries to cancel/disable them when they've already started their execution. As the deadlock is caused by rtnl_lock, it causes many other processes to stall, not only atlantic related stuff. Fix it by introducing a mutex that protects each NIC's macsec related data, and locking it instead of the rtnl_lock from the service task and the threaded IRQ. Before this patch, all macsec data was protected with rtnl_lock, but maybe not all of it needs to be protected. With this new mutex, further efforts can be made to limit the protected data only to that which requires it. However, probably it doesn't worth it because all macsec's data accesses are infrequent, and almost all are done from macsec_ops or ethtool callbacks, called holding rtnl_lock, so macsec_mutex won't never be much contended. The issue appeared repeteadly attaching and deattaching the NIC to a bond interface. Doing that after this patch I cannot reproduce the bug. Fixes: 62c1c2e ("net: atlantic: MACSec offload skeleton") Reported-by: Li Liang <liali@redhat.com> Suggested-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Íñigo Huguet <ihuguet@redhat.com> Reviewed-by: Igor Russkikh <irusskikh@marvell.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 0bda036 commit 6960d13

File tree

2 files changed

+74
-24
lines changed

2 files changed

+74
-24
lines changed

drivers/net/ethernet/aquantia/atlantic/aq_macsec.c

Lines changed: 72 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,26 +1394,57 @@ static void aq_check_txsa_expiration(struct aq_nic_s *nic)
13941394
egress_sa_threshold_expired);
13951395
}
13961396

1397+
#define AQ_LOCKED_MDO_DEF(mdo) \
1398+
static int aq_locked_mdo_##mdo(struct macsec_context *ctx) \
1399+
{ \
1400+
struct aq_nic_s *nic = netdev_priv(ctx->netdev); \
1401+
int ret; \
1402+
mutex_lock(&nic->macsec_mutex); \
1403+
ret = aq_mdo_##mdo(ctx); \
1404+
mutex_unlock(&nic->macsec_mutex); \
1405+
return ret; \
1406+
}
1407+
1408+
AQ_LOCKED_MDO_DEF(dev_open)
1409+
AQ_LOCKED_MDO_DEF(dev_stop)
1410+
AQ_LOCKED_MDO_DEF(add_secy)
1411+
AQ_LOCKED_MDO_DEF(upd_secy)
1412+
AQ_LOCKED_MDO_DEF(del_secy)
1413+
AQ_LOCKED_MDO_DEF(add_rxsc)
1414+
AQ_LOCKED_MDO_DEF(upd_rxsc)
1415+
AQ_LOCKED_MDO_DEF(del_rxsc)
1416+
AQ_LOCKED_MDO_DEF(add_rxsa)
1417+
AQ_LOCKED_MDO_DEF(upd_rxsa)
1418+
AQ_LOCKED_MDO_DEF(del_rxsa)
1419+
AQ_LOCKED_MDO_DEF(add_txsa)
1420+
AQ_LOCKED_MDO_DEF(upd_txsa)
1421+
AQ_LOCKED_MDO_DEF(del_txsa)
1422+
AQ_LOCKED_MDO_DEF(get_dev_stats)
1423+
AQ_LOCKED_MDO_DEF(get_tx_sc_stats)
1424+
AQ_LOCKED_MDO_DEF(get_tx_sa_stats)
1425+
AQ_LOCKED_MDO_DEF(get_rx_sc_stats)
1426+
AQ_LOCKED_MDO_DEF(get_rx_sa_stats)
1427+
13971428
const struct macsec_ops aq_macsec_ops = {
1398-
.mdo_dev_open = aq_mdo_dev_open,
1399-
.mdo_dev_stop = aq_mdo_dev_stop,
1400-
.mdo_add_secy = aq_mdo_add_secy,
1401-
.mdo_upd_secy = aq_mdo_upd_secy,
1402-
.mdo_del_secy = aq_mdo_del_secy,
1403-
.mdo_add_rxsc = aq_mdo_add_rxsc,
1404-
.mdo_upd_rxsc = aq_mdo_upd_rxsc,
1405-
.mdo_del_rxsc = aq_mdo_del_rxsc,
1406-
.mdo_add_rxsa = aq_mdo_add_rxsa,
1407-
.mdo_upd_rxsa = aq_mdo_upd_rxsa,
1408-
.mdo_del_rxsa = aq_mdo_del_rxsa,
1409-
.mdo_add_txsa = aq_mdo_add_txsa,
1410-
.mdo_upd_txsa = aq_mdo_upd_txsa,
1411-
.mdo_del_txsa = aq_mdo_del_txsa,
1412-
.mdo_get_dev_stats = aq_mdo_get_dev_stats,
1413-
.mdo_get_tx_sc_stats = aq_mdo_get_tx_sc_stats,
1414-
.mdo_get_tx_sa_stats = aq_mdo_get_tx_sa_stats,
1415-
.mdo_get_rx_sc_stats = aq_mdo_get_rx_sc_stats,
1416-
.mdo_get_rx_sa_stats = aq_mdo_get_rx_sa_stats,
1429+
.mdo_dev_open = aq_locked_mdo_dev_open,
1430+
.mdo_dev_stop = aq_locked_mdo_dev_stop,
1431+
.mdo_add_secy = aq_locked_mdo_add_secy,
1432+
.mdo_upd_secy = aq_locked_mdo_upd_secy,
1433+
.mdo_del_secy = aq_locked_mdo_del_secy,
1434+
.mdo_add_rxsc = aq_locked_mdo_add_rxsc,
1435+
.mdo_upd_rxsc = aq_locked_mdo_upd_rxsc,
1436+
.mdo_del_rxsc = aq_locked_mdo_del_rxsc,
1437+
.mdo_add_rxsa = aq_locked_mdo_add_rxsa,
1438+
.mdo_upd_rxsa = aq_locked_mdo_upd_rxsa,
1439+
.mdo_del_rxsa = aq_locked_mdo_del_rxsa,
1440+
.mdo_add_txsa = aq_locked_mdo_add_txsa,
1441+
.mdo_upd_txsa = aq_locked_mdo_upd_txsa,
1442+
.mdo_del_txsa = aq_locked_mdo_del_txsa,
1443+
.mdo_get_dev_stats = aq_locked_mdo_get_dev_stats,
1444+
.mdo_get_tx_sc_stats = aq_locked_mdo_get_tx_sc_stats,
1445+
.mdo_get_tx_sa_stats = aq_locked_mdo_get_tx_sa_stats,
1446+
.mdo_get_rx_sc_stats = aq_locked_mdo_get_rx_sc_stats,
1447+
.mdo_get_rx_sa_stats = aq_locked_mdo_get_rx_sa_stats,
14171448
};
14181449

14191450
int aq_macsec_init(struct aq_nic_s *nic)
@@ -1435,6 +1466,7 @@ int aq_macsec_init(struct aq_nic_s *nic)
14351466

14361467
nic->ndev->features |= NETIF_F_HW_MACSEC;
14371468
nic->ndev->macsec_ops = &aq_macsec_ops;
1469+
mutex_init(&nic->macsec_mutex);
14381470

14391471
return 0;
14401472
}
@@ -1458,7 +1490,7 @@ int aq_macsec_enable(struct aq_nic_s *nic)
14581490
if (!nic->macsec_cfg)
14591491
return 0;
14601492

1461-
rtnl_lock();
1493+
mutex_lock(&nic->macsec_mutex);
14621494

14631495
if (nic->aq_fw_ops->send_macsec_req) {
14641496
struct macsec_cfg_request cfg = { 0 };
@@ -1507,7 +1539,7 @@ int aq_macsec_enable(struct aq_nic_s *nic)
15071539
ret = aq_apply_macsec_cfg(nic);
15081540

15091541
unlock:
1510-
rtnl_unlock();
1542+
mutex_unlock(&nic->macsec_mutex);
15111543
return ret;
15121544
}
15131545

@@ -1519,9 +1551,9 @@ void aq_macsec_work(struct aq_nic_s *nic)
15191551
if (!netif_carrier_ok(nic->ndev))
15201552
return;
15211553

1522-
rtnl_lock();
1554+
mutex_lock(&nic->macsec_mutex);
15231555
aq_check_txsa_expiration(nic);
1524-
rtnl_unlock();
1556+
mutex_unlock(&nic->macsec_mutex);
15251557
}
15261558

15271559
int aq_macsec_rx_sa_cnt(struct aq_nic_s *nic)
@@ -1532,21 +1564,30 @@ int aq_macsec_rx_sa_cnt(struct aq_nic_s *nic)
15321564
if (!cfg)
15331565
return 0;
15341566

1567+
mutex_lock(&nic->macsec_mutex);
1568+
15351569
for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
15361570
if (!test_bit(i, &cfg->rxsc_idx_busy))
15371571
continue;
15381572
cnt += hweight_long(cfg->aq_rxsc[i].rx_sa_idx_busy);
15391573
}
15401574

1575+
mutex_unlock(&nic->macsec_mutex);
15411576
return cnt;
15421577
}
15431578

15441579
int aq_macsec_tx_sc_cnt(struct aq_nic_s *nic)
15451580
{
1581+
int cnt;
1582+
15461583
if (!nic->macsec_cfg)
15471584
return 0;
15481585

1549-
return hweight_long(nic->macsec_cfg->txsc_idx_busy);
1586+
mutex_lock(&nic->macsec_mutex);
1587+
cnt = hweight_long(nic->macsec_cfg->txsc_idx_busy);
1588+
mutex_unlock(&nic->macsec_mutex);
1589+
1590+
return cnt;
15501591
}
15511592

15521593
int aq_macsec_tx_sa_cnt(struct aq_nic_s *nic)
@@ -1557,12 +1598,15 @@ int aq_macsec_tx_sa_cnt(struct aq_nic_s *nic)
15571598
if (!cfg)
15581599
return 0;
15591600

1601+
mutex_lock(&nic->macsec_mutex);
1602+
15601603
for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
15611604
if (!test_bit(i, &cfg->txsc_idx_busy))
15621605
continue;
15631606
cnt += hweight_long(cfg->aq_txsc[i].tx_sa_idx_busy);
15641607
}
15651608

1609+
mutex_unlock(&nic->macsec_mutex);
15661610
return cnt;
15671611
}
15681612

@@ -1634,6 +1678,8 @@ u64 *aq_macsec_get_stats(struct aq_nic_s *nic, u64 *data)
16341678
if (!cfg)
16351679
return data;
16361680

1681+
mutex_lock(&nic->macsec_mutex);
1682+
16371683
aq_macsec_update_stats(nic);
16381684

16391685
common_stats = &cfg->stats;
@@ -1716,5 +1762,7 @@ u64 *aq_macsec_get_stats(struct aq_nic_s *nic, u64 *data)
17161762

17171763
data += i;
17181764

1765+
mutex_unlock(&nic->macsec_mutex);
1766+
17191767
return data;
17201768
}

drivers/net/ethernet/aquantia/atlantic/aq_nic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ struct aq_nic_s {
157157
struct mutex fwreq_mutex;
158158
#if IS_ENABLED(CONFIG_MACSEC)
159159
struct aq_macsec_cfg *macsec_cfg;
160+
/* mutex to protect data in macsec_cfg */
161+
struct mutex macsec_mutex;
160162
#endif
161163
/* PTP support */
162164
struct aq_ptp_s *aq_ptp;

0 commit comments

Comments
 (0)