After h->ae_algo->ops->get_vector() has acquired MSI-X vectors, a subsequent devm_kcalloc failure for priv->tqp_vector jumps to 'out' and returns without calling put_vector() to release them. The underlying hclge/hclgevf bookkeeping (num_msi_used, num_msi_left, vector_status[]) is left inconsistent: the vectors are marked as in use but hns3_enet never tracks or releases them. On the reset path this leak accumulates across failed reset attempts, steadily reducing num_msi_left until get_vector() can no longer satisfy the requested count, at which point the interface fails to recover. Call put_vector() for every vector acquired by get_vector() before returning an error, and reset priv->vector_num so the dealloc path cannot dereference a NULL priv->tqp_vector. Fixes: dd38c72604dc ("net: hns3: fix for coalesce configuration lost during reset") Signed-off-by: Jijie Shao --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 47788be64be6..2f3aeade558c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -4854,7 +4854,7 @@ static int hns3_nic_alloc_vector_data(struct hns3_nic_priv *priv) GFP_KERNEL); if (!priv->tqp_vector) { ret = -ENOMEM; - goto out; + goto err_put_vector; } for (i = 0; i < priv->vector_num; i++) { @@ -4865,7 +4865,13 @@ static int hns3_nic_alloc_vector_data(struct hns3_nic_priv *priv) hns3_vector_coalesce_init(tqp_vector, priv); } -out: + devm_kfree(&pdev->dev, vector); + return 0; + +err_put_vector: + for (i = 0; i < vector_num; i++) + h->ae_algo->ops->put_vector(h, vector[i].vector); + priv->vector_num = 0; devm_kfree(&pdev->dev, vector); return ret; } -- 2.43.0 NAPI polling on hns3 is driven by hardware RX interrupts. Under memory pressure, RX skb and frag allocations fail, so packets are no longer reaped from the hardware rx ring. Once the ring fills, the hardware stops generating RX interrupts and NAPI is never scheduled again -- even after memory becomes available. The interface falls into a deadlock: draining the ring needs NAPI, scheduling NAPI needs an interrupt, and the interrupt needs the ring to be drained. Break the deadlock by adding a software recovery path that re-arms NAPI via a 250ms delayed_work, independent of hardware interrupts. A per-vector bitmap tracks which vectors have rings in OOM state, and the work function schedules NAPI for each affected vector. OOM state is marked at every RX allocation failure site. Also fix hns3_clean_rx_ring() to return recv_pkts instead of budget on allocation failure, preventing NAPI busy-poll under low memory. Add rx_oom_cnt ethtool counter for diagnostics. Fixes: 81ae0e0491f3 ("net: hns3: Add skb chain when num of RX buf exceeds MAX_SKB_FRAGS") Signed-off-by: Jijie Shao --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 52 ++++++++++++++++++- .../net/ethernet/hisilicon/hns3/hns3_enet.h | 17 ++++++ .../ethernet/hisilicon/hns3/hns3_ethtool.c | 1 + 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 2f3aeade558c..0c088feae03c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -78,6 +78,8 @@ module_param(page_pool_enabled, bool, 0400); #define HNS3_MIN_TX_LEN 33U #define HNS3_MIN_TUN_PKT_LEN 65U +#define HNS3_OOM_POLL_INTERVAL_MS 250 + /* hns3_pci_tbl - PCI Device ID Table * * Last entry must be all 0s @@ -3793,6 +3795,7 @@ static int hns3_handle_rx_copybreak(struct sk_buff *skb, int i, hns3_rl_err(ring_to_netdev(ring), "failed to allocate rx frag\n"); + hns3_ring_set_oom_state(ring); return -ENOMEM; } @@ -4162,6 +4165,7 @@ static int hns3_add_frag(struct hns3_enet_ring *ring) if (unlikely(!new_skb)) { hns3_rl_err(ring_to_netdev(ring), "alloc rx fraglist skb fail\n"); + hns3_ring_set_oom_state(ring); return -ENXIO; } @@ -4451,6 +4455,34 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring) return 0; } +static void hns3_oom_task(struct work_struct *work) +{ + struct hns3_nic_priv *priv = container_of(work, struct hns3_nic_priv, + oom_task.work); + struct net_device *netdev = priv->netdev; + struct hnae3_handle *h = priv->ae_handle; + u16 i; + + if (test_bit(HNS3_NIC_STATE_DOWN, &priv->state)) + return; + + netif_dbg(h, rx_err, netdev, "oom napi_schedule 0x%*pb\n", + priv->vector_num, priv->oom_vector_bm); + for (i = 0; i < priv->vector_num; i++) + if (test_and_clear_bit(i, priv->oom_vector_bm)) + napi_schedule(&priv->tqp_vector[i].napi); +} + +static void hns3_oom_task_schedule(struct hns3_enet_ring *ring) +{ + struct hns3_nic_priv *priv = netdev_priv(ring_to_netdev(ring)); + + hns3_ring_stats_update(ring, rx_oom_cnt); + hns3_ring_set_oom_state(ring); + schedule_delayed_work(&priv->oom_task, + msecs_to_jiffies(HNS3_OOM_POLL_INTERVAL_MS)); +} + int hns3_clean_rx_ring(struct hns3_enet_ring *ring, int budget, void (*rx_fn)(struct hns3_enet_ring *, struct sk_buff *)) { @@ -4472,6 +4504,9 @@ int hns3_clean_rx_ring(struct hns3_enet_ring *ring, int budget, /* Poll one pkt */ err = hns3_handle_rx_bd(ring); + if (unlikely(err == -ENOMEM)) + failure = true; + /* Do not get FE for the packet or failed to alloc skb */ if (unlikely(!ring->skb || err == -ENXIO)) { goto out; @@ -4493,7 +4528,10 @@ int hns3_clean_rx_ring(struct hns3_enet_ring *ring, int budget, failure = failure || hns3_nic_alloc_rx_buffers(ring, unused_count); - return failure ? budget : recv_pkts; + if (unlikely(failure || hns3_ring_is_oom_state(ring))) + hns3_oom_task_schedule(ring); + + return recv_pkts; } static void hns3_update_rx_int_coalesce(struct hns3_enet_tqp_vector *tqp_vector) @@ -4788,6 +4826,7 @@ static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv) hns3_nic_common_poll); } + INIT_DELAYED_WORK(&priv->oom_task, hns3_oom_task); return 0; map_ring_fail: @@ -4865,9 +4904,18 @@ static int hns3_nic_alloc_vector_data(struct hns3_nic_priv *priv) hns3_vector_coalesce_init(tqp_vector, priv); } + priv->oom_vector_bm = bitmap_zalloc(vector_num, GFP_KERNEL); + if (!priv->oom_vector_bm) { + ret = -ENOMEM; + goto err_free_tqp_vector; + } + devm_kfree(&pdev->dev, vector); return 0; +err_free_tqp_vector: + devm_kfree(&pdev->dev, priv->tqp_vector); + priv->tqp_vector = NULL; err_put_vector: for (i = 0; i < vector_num; i++) h->ae_algo->ops->put_vector(h, vector[i].vector); @@ -4889,6 +4937,7 @@ static void hns3_nic_uninit_vector_data(struct hns3_nic_priv *priv) struct hns3_enet_tqp_vector *tqp_vector; int i; + cancel_delayed_work_sync(&priv->oom_task); for (i = 0; i < priv->vector_num; i++) { tqp_vector = &priv->tqp_vector[i]; @@ -4920,6 +4969,7 @@ static void hns3_nic_dealloc_vector_data(struct hns3_nic_priv *priv) struct pci_dev *pdev = h->pdev; int i, ret; + bitmap_free(priv->oom_vector_bm); for (i = 0; i < priv->vector_num; i++) { struct hns3_enet_tqp_vector *tqp_vector; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 933e3527ed82..27a09629cbca 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -449,6 +449,7 @@ struct ring_stats { u64 non_reuse_pg; u64 frag_alloc_err; u64 frag_alloc; + u64 rx_oom_cnt; }; __le16 csum; }; @@ -585,6 +586,8 @@ struct hns3_nic_priv { struct hns3_enet_tqp_vector *tqp_vector; u16 vector_num; u8 max_non_tso_bd_num; + struct delayed_work oom_task; + unsigned long *oom_vector_bm; u64 tx_timeout_count; @@ -711,6 +714,20 @@ static inline unsigned int hns3_page_order(struct hns3_enet_ring *ring) #define hns3_rl_usec_to_reg(int_rl) ((int_rl) >> 2) #define hns3_rl_round_down(int_rl) round_down(int_rl, 4) +static inline void hns3_ring_set_oom_state(struct hns3_enet_ring *ring) +{ + struct hns3_nic_priv *priv = netdev_priv(ring_to_netdev(ring)); + + set_bit(ring->tqp_vector->idx, priv->oom_vector_bm); +} + +static inline bool hns3_ring_is_oom_state(struct hns3_enet_ring *ring) +{ + struct hns3_nic_priv *priv = netdev_priv(ring_to_netdev(ring)); + + return test_bit(ring->tqp_vector->idx, priv->oom_vector_bm); +} + void hns3_ethtool_set_ops(struct net_device *netdev); int hns3_set_channels(struct net_device *netdev, struct ethtool_channels *ch); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index e7318f236315..392653635bda 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -62,6 +62,7 @@ static const struct hns3_stats hns3_rxq_stats[] = { HNS3_TQP_STAT("non_reuse_pg", non_reuse_pg), HNS3_TQP_STAT("frag_alloc_err", frag_alloc_err), HNS3_TQP_STAT("frag_alloc", frag_alloc), + HNS3_TQP_STAT("rx_oom_cnt", rx_oom_cnt), }; #define HNS3_PRIV_FLAGS_LEN ARRAY_SIZE(hns3_priv_flags) -- 2.43.0 The seq_file refactoring of hns3 debugfs removed the per-file entry state checks. Without them, debugfs show callbacks can access priv->ring, priv->tqp_vector, and ring->desc while these resources are being freed by reset, driver unload, or ethtool ring resize. Plain state-bit checks leave a TOCTOU window between check and use. Fix by adding a mutex (dbg_mutex) to struct hnae3_handle, shared by enet-layer and PF-layer debugfs callbacks via the common handle. Readers acquire the mutex and check device state at entry and per iteration -- the latter lets an in-flight reader exit promptly when reset begins mid-dump, keeping reset latency bounded. Writers clear INITED first to signal readers, then acquire the mutex before freeing resources. The dbg_uninit() call stays outside the mutex to avoid deadlock with debugfs_remove_recursive. Fixes: eced3d1c41db ("net: hns3: use seq_file for files in queue/ in debugfs") Closes: https://lore.kernel.org/all/a0853cd9-cab5-441d-b181-8ba97f2f58b0@huawei.com/ Signed-off-by: Jijie Shao --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 + .../ethernet/hisilicon/hns3/hns3_debugfs.c | 95 +++++++++++-------- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 6 ++ .../ethernet/hisilicon/hns3/hns3_ethtool.c | 1 + .../hisilicon/hns3/hns3pf/hclge_debugfs.c | 14 +++ 5 files changed, 77 insertions(+), 40 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 4286af9239b0..e94cc33da864 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -944,6 +944,7 @@ struct hnae3_handle { u8 netdev_flags; struct dentry *hnae3_dbgfs; + struct mutex dbg_mutex; /* protect debugfs against reset/unload */ /* Network interface message level enabled bits */ u32 msg_enable; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index 1347edac7699..7d913302f442 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -389,6 +389,12 @@ static const char * const dim_state_str[] = { "START", "IN_PROG", "APPLY" }; static const char * const dim_tune_stat_str[] = { "ON_TOP", "TIRED", "RIGHT", "LEFT" }; +static bool hns3_dbg_is_device_busy(struct hns3_nic_priv *priv) +{ + return !test_bit(HNS3_NIC_STATE_INITED, &priv->state) || + test_bit(HNS3_NIC_STATE_RESETTING, &priv->state); +} + static void hns3_get_coal_info(struct hns3_enet_tqp_vector *tqp_vector, struct seq_file *s, int i, bool is_tx) { @@ -434,7 +440,7 @@ static void hns3_get_coal_info(struct hns3_enet_tqp_vector *tqp_vector, } } -static void hns3_dump_coal_info(struct seq_file *s, bool is_tx) +static int hns3_dump_coal_info(struct seq_file *s, bool is_tx) { struct hnae3_handle *h = hnae3_seq_file_to_handle(s); struct hns3_enet_tqp_vector *tqp_vector; @@ -448,18 +454,32 @@ static void hns3_dump_coal_info(struct seq_file *s, bool is_tx) seq_puts(s, "HW_GL HW_QL\n"); for (i = 0; i < priv->vector_num; i++) { + if (hns3_dbg_is_device_busy(priv)) + return -EBUSY; + tqp_vector = &priv->tqp_vector[i]; hns3_get_coal_info(tqp_vector, s, i, is_tx); } + + return 0; } static int hns3_dbg_coal_info(struct seq_file *s, void *data) { - hns3_dump_coal_info(s, true); - seq_puts(s, "\n"); - hns3_dump_coal_info(s, false); + struct hnae3_handle *h = hnae3_seq_file_to_handle(s); + struct hns3_nic_priv *priv = h->priv; + int ret; - return 0; + guard(mutex)(&priv->ae_handle->dbg_mutex); + if (hns3_dbg_is_device_busy(priv)) + return -EBUSY; + + ret = hns3_dump_coal_info(s, true); + if (ret) + return ret; + + seq_puts(s, "\n"); + return hns3_dump_coal_info(s, false); } static void hns3_dump_rx_queue_info(struct hns3_enet_ring *ring, @@ -504,22 +524,16 @@ static int hns3_dbg_rx_queue_info(struct seq_file *s, void *data) struct hns3_enet_ring *ring; u32 i; - if (!priv->ring) { - dev_err(&h->pdev->dev, "priv->ring is NULL\n"); - return -EFAULT; - } + guard(mutex)(&priv->ae_handle->dbg_mutex); + if (hns3_dbg_is_device_busy(priv)) + return -EBUSY; seq_puts(s, "QUEUE_ID BD_NUM BD_LEN TAIL HEAD FBDNUM "); seq_puts(s, "PKTNUM COPYBREAK RING_EN RX_RING_EN BASE_ADDR\n"); for (i = 0; i < h->kinfo.num_tqps; i++) { - /* Each cycle needs to determine whether the instance is reset, - * to prevent reference to invalid memory. And need to ensure - * that the following code is executed within 100ms. - */ - if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) || - test_bit(HNS3_NIC_STATE_RESETTING, &priv->state)) - return -EPERM; + if (hns3_dbg_is_device_busy(priv)) + return -EBUSY; ring = &priv->ring[(u32)(i + h->kinfo.num_tqps)]; hns3_dump_rx_queue_info(ring, s, i); @@ -569,22 +583,16 @@ static int hns3_dbg_tx_queue_info(struct seq_file *s, void *data) struct hns3_enet_ring *ring; u32 i; - if (!priv->ring) { - dev_err(&h->pdev->dev, "priv->ring is NULL\n"); - return -EFAULT; - } + guard(mutex)(&priv->ae_handle->dbg_mutex); + if (hns3_dbg_is_device_busy(priv)) + return -EBUSY; seq_puts(s, "QUEUE_ID BD_NUM TC TAIL HEAD FBDNUM OFFSET "); seq_puts(s, "PKTNUM RING_EN TX_RING_EN BASE_ADDR\n"); for (i = 0; i < h->kinfo.num_tqps; i++) { - /* Each cycle needs to determine whether the instance is reset, - * to prevent reference to invalid memory. And need to ensure - * that the following code is executed within 100ms. - */ - if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) || - test_bit(HNS3_NIC_STATE_RESETTING, &priv->state)) - return -EPERM; + if (hns3_dbg_is_device_busy(priv)) + return -EBUSY; ring = &priv->ring[i]; hns3_dump_tx_queue_info(ring, s, i); @@ -604,9 +612,14 @@ static int hns3_dbg_queue_map(struct seq_file *s, void *data) seq_puts(s, "local_queue_id global_queue_id vector_id\n"); + guard(mutex)(&priv->ae_handle->dbg_mutex); + if (hns3_dbg_is_device_busy(priv)) + return -EBUSY; + for (i = 0; i < h->kinfo.num_tqps; i++) { - if (!priv->ring || !priv->ring[i].tqp_vector) - continue; + if (hns3_dbg_is_device_busy(priv)) + return -EBUSY; + seq_printf(s, "%-16u%-17u%d\n", i, h->ae_algo->ops->get_global_queue_id(h, i), priv->ring[i].tqp_vector->vector_irq); @@ -661,8 +674,10 @@ static int hns3_dbg_rx_bd_info(struct seq_file *s, void *private) ring = &priv->ring[data->qid + data->handle->kinfo.num_tqps]; for (i = 0; i < ring->desc_num; i++) { - desc = &ring->desc[i]; + if (hns3_dbg_is_device_busy(priv)) + return -EBUSY; + desc = &ring->desc[i]; hns3_dump_rx_bd_info(priv, desc, s, i); } @@ -706,8 +721,10 @@ static int hns3_dbg_tx_bd_info(struct seq_file *s, void *private) ring = &priv->ring[data->qid]; for (i = 0; i < ring->desc_num; i++) { - desc = &ring->desc[i]; + if (hns3_dbg_is_device_busy(priv)) + return -EBUSY; + desc = &ring->desc[i]; hns3_dump_tx_bd_info(desc, s, i); } @@ -796,10 +813,9 @@ static int hns3_dbg_page_pool_info(struct seq_file *s, void *data) struct hns3_enet_ring *ring; u32 i; - if (!priv->ring) { - dev_err(&h->pdev->dev, "priv->ring is NULL\n"); - return -EFAULT; - } + guard(mutex)(&priv->ae_handle->dbg_mutex); + if (hns3_dbg_is_device_busy(priv)) + return -EBUSY; if (!priv->ring[h->kinfo.num_tqps].page_pool) { dev_err(&h->pdev->dev, "page pool is not initialized\n"); @@ -810,9 +826,8 @@ static int hns3_dbg_page_pool_info(struct seq_file *s, void *data) seq_puts(s, "POOL_SIZE(PAGE_NUM) ORDER NUMA_ID MAX_LEN\n"); for (i = 0; i < h->kinfo.num_tqps; i++) { - if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) || - test_bit(HNS3_NIC_STATE_RESETTING, &priv->state)) - return -EPERM; + if (hns3_dbg_is_device_busy(priv)) + return -EBUSY; ring = &priv->ring[(u32)(i + h->kinfo.num_tqps)]; hns3_dump_page_pool_info(ring, s, i); @@ -827,8 +842,8 @@ static int hns3_dbg_bd_info_show(struct seq_file *s, void *private) struct hnae3_handle *h = data->handle; struct hns3_nic_priv *priv = h->priv; - if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) || - test_bit(HNS3_NIC_STATE_RESETTING, &priv->state)) + guard(mutex)(&priv->ae_handle->dbg_mutex); + if (hns3_dbg_is_device_busy(priv)) return -EBUSY; if (data->cmd == HNAE3_DBG_CMD_TX_BD) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 0c088feae03c..bae8b32ffc5b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -5449,6 +5449,7 @@ static int hns3_client_init(struct hnae3_handle *handle) priv->min_tx_copybreak = 0; priv->min_tx_spare_buf_size = 0; set_bit(HNS3_NIC_STATE_DOWN, &priv->state); + mutex_init(&handle->dbg_mutex); handle->msg_enable = netif_msg_init(debug, DEFAULT_MSG_LEVEL); @@ -5562,6 +5563,7 @@ static int hns3_client_init(struct hnae3_handle *handle) priv->ring = NULL; out_get_ring_cfg: priv->ae_handle = NULL; + mutex_destroy(&handle->dbg_mutex); free_netdev(netdev); return ret; } @@ -5585,6 +5587,7 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset) hns3_free_rx_cpu_rmap(netdev); + mutex_lock(&handle->dbg_mutex); hns3_nic_uninit_irq(priv); hns3_clear_all_ring(handle, true); @@ -5596,9 +5599,11 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset) hns3_uninit_all_ring(priv); hns3_put_ring_config(priv); + mutex_unlock(&handle->dbg_mutex); out_netdev_free: hns3_dbg_uninit(handle); + mutex_destroy(&handle->dbg_mutex); free_netdev(netdev); } @@ -5875,6 +5880,7 @@ static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle) return 0; } + guard(mutex)(&handle->dbg_mutex); hns3_free_rx_cpu_rmap(netdev); hns3_nic_uninit_irq(priv); hns3_clear_all_ring(handle, true); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 392653635bda..4e7a7e6b21ee 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -1258,6 +1258,7 @@ static int hns3_set_ringparam(struct net_device *ndev, if (if_running) ndev->netdev_ops->ndo_stop(ndev); + guard(mutex)(&h->dbg_mutex); hns3_change_all_ring_bd_num(priv, new_ringparam.tx_desc_num, new_ringparam.rx_desc_num); hns3_change_rx_buf_len(ndev, new_ringparam.rx_buf_len); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index 9a4e29bfa166..1e9d3e08b7de 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -15,6 +15,12 @@ #define hclge_seq_file_to_hdev(s) \ (((struct hnae3_ae_dev *)hnae3_seq_file_to_ae_dev(s))->priv) +static bool hclge_dbg_is_device_busy(struct hclge_dev *hdev) +{ + return test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) || + test_bit(HCLGE_STATE_RST_FAIL, &hdev->state); +} + static const char * const hclge_mac_state_str[] = { "TO_ADD", "TO_DEL", "ACTIVE" }; @@ -2621,6 +2627,10 @@ static int hclge_dbg_dump_umv_info(struct seq_file *s, void *data) struct hclge_vport *vport; u8 i; + guard(mutex)(&hdev->vport[0].nic.dbg_mutex); + if (hclge_dbg_is_device_busy(hdev)) + return -EBUSY; + seq_printf(s, "num_alloc_vport : %u\n", hdev->num_alloc_vport); seq_printf(s, "max_umv_size : %u\n", hdev->max_umv_size); seq_printf(s, "wanted_umv_size : %u\n", hdev->wanted_umv_size); @@ -2831,6 +2841,10 @@ static int hclge_dbg_dump_vlan_offload_config(struct hclge_dev *hdev, int ret; u8 i; + guard(mutex)(&hdev->vport[0].nic.dbg_mutex); + if (hclge_dbg_is_device_busy(hdev)) + return -EBUSY; + seq_puts(s, "FUNC_ID PVID ACCEPT_TAG1 ACCEPT_TAG2 ACCEPT_UNTAG1 "); seq_puts(s, "ACCEPT_UNTAG2 INSERT_TAG1 INSERT_TAG2 SHIFT_TAG "); seq_puts(s, "STRIP_TAG1 STRIP_TAG2 DROP_TAG1 DROP_TAG2 "); -- 2.43.0