[PATCH v2 1/2] net/mlx5: check for no data read in devx interrupt

Kevin Traynor
2026-02-06T17:21:24Z

A busy-loop may occur when there are EPOLLERR, EPOLLHUP or
EPOLLRDHUP epoll events for the devx interrupt fd.

This may happen if the interrupt fd is deleted, if the device
is unbound from mlx5_core kernel driver or if the device is
removed by the mlx5 kernel driver as part of LAG setup.

When that occurs, there is no data to be read and in the devx
interrupt handler an EAGAIN is returned on the first call to
devx_get_async_cmd_comp, but this is not checked.

As the interrupt is not removed or condition reset, it causes
an interrupt processing busy-loop, which leads to the dpdk-intr
thread going to 100% CPU.

e.g.
epoll_wait
(6, [{events=EPOLLIN|EPOLLRDHUP, data={u32=28, u64=28}}], 8, -1) = 1
read(28, 0x7f1f5c7fc2f0, 40)
= -1 EAGAIN (Resource temporarily unavailable)
epoll_wait
(6, [{events=EPOLLIN|EPOLLRDHUP, data={u32=28, u64=28}}], 8, -1) = 1
read(28, 0x7f1f5c7fc2f0, 40)
= -1 EAGAIN (Resource temporarily unavailable)

Add a check for an EAGAIN return from devx_get_async_cmd_comp on the
first read. If that happens, unregister the callback to prevent looping.

Bugzilla ID: 1873
Fixes: f15db67df09c ("net/mlx5: accelerate DV flow counter query")
Cc: stable@dpdk.org

Signed-off-by: Kevin Traynor <ktraynor@redhat.com>
---
drivers/net/mlx5/linux/mlx5_ethdev_os.c | 34 ++++++++++++++++++++-----
1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/drivers/net/mlx5/linux/mlx5_ethdev_os.c b/drivers/net/mlx5/linux/mlx5_ethdev_os.c
index 50997c187c..18b0baee04 100644
--- a/drivers/net/mlx5/linux/mlx5_ethdev_os.c
+++ b/drivers/net/mlx5/linux/mlx5_ethdev_os.c
@@ -859,11 +859,33 @@ mlx5_dev_interrupt_handler_devx(void *cb_arg)
} out;
uint8_t *buf = out.buf + sizeof(out.cmd_resp);
+ bool data_read = false;
+ int ret;

- while (!mlx5_glue->devx_get_async_cmd_comp(sh->devx_comp,
- &out.cmd_resp,
- sizeof(out.buf)))
- mlx5_flow_async_pool_query_handle
- (sh, (uint64_t)out.cmd_resp.wr_id,
- mlx5_devx_get_out_command_status(buf));
+ while (!(ret = mlx5_glue->devx_get_async_cmd_comp(sh->devx_comp,
+ &out.cmd_resp,
+ sizeof(out.buf)))) {
+ data_read = true;
+ mlx5_flow_async_pool_query_handle(sh,
+ (uint64_t)out.cmd_resp.wr_id,
+ mlx5_devx_get_out_command_status(buf));
+ };
+
+ if (!data_read && ret == EAGAIN) {
+ /**
+ * no data and EAGAIN indicate there is an error or
+ * disconnect state. Unregister callback to prevent
+ * interrupt busy-looping.
+ */
+ DRV_LOG(DEBUG, "no data for mlx5 devx interrupt on fd %d",
+ rte_intr_fd_get(sh->intr_handle_devx));
+
+ if (rte_intr_callback_unregister_pending(sh->intr_handle_devx,
+ mlx5_dev_interrupt_handler_devx,
+ (void *)sh, NULL) < 0) {
+ DRV_LOG(WARNING,
+ "unable to unregister mlx5 devx interrupt callback on fd %d",
+ rte_intr_fd_get(sh->intr_handle_devx));
+ }
+ }
#endif /* HAVE_IBV_DEVX_ASYNC */
}
--
2.52.0