* [RFC v3 0/5] Interrupts API update
@ 2026-09-07 12:13 David Marchand
2026-09-07 12:13 ` [RFC v3 1/5] vdpa/mlx5: fix check on err interrupt FD David Marchand
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: David Marchand @ 2026-09-07 12:13 UTC (permalink / raw)
To: dev, hkalra
This series is a simple cleanup to have a simpler helper that close all
FD reference in an interrupt handle.
It helped catch one small FD leak in FreeBSD EAL.
This should make life (a bit) easier on driver side and help limit FD
leaks.
--
David Marchand
Changes since RFC v2:
- added unit test for the new API,
- caught some FD leak by code review,
- split patch 3 from v2 in two, and added one debug check (see patch 5),
Changes since RFC v1:
- squashed FreeBSD PCI change,
- updated interrupt unit test,
David Marchand (5):
vdpa/mlx5: fix check on err interrupt FD
eal/freebsd: fix a FD leak in the alarm subsystem
interrupts: mark file descriptors invalid on allocation
interrupts: close interrupt FDs
interrupts: warn on leaked file descriptors
app/test/test_interrupts.c | 89 ++++++++++++++++++-
doc/guides/rel_notes/release_26_11.rst | 7 ++
drivers/bus/cdx/cdx_vfio.c | 16 ++--
drivers/bus/pci/bsd/pci.c | 7 +-
drivers/bus/pci/linux/pci_uio.c | 15 +---
drivers/bus/pci/linux/pci_vfio.c | 29 ++----
drivers/bus/pci/pci_common_uio.c | 18 +---
drivers/bus/vmbus/linux/vmbus_uio.c | 13 +--
drivers/bus/vmbus/vmbus_common_uio.c | 17 +---
drivers/common/cnxk/roc_platform.h | 2 +
drivers/common/mlx5/linux/mlx5_common_os.c | 6 +-
drivers/net/failsafe/failsafe.c | 3 -
drivers/net/mana/mana.c | 5 +-
drivers/net/memif/memif_socket.c | 13 +--
drivers/net/memif/rte_eth_memif.c | 6 --
drivers/net/mlx4/mlx4.c | 3 -
drivers/net/mlx4/mlx4_intr.c | 1 +
drivers/net/sxe2/sxe2_irq.c | 5 +-
drivers/net/tap/rte_eth_tap.c | 2 +-
.../net/virtio/virtio_user/virtio_user_dev.c | 2 +
drivers/raw/cnxk_gpio/cnxk_gpio.c | 3 +
drivers/vdpa/mlx5/mlx5_vdpa_event.c | 6 +-
drivers/vdpa/mlx5/mlx5_vdpa_virtq.c | 1 +
lib/eal/common/eal_common_interrupts.c | 35 ++++++++
lib/eal/freebsd/eal_alarm.c | 8 +-
lib/eal/include/rte_interrupts.h | 29 ++++++
lib/eal/linux/eal_dev.c | 9 +-
27 files changed, 211 insertions(+), 139 deletions(-)
--
2.54.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC v3 1/5] vdpa/mlx5: fix check on err interrupt FD
2026-09-07 12:13 [RFC v3 0/5] Interrupts API update David Marchand
@ 2026-09-07 12:13 ` David Marchand
2026-09-07 12:13 ` [RFC v3 2/5] eal/freebsd: fix a FD leak in the alarm subsystem David Marchand
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: David Marchand @ 2026-09-07 12:13 UTC (permalink / raw)
To: dev, hkalra
Cc: Matan Azrad, Viacheslav Ovsiienko, Maxime Coquelin, Xueming Li
A 0 file descriptor is valid.
Prefer setting to -1 to indicate an invalid FD.
Fixes: 0474419bae7c ("vdpa/mlx5: handle hardware error")
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/vdpa/mlx5/mlx5_vdpa_event.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/vdpa/mlx5/mlx5_vdpa_event.c b/drivers/vdpa/mlx5/mlx5_vdpa_event.c
index 43585a94b2..dee2ccc23d 100644
--- a/drivers/vdpa/mlx5/mlx5_vdpa_event.c
+++ b/drivers/vdpa/mlx5/mlx5_vdpa_event.c
@@ -452,7 +452,7 @@ mlx5_vdpa_err_event_setup(struct mlx5_vdpa_priv *priv)
mlx5_vdpa_err_interrupt_handler,
priv);
if (ret != 0) {
- rte_intr_fd_set(priv->err_intr_handle, 0);
+ rte_intr_fd_set(priv->err_intr_handle, -1);
DRV_LOG(ERR, "Failed to register error interrupt for device %d.",
priv->vid);
rte_errno = -ret;
@@ -473,7 +473,7 @@ mlx5_vdpa_err_event_unset(struct mlx5_vdpa_priv *priv)
int retries = MLX5_VDPA_INTR_RETRIES;
int ret = -EAGAIN;
- if (!rte_intr_fd_get(priv->err_intr_handle))
+ if (rte_intr_fd_get(priv->err_intr_handle) < 0)
return;
while (retries-- && ret == -EAGAIN) {
ret = rte_intr_callback_unregister(priv->err_intr_handle,
@@ -487,6 +487,7 @@ mlx5_vdpa_err_event_unset(struct mlx5_vdpa_priv *priv)
rte_pause();
}
}
+ rte_intr_fd_set(priv->err_intr_handle, -1);
if (priv->err_chnl) {
#ifdef HAVE_IBV_DEVX_EVENT
union {
--
2.54.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [RFC v3 2/5] eal/freebsd: fix a FD leak in the alarm subsystem
2026-09-07 12:13 [RFC v3 0/5] Interrupts API update David Marchand
2026-09-07 12:13 ` [RFC v3 1/5] vdpa/mlx5: fix check on err interrupt FD David Marchand
@ 2026-09-07 12:13 ` David Marchand
2026-09-07 12:35 ` Bruce Richardson
2026-09-07 12:13 ` [RFC v3 3/5] interrupts: mark file descriptors invalid on allocation David Marchand
` (2 subsequent siblings)
4 siblings, 1 reply; 8+ messages in thread
From: David Marchand @ 2026-09-07 12:13 UTC (permalink / raw)
To: dev, hkalra; +Cc: stable, Bruce Richardson, Anatoly Burakov
Caught by code review, while looking at rte_intr_instance_free() users.
Even if the FD is not used, it must still be closed when uninitialising
the alarm subsystem.
Fixes: 26021a715067 ("eal/bsd: support alarm API")
Cc: stable@dpdk.org
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
lib/eal/freebsd/eal_alarm.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/lib/eal/freebsd/eal_alarm.c b/lib/eal/freebsd/eal_alarm.c
index c03e281e67..2905841b5e 100644
--- a/lib/eal/freebsd/eal_alarm.c
+++ b/lib/eal/freebsd/eal_alarm.c
@@ -54,6 +54,8 @@ rte_eal_alarm_cleanup(void)
int ret = rte_intr_callback_unregister_sync(intr_handle,
eal_alarm_callback, (void *)-1);
if (ret >= 0) {
+ close(rte_intr_fd_get(intr_handle));
+ rte_intr_fd_set(intr_handle, -1);
rte_intr_instance_free(intr_handle);
intr_handle = NULL;
}
@@ -62,7 +64,7 @@ rte_eal_alarm_cleanup(void)
int
rte_eal_alarm_init(void)
{
- int fd;
+ int fd = -1;
intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
if (intr_handle == NULL) {
@@ -88,6 +90,8 @@ rte_eal_alarm_init(void)
return 0;
error:
+ if (fd >= 0)
+ close(fd);
rte_intr_instance_free(intr_handle);
return -1;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [RFC v3 3/5] interrupts: mark file descriptors invalid on allocation
2026-09-07 12:13 [RFC v3 0/5] Interrupts API update David Marchand
2026-09-07 12:13 ` [RFC v3 1/5] vdpa/mlx5: fix check on err interrupt FD David Marchand
2026-09-07 12:13 ` [RFC v3 2/5] eal/freebsd: fix a FD leak in the alarm subsystem David Marchand
@ 2026-09-07 12:13 ` David Marchand
2026-09-07 12:13 ` [RFC v3 4/5] interrupts: close interrupt FDs David Marchand
2026-09-07 12:13 ` [RFC v3 5/5] interrupts: warn on leaked file descriptors David Marchand
4 siblings, 0 replies; 8+ messages in thread
From: David Marchand @ 2026-09-07 12:13 UTC (permalink / raw)
To: dev, hkalra
Cc: Nipun Gupta, Nikhil Agarwal, Chenbo Xia, Anatoly Burakov, Long Li,
Wei Hu, Gaetan Rivet, Jakub Grajciar, Matan Azrad,
Viacheslav Ovsiienko, Stephen Hemminger, Bruce Richardson
Initialize fd, dev_fd, and all efds array elements as invalid in
rte_intr_instance_alloc().
This follows Unix convention, avoiding confusion with fd 0
which could result from zero-initialization.
Update the API documentation to reflect this behavior and add a
unit test check to verify the fd is invalid after allocation.
Update the FreeBSD PCI implementation that checked against a 0 FD.
Add a hack in the unit test to let the UIO simulated tests pass.
Remove now-redundant initialization calls that were setting the fd
invalid right after allocation.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
Changes since RFC v1:
- squashed FreeBSD PCI update,
- updated unit test,
---
app/test/test_interrupts.c | 12 ++++++++++--
doc/guides/rel_notes/release_26_11.rst | 5 +++++
drivers/bus/cdx/cdx_vfio.c | 6 ------
drivers/bus/pci/bsd/pci.c | 2 +-
drivers/bus/pci/linux/pci_vfio.c | 11 -----------
drivers/bus/pci/pci_common_uio.c | 6 ------
drivers/bus/vmbus/vmbus_common_uio.c | 6 ------
drivers/net/failsafe/failsafe.c | 3 ---
drivers/net/mana/mana.c | 4 ----
drivers/net/memif/rte_eth_memif.c | 6 ------
drivers/net/mlx4/mlx4.c | 3 ---
drivers/net/tap/rte_eth_tap.c | 1 -
lib/eal/common/eal_common_interrupts.c | 6 ++++++
lib/eal/freebsd/eal_alarm.c | 3 ---
lib/eal/include/rte_interrupts.h | 2 ++
lib/eal/linux/eal_dev.c | 4 ----
16 files changed, 24 insertions(+), 56 deletions(-)
diff --git a/app/test/test_interrupts.c b/app/test/test_interrupts.c
index 3a5be92cd7..747dfc4f48 100644
--- a/app/test/test_interrupts.c
+++ b/app/test/test_interrupts.c
@@ -73,11 +73,13 @@ test_interrupt_init(void)
rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
if (!intr_handles[i])
return -1;
+ if (rte_intr_fd_get(intr_handles[i]) != -1)
+ return -1;
+ if (rte_intr_dev_fd_get(intr_handles[i]) != -1)
+ return -1;
}
test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
- if (rte_intr_fd_set(test_intr_handle, -1))
- return -1;
if (rte_intr_type_set(test_intr_handle, RTE_INTR_HANDLE_UNKNOWN))
return -1;
@@ -90,6 +92,9 @@ test_interrupt_init(void)
test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO];
if (rte_intr_fd_set(test_intr_handle, pfds.readfd))
return -1;
+ /* HACK: UIO type does not require a device FD, but a valid handle should contain one */
+ if (rte_intr_dev_fd_set(test_intr_handle, INT_MAX))
+ return -1;
if (rte_intr_type_set(test_intr_handle, RTE_INTR_HANDLE_UIO))
return -1;
@@ -108,6 +113,9 @@ test_interrupt_init(void)
test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1];
if (rte_intr_fd_set(test_intr_handle, pfds.writefd))
return -1;
+ /* HACK: UIO type does not require a device FD, but a valid handle should contain one */
+ if (rte_intr_dev_fd_set(test_intr_handle, INT_MAX))
+ return -1;
if (rte_intr_type_set(test_intr_handle, RTE_INTR_HANDLE_UIO))
return -1;
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 87c7e81bde..36d6f3a05f 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -95,6 +95,11 @@ API Changes
Also, make sure to start the actual text at the margin.
=======================================================
+* interrupts: Updated interrupt handle file descriptor management.
+
+ * ``rte_intr_instance_alloc()`` now initializes file descriptors
+ to invalid values instead of zero.
+
ABI Changes
-----------
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..0e4af4e940 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -397,9 +397,6 @@ cdx_vfio_map_resource_primary(struct rte_cdx_device *dev)
struct cdx_map *maps;
int vfio_dev_fd, i, ret;
- if (rte_intr_fd_set(dev->intr_handle, -1))
- return -1;
-
ret = rte_vfio_setup_device(RTE_CDX_BUS_DEVICES_PATH, dev_name,
&vfio_dev_fd, &device_info);
if (ret)
@@ -493,9 +490,6 @@ cdx_vfio_map_resource_secondary(struct rte_cdx_device *dev)
const char *dev_name = dev->device.name;
struct cdx_map *maps;
- if (rte_intr_fd_set(dev->intr_handle, -1))
- return -1;
-
/* if we're in a secondary process, just find our tailq entry */
TAILQ_FOREACH(vfio_res, vfio_res_list, next) {
if (strcmp(vfio_res->name, dev_name))
diff --git a/drivers/bus/pci/bsd/pci.c b/drivers/bus/pci/bsd/pci.c
index c6df31d486..bbe08605af 100644
--- a/drivers/bus/pci/bsd/pci.c
+++ b/drivers/bus/pci/bsd/pci.c
@@ -93,7 +93,7 @@ pci_uio_free_resource(struct rte_pci_device *dev,
{
rte_free(uio_res);
- if (rte_intr_fd_get(dev->intr_handle)) {
+ if (rte_intr_fd_get(dev->intr_handle) >= 0) {
close(rte_intr_fd_get(dev->intr_handle));
rte_intr_fd_set(dev->intr_handle, -1);
rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
diff --git a/drivers/bus/pci/linux/pci_vfio.c b/drivers/bus/pci/linux/pci_vfio.c
index bc5c5c2499..a92a0d86ec 100644
--- a/drivers/bus/pci/linux/pci_vfio.c
+++ b/drivers/bus/pci/linux/pci_vfio.c
@@ -742,12 +742,6 @@ pci_vfio_map_resource_primary(struct rte_pci_device *dev)
struct pci_map *maps;
- if (rte_intr_fd_set(dev->intr_handle, -1))
- return -1;
-
- if (rte_intr_fd_set(dev->vfio_req_intr_handle, -1))
- return -1;
-
/* store PCI address string */
snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
loc->domain, loc->bus, loc->devid, loc->function);
@@ -939,11 +933,6 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev)
struct pci_map *maps;
- if (rte_intr_fd_set(dev->intr_handle, -1))
- return -1;
- if (rte_intr_fd_set(dev->vfio_req_intr_handle, -1))
- return -1;
-
/* store PCI address string */
snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
loc->domain, loc->bus, loc->devid, loc->function);
diff --git a/drivers/bus/pci/pci_common_uio.c b/drivers/bus/pci/pci_common_uio.c
index 71974e9f56..47d50721dc 100644
--- a/drivers/bus/pci/pci_common_uio.c
+++ b/drivers/bus/pci/pci_common_uio.c
@@ -101,12 +101,6 @@ pci_uio_map_resource(struct rte_pci_device *dev)
struct mapped_pci_res_list *uio_res_list =
RTE_TAILQ_CAST(rte_uio_tailq.head, mapped_pci_res_list);
- if (rte_intr_fd_set(dev->intr_handle, -1))
- return -1;
-
- if (rte_intr_dev_fd_set(dev->intr_handle, -1))
- return -1;
-
/* allocate uio resource */
ret = pci_uio_alloc_resource(dev, &uio_res);
if (ret)
diff --git a/drivers/bus/vmbus/vmbus_common_uio.c b/drivers/bus/vmbus/vmbus_common_uio.c
index c6e7e07302..7459f4ea7a 100644
--- a/drivers/bus/vmbus/vmbus_common_uio.c
+++ b/drivers/bus/vmbus/vmbus_common_uio.c
@@ -173,12 +173,6 @@ vmbus_uio_map_resource(struct rte_vmbus_device *dev)
int ret;
/* TODO: handle rescind */
- if (rte_intr_fd_set(dev->intr_handle, -1))
- return -1;
-
- if (rte_intr_dev_fd_set(dev->intr_handle, -1))
- return -1;
-
if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN))
return -1;
diff --git a/drivers/net/failsafe/failsafe.c b/drivers/net/failsafe/failsafe.c
index aa3fe53b22..3ba143924d 100644
--- a/drivers/net/failsafe/failsafe.c
+++ b/drivers/net/failsafe/failsafe.c
@@ -279,9 +279,6 @@ fs_eth_dev_create(struct rte_vdev_device *vdev)
goto cancel_alarm;
}
- if (rte_intr_fd_set(PRIV(dev)->intr_handle, -1))
- goto cancel_alarm;
-
if (rte_intr_type_set(PRIV(dev)->intr_handle, RTE_INTR_HANDLE_EXT))
goto cancel_alarm;
diff --git a/drivers/net/mana/mana.c b/drivers/net/mana/mana.c
index 0b72f711a1..1864ba2a2b 100644
--- a/drivers/net/mana/mana.c
+++ b/drivers/net/mana/mana.c
@@ -1946,10 +1946,6 @@ mana_intr_install(struct rte_eth_dev *eth_dev, struct mana_priv *priv)
return -ENOMEM;
}
- ret = rte_intr_fd_set(priv->intr_handle, -1);
- if (ret)
- goto free_intr;
-
ret = mana_fd_set_non_blocking(ctx->async_fd);
if (ret) {
DRV_LOG(ERR, "Failed to change async_fd to NONBLOCK");
diff --git a/drivers/net/memif/rte_eth_memif.c b/drivers/net/memif/rte_eth_memif.c
index 5d153c3a5a..04e12b8ffa 100644
--- a/drivers/net/memif/rte_eth_memif.c
+++ b/drivers/net/memif/rte_eth_memif.c
@@ -1496,9 +1496,6 @@ memif_tx_queue_setup(struct rte_eth_dev *dev,
mq->n_pkts = 0;
mq->n_bytes = 0;
- if (rte_intr_fd_set(mq->intr_handle, -1))
- return -rte_errno;
-
if (rte_intr_type_set(mq->intr_handle, RTE_INTR_HANDLE_EXT))
return -rte_errno;
@@ -1536,9 +1533,6 @@ memif_rx_queue_setup(struct rte_eth_dev *dev,
mq->n_pkts = 0;
mq->n_bytes = 0;
- if (rte_intr_fd_set(mq->intr_handle, -1))
- return -rte_errno;
-
if (rte_intr_type_set(mq->intr_handle, RTE_INTR_HANDLE_EXT))
return -rte_errno;
diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index 28f1116891..dbcd98d49f 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -1062,9 +1062,6 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
goto port_error;
}
- if (rte_intr_fd_set(priv->intr_handle, -1))
- goto port_error;
-
if (rte_intr_type_set(priv->intr_handle, RTE_INTR_HANDLE_EXT))
goto port_error;
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index b93452f168..13114edba5 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -2191,7 +2191,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
dev->tx_pkt_burst = pmd_tx_burst;
rte_intr_type_set(pmd->intr_handle, RTE_INTR_HANDLE_EXT);
- rte_intr_fd_set(pmd->intr_handle, -1);
dev->intr_handle = pmd->intr_handle;
/* Presetup the fds to -1 as being not valid */
diff --git a/lib/eal/common/eal_common_interrupts.c b/lib/eal/common/eal_common_interrupts.c
index a2a310750a..4e31a71319 100644
--- a/lib/eal/common/eal_common_interrupts.c
+++ b/lib/eal/common/eal_common_interrupts.c
@@ -68,6 +68,8 @@ struct rte_intr_handle *rte_intr_instance_alloc(uint32_t flags)
rte_errno = ENOMEM;
goto fail;
}
+ for (int i = 0; i < RTE_MAX_RXTX_INTR_VEC_ID; i++)
+ intr_handle->efds[i] = -1;
if (uses_rte_memory) {
intr_handle->elist = rte_zmalloc(NULL,
@@ -83,6 +85,8 @@ struct rte_intr_handle *rte_intr_instance_alloc(uint32_t flags)
goto fail;
}
+ intr_handle->fd = -1;
+ intr_handle->dev_fd = -1;
intr_handle->alloc_flags = flags;
intr_handle->nb_intr = RTE_MAX_RXTX_INTR_VEC_ID;
@@ -153,6 +157,8 @@ int rte_intr_event_list_update(struct rte_intr_handle *intr_handle, int size)
goto fail;
}
intr_handle->efds = tmp_efds;
+ for (int i = intr_handle->nb_intr; i < size; i++)
+ intr_handle->efds[i] = -1;
if (uses_rte_memory) {
tmp_elist = rte_realloc(intr_handle->elist,
diff --git a/lib/eal/freebsd/eal_alarm.c b/lib/eal/freebsd/eal_alarm.c
index 2905841b5e..c563ee9cc2 100644
--- a/lib/eal/freebsd/eal_alarm.c
+++ b/lib/eal/freebsd/eal_alarm.c
@@ -75,9 +75,6 @@ rte_eal_alarm_init(void)
if (rte_intr_type_set(intr_handle, RTE_INTR_HANDLE_ALARM))
goto error;
- if (rte_intr_fd_set(intr_handle, -1))
- goto error;
-
/* on FreeBSD, timers don't use fd's, and their identifiers are stored
* in separate namespace from fd's, so using any value is OK. however,
* EAL interrupts handler expects fd's to be unique, so use an actual fd
diff --git a/lib/eal/include/rte_interrupts.h b/lib/eal/include/rte_interrupts.h
index 0ae16bbe19..1cfb9d3f8e 100644
--- a/lib/eal/include/rte_interrupts.h
+++ b/lib/eal/include/rte_interrupts.h
@@ -225,6 +225,8 @@ uint32_t rte_intr_active_events_flags(void);
* can be realloced later based on size of MSIX interrupts supported by a PCI
* device.
*
+ * All file descriptors (fd, dev_fd, efds) are initialized to -1.
+ *
* This function should be called from application or driver, before calling
* any of the interrupt APIs.
*
diff --git a/lib/eal/linux/eal_dev.c b/lib/eal/linux/eal_dev.c
index ec408649d0..c78e565427 100644
--- a/lib/eal/linux/eal_dev.c
+++ b/lib/eal/linux/eal_dev.c
@@ -326,10 +326,6 @@ rte_dev_event_monitor_start(void)
if (ret)
goto exit;
- ret = rte_intr_fd_set(intr_handle, -1);
- if (ret)
- goto exit;
-
ret = dev_uev_socket_fd_create();
if (ret) {
EAL_LOG(ERR, "error create device event fd.");
--
2.54.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [RFC v3 4/5] interrupts: close interrupt FDs
2026-09-07 12:13 [RFC v3 0/5] Interrupts API update David Marchand
` (2 preceding siblings ...)
2026-09-07 12:13 ` [RFC v3 3/5] interrupts: mark file descriptors invalid on allocation David Marchand
@ 2026-09-07 12:13 ` David Marchand
2026-09-07 12:13 ` [RFC v3 5/5] interrupts: warn on leaked file descriptors David Marchand
4 siblings, 0 replies; 8+ messages in thread
From: David Marchand @ 2026-09-07 12:13 UTC (permalink / raw)
To: dev, hkalra
Cc: Nipun Gupta, Nikhil Agarwal, Chenbo Xia, Anatoly Burakov, Long Li,
Wei Hu, Nithin Dabilpuram, Kiran Kumar K, Sunil Kumar Kori,
Satha Rao, Jakub Grajciar, Bruce Richardson
Add rte_intr_fd_close() and rte_intr_dev_fd_close() helpers to
encapsulate the common pattern of closing an interrupt handle's
file descriptor and resetting it to -1.
This simplifies code in multiple drivers that previously had to:
if (rte_intr_fd_get(handle) >= 0) {
close(rte_intr_fd_get(handle));
rte_intr_fd_set(handle, -1);
}
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
Changes since RFC v2:
- added unit test,
- converted bus/cdx and FreeBSD EAL interrupt code,
- added wrappers for common/cnxk,
---
app/test/test_interrupts.c | 72 ++++++++++++++++++++++++++
doc/guides/rel_notes/release_26_11.rst | 2 +
drivers/bus/cdx/cdx_vfio.c | 6 +--
drivers/bus/pci/bsd/pci.c | 7 +--
drivers/bus/pci/linux/pci_uio.c | 15 ++----
drivers/bus/pci/linux/pci_vfio.c | 16 ++----
drivers/bus/pci/pci_common_uio.c | 12 +----
drivers/bus/vmbus/linux/vmbus_uio.c | 13 ++---
drivers/bus/vmbus/vmbus_common_uio.c | 11 +---
drivers/common/cnxk/roc_platform.h | 2 +
drivers/net/memif/memif_socket.c | 13 ++---
lib/eal/common/eal_common_interrupts.c | 23 ++++++++
lib/eal/freebsd/eal_alarm.c | 3 +-
lib/eal/include/rte_interrupts.h | 27 ++++++++++
lib/eal/linux/eal_dev.c | 5 +-
15 files changed, 147 insertions(+), 80 deletions(-)
diff --git a/app/test/test_interrupts.c b/app/test/test_interrupts.c
index 747dfc4f48..67f1e6429a 100644
--- a/app/test/test_interrupts.c
+++ b/app/test/test_interrupts.c
@@ -169,6 +169,65 @@ test_interrupt_handle_compare(struct rte_intr_handle *intr_handle_l,
return 0;
}
+/**
+ * Tests for rte_intr_fd_close() and rte_intr_dev_fd_close().
+ */
+static int
+test_interrupt_close(void)
+{
+ struct rte_intr_handle *intr_handle;
+ int pipefd[2];
+
+ /* check with null intr_handle */
+ rte_intr_fd_close(NULL);
+ rte_intr_dev_fd_close(NULL);
+
+ intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
+ if (!intr_handle)
+ return -1;
+
+ if (pipe(pipefd) < 0) {
+ rte_intr_instance_free(intr_handle);
+ return -1;
+ }
+
+ if (rte_intr_fd_set(intr_handle, pipefd[0]) < 0 ||
+ rte_intr_dev_fd_set(intr_handle, pipefd[1]) < 0) {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ rte_intr_instance_free(intr_handle);
+ return -1;
+ }
+
+ /* check rte_intr_fd_close */
+ rte_intr_fd_close(intr_handle);
+
+ if (rte_intr_fd_get(intr_handle) != -1) {
+ printf("fd not set to -1 after close\n");
+ close(pipefd[1]);
+ rte_intr_instance_free(intr_handle);
+ return -1;
+ }
+
+ /* calling again should be a noop */
+ rte_intr_fd_close(intr_handle);
+
+ /* check rte_intr_dev_fd_close */
+ rte_intr_dev_fd_close(intr_handle);
+
+ if (rte_intr_dev_fd_get(intr_handle) != -1) {
+ printf("dev_fd not set to -1 after close\n");
+ rte_intr_instance_free(intr_handle);
+ return -1;
+ }
+
+ /* calling again should be a noop */
+ rte_intr_dev_fd_close(intr_handle);
+
+ rte_intr_instance_free(intr_handle);
+ return 0;
+}
+
#else
/* to be implemented for bsd later */
static inline int
@@ -206,6 +265,12 @@ test_interrupt_handle_compare(struct rte_intr_handle *intr_handle_l,
return 0;
}
+
+static int
+test_interrupt_close(void)
+{
+ return 0;
+}
#endif /* RTE_EXEC_ENV_LINUX */
/**
@@ -566,6 +631,13 @@ test_interrupt(void)
}
rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
+ printf("start interrupt close test\n");
+ if (test_interrupt_close() < 0) {
+ printf("fail to check interrupt close\n");
+ goto out;
+ }
+ rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
+
ret = 0;
out:
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 36d6f3a05f..07b90f1529 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -99,6 +99,8 @@ API Changes
* ``rte_intr_instance_alloc()`` now initializes file descriptors
to invalid values instead of zero.
+ * Added ``rte_intr_fd_close()`` and ``rte_intr_dev_fd_close()``
+ helpers to close file descriptors and reset them to -1.
ABI Changes
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 0e4af4e940..8d67058bfe 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -110,11 +110,7 @@ cdx_vfio_unmap_resource_primary(struct rte_cdx_device *dev)
CDX_BUS_ERR("Error when disabling bus master for %s",
dev->device.name);
- if (close(rte_intr_fd_get(dev->intr_handle)) < 0) {
- CDX_BUS_ERR("Error when closing eventfd file descriptor for %s",
- dev->device.name);
- return -1;
- }
+ rte_intr_fd_close(dev->intr_handle);
}
vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
diff --git a/drivers/bus/pci/bsd/pci.c b/drivers/bus/pci/bsd/pci.c
index bbe08605af..f1012bb91b 100644
--- a/drivers/bus/pci/bsd/pci.c
+++ b/drivers/bus/pci/bsd/pci.c
@@ -93,11 +93,8 @@ pci_uio_free_resource(struct rte_pci_device *dev,
{
rte_free(uio_res);
- if (rte_intr_fd_get(dev->intr_handle) >= 0) {
- close(rte_intr_fd_get(dev->intr_handle));
- rte_intr_fd_set(dev->intr_handle, -1);
- rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
- }
+ rte_intr_fd_close(dev->intr_handle);
+ rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
}
int
diff --git a/drivers/bus/pci/linux/pci_uio.c b/drivers/bus/pci/linux/pci_uio.c
index 40e96b1c67..0983474994 100644
--- a/drivers/bus/pci/linux/pci_uio.c
+++ b/drivers/bus/pci/linux/pci_uio.c
@@ -197,20 +197,11 @@ void
pci_uio_free_resource(struct rte_pci_device *dev,
struct mapped_pci_resource *uio_res)
{
- int uio_cfg_fd = rte_intr_dev_fd_get(dev->intr_handle);
-
rte_free(uio_res);
- if (uio_cfg_fd >= 0) {
- close(uio_cfg_fd);
- rte_intr_dev_fd_set(dev->intr_handle, -1);
- }
-
- if (rte_intr_fd_get(dev->intr_handle) >= 0) {
- close(rte_intr_fd_get(dev->intr_handle));
- rte_intr_fd_set(dev->intr_handle, -1);
- rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
- }
+ rte_intr_dev_fd_close(dev->intr_handle);
+ rte_intr_fd_close(dev->intr_handle);
+ rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
}
int
diff --git a/drivers/bus/pci/linux/pci_vfio.c b/drivers/bus/pci/linux/pci_vfio.c
index a92a0d86ec..84c338c68e 100644
--- a/drivers/bus/pci/linux/pci_vfio.c
+++ b/drivers/bus/pci/linux/pci_vfio.c
@@ -354,9 +354,7 @@ pci_vfio_enable_notifier(struct rte_pci_device *dev, int vfio_dev_fd)
return 0;
error:
- close(fd);
-
- rte_intr_fd_set(dev->vfio_req_intr_handle, -1);
+ rte_intr_fd_close(dev->vfio_req_intr_handle);
rte_intr_type_set(dev->vfio_req_intr_handle, RTE_INTR_HANDLE_UNKNOWN);
rte_intr_dev_fd_set(dev->vfio_req_intr_handle, -1);
@@ -383,9 +381,7 @@ pci_vfio_disable_notifier(struct rte_pci_device *dev)
return -1;
}
- close(rte_intr_fd_get(dev->vfio_req_intr_handle));
-
- rte_intr_fd_set(dev->vfio_req_intr_handle, -1);
+ rte_intr_fd_close(dev->vfio_req_intr_handle);
rte_intr_type_set(dev->vfio_req_intr_handle, RTE_INTR_HANDLE_UNKNOWN);
rte_intr_dev_fd_set(dev->vfio_req_intr_handle, -1);
@@ -1073,13 +1069,7 @@ pci_vfio_unmap_resource_primary(struct rte_pci_device *dev)
return -1;
}
- if (rte_intr_fd_get(dev->intr_handle) < 0)
- return -1;
-
- if (close(rte_intr_fd_get(dev->intr_handle)) < 0) {
- PCI_LOG(INFO, "Error when closing eventfd file descriptor for %s", pci_addr);
- return -1;
- }
+ rte_intr_fd_close(dev->intr_handle);
vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
if (vfio_dev_fd < 0)
diff --git a/drivers/bus/pci/pci_common_uio.c b/drivers/bus/pci/pci_common_uio.c
index 47d50721dc..52a10f806a 100644
--- a/drivers/bus/pci/pci_common_uio.c
+++ b/drivers/bus/pci/pci_common_uio.c
@@ -211,7 +211,6 @@ pci_uio_unmap_resource(struct rte_pci_device *dev)
struct mapped_pci_resource *uio_res;
struct mapped_pci_res_list *uio_res_list =
RTE_TAILQ_CAST(rte_uio_tailq.head, mapped_pci_res_list);
- int uio_cfg_fd;
if (dev == NULL)
return;
@@ -222,15 +221,8 @@ pci_uio_unmap_resource(struct rte_pci_device *dev)
return;
/* close fd */
- if (rte_intr_fd_get(dev->intr_handle) >= 0)
- close(rte_intr_fd_get(dev->intr_handle));
- uio_cfg_fd = rte_intr_dev_fd_get(dev->intr_handle);
- if (uio_cfg_fd >= 0) {
- close(uio_cfg_fd);
- rte_intr_dev_fd_set(dev->intr_handle, -1);
- }
-
- rte_intr_fd_set(dev->intr_handle, -1);
+ rte_intr_fd_close(dev->intr_handle);
+ rte_intr_dev_fd_close(dev->intr_handle);
rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
/* secondary processes - just free maps */
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..c52d6738a5 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -67,16 +67,9 @@ vmbus_uio_free_resource(struct rte_vmbus_device *dev,
{
rte_free(uio_res);
- if (rte_intr_dev_fd_get(dev->intr_handle) >= 0) {
- close(rte_intr_dev_fd_get(dev->intr_handle));
- rte_intr_dev_fd_set(dev->intr_handle, -1);
- }
-
- if (rte_intr_fd_get(dev->intr_handle) >= 0) {
- close(rte_intr_fd_get(dev->intr_handle));
- rte_intr_fd_set(dev->intr_handle, -1);
- rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
- }
+ rte_intr_dev_fd_close(dev->intr_handle);
+ rte_intr_fd_close(dev->intr_handle);
+ rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
}
int
diff --git a/drivers/bus/vmbus/vmbus_common_uio.c b/drivers/bus/vmbus/vmbus_common_uio.c
index 7459f4ea7a..9765f5f609 100644
--- a/drivers/bus/vmbus/vmbus_common_uio.c
+++ b/drivers/bus/vmbus/vmbus_common_uio.c
@@ -254,14 +254,7 @@ vmbus_uio_unmap_resource(struct rte_vmbus_device *dev)
rte_free(uio_res);
/* close fd */
- if (rte_intr_fd_get(dev->intr_handle) >= 0)
- close(rte_intr_fd_get(dev->intr_handle));
-
- if (rte_intr_dev_fd_get(dev->intr_handle) >= 0) {
- close(rte_intr_dev_fd_get(dev->intr_handle));
- rte_intr_dev_fd_set(dev->intr_handle, -1);
- }
-
- rte_intr_fd_set(dev->intr_handle, -1);
+ rte_intr_fd_close(dev->intr_handle);
+ rte_intr_dev_fd_close(dev->intr_handle);
rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
}
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index ac4f76473f..aba9782023 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -171,8 +171,10 @@ plt_thread_is_valid(plt_thread_t thr)
#define plt_intr_vec_list_free rte_intr_vec_list_free
#define plt_intr_fd_set rte_intr_fd_set
#define plt_intr_fd_get rte_intr_fd_get
+#define plt_intr_fd_close rte_intr_fd_close
#define plt_intr_dev_fd_get rte_intr_dev_fd_get
#define plt_intr_dev_fd_set rte_intr_dev_fd_set
+#define plt_intr_dev_fd_close rte_intr_dev_fd_close
#define plt_intr_type_get rte_intr_type_get
#define plt_intr_type_set rte_intr_type_set
#define plt_intr_instance_alloc rte_intr_instance_alloc
diff --git a/drivers/net/memif/memif_socket.c b/drivers/net/memif/memif_socket.c
index 649f8d0e61..94cd70fb89 100644
--- a/drivers/net/memif/memif_socket.c
+++ b/drivers/net/memif/memif_socket.c
@@ -510,8 +510,7 @@ memif_intr_unregister_handler(struct rte_intr_handle *intr_handle, void *arg)
struct memif_control_channel *cc = arg;
/* close control channel fd */
- if (rte_intr_fd_get(intr_handle) >= 0)
- close(rte_intr_fd_get(intr_handle));
+ rte_intr_fd_close(intr_handle);
/* clear message queue */
while ((elt = TAILQ_FIRST(&cc->msg_queue)) != NULL) {
TAILQ_REMOVE(&cc->msg_queue, elt, next);
@@ -596,10 +595,7 @@ memif_disconnect(struct rte_eth_dev *dev)
continue;
}
- if (rte_intr_fd_get(mq->intr_handle) > 0) {
- close(rte_intr_fd_get(mq->intr_handle));
- rte_intr_fd_set(mq->intr_handle, -1);
- }
+ rte_intr_fd_close(mq->intr_handle);
}
for (i = 0; i < pmd->cfg.num_s2c_rings; i++) {
if (pmd->role == MEMIF_ROLE_SERVER) {
@@ -614,10 +610,7 @@ memif_disconnect(struct rte_eth_dev *dev)
continue;
}
- if (rte_intr_fd_get(mq->intr_handle) > 0) {
- close(rte_intr_fd_get(mq->intr_handle));
- rte_intr_fd_set(mq->intr_handle, -1);
- }
+ rte_intr_fd_close(mq->intr_handle);
}
memif_free_regions(dev);
diff --git a/lib/eal/common/eal_common_interrupts.c b/lib/eal/common/eal_common_interrupts.c
index 4e31a71319..8176eb089a 100644
--- a/lib/eal/common/eal_common_interrupts.c
+++ b/lib/eal/common/eal_common_interrupts.c
@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <rte_errno.h>
#include <rte_interrupts.h>
@@ -219,6 +220,17 @@ int rte_intr_fd_get(const struct rte_intr_handle *intr_handle)
return -1;
}
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_intr_fd_close, 26.11)
+void rte_intr_fd_close(struct rte_intr_handle *intr_handle)
+{
+ int fd = rte_intr_fd_get(intr_handle);
+
+ if (fd >= 0) {
+ close(fd);
+ rte_intr_fd_set(intr_handle, -1);
+ }
+}
+
RTE_EXPORT_SYMBOL(rte_intr_type_set)
int rte_intr_type_set(struct rte_intr_handle *intr_handle,
enum rte_intr_handle_type type)
@@ -265,6 +277,17 @@ int rte_intr_dev_fd_get(const struct rte_intr_handle *intr_handle)
return -1;
}
+RTE_EXPORT_INTERNAL_SYMBOL(rte_intr_dev_fd_close)
+void rte_intr_dev_fd_close(struct rte_intr_handle *intr_handle)
+{
+ int fd = rte_intr_dev_fd_get(intr_handle);
+
+ if (fd >= 0) {
+ close(fd);
+ rte_intr_dev_fd_set(intr_handle, -1);
+ }
+}
+
RTE_EXPORT_INTERNAL_SYMBOL(rte_intr_max_intr_set)
int rte_intr_max_intr_set(struct rte_intr_handle *intr_handle,
int max_intr)
diff --git a/lib/eal/freebsd/eal_alarm.c b/lib/eal/freebsd/eal_alarm.c
index c563ee9cc2..2697921760 100644
--- a/lib/eal/freebsd/eal_alarm.c
+++ b/lib/eal/freebsd/eal_alarm.c
@@ -54,8 +54,7 @@ rte_eal_alarm_cleanup(void)
int ret = rte_intr_callback_unregister_sync(intr_handle,
eal_alarm_callback, (void *)-1);
if (ret >= 0) {
- close(rte_intr_fd_get(intr_handle));
- rte_intr_fd_set(intr_handle, -1);
+ rte_intr_fd_close(intr_handle);
rte_intr_instance_free(intr_handle);
intr_handle = NULL;
}
diff --git a/lib/eal/include/rte_interrupts.h b/lib/eal/include/rte_interrupts.h
index 1cfb9d3f8e..d04c0c7b15 100644
--- a/lib/eal/include/rte_interrupts.h
+++ b/lib/eal/include/rte_interrupts.h
@@ -279,6 +279,19 @@ rte_intr_fd_set(struct rte_intr_handle *intr_handle, int fd);
int
rte_intr_fd_get(const struct rte_intr_handle *intr_handle);
+/**
+ * Close the FD of the given interrupt handle instance,
+ * and set FD to -1.
+ *
+ * If FD is not valid (< 0), nothing is done.
+ *
+ * @param intr_handle
+ * pointer to the interrupt handle.
+ */
+__rte_experimental
+void
+rte_intr_fd_close(struct rte_intr_handle *intr_handle);
+
/**
* Set the type field of interrupt handle with user provided
* interrupt type.
@@ -467,6 +480,20 @@ __rte_internal
int
rte_intr_dev_fd_get(const struct rte_intr_handle *intr_handle);
+/**
+ * @internal
+ * Close the device FD of the given interrupt handle instance,
+ * and set device FD to -1.
+ *
+ * If device FD is not valid (< 0), nothing is done.
+ *
+ * @param intr_handle
+ * pointer to the interrupt handle.
+ */
+__rte_internal
+void
+rte_intr_dev_fd_close(struct rte_intr_handle *intr_handle);
+
/**
* @internal
* Set the max intr field of interrupt handle with user
diff --git a/lib/eal/linux/eal_dev.c b/lib/eal/linux/eal_dev.c
index c78e565427..4f55dcc4e7 100644
--- a/lib/eal/linux/eal_dev.c
+++ b/lib/eal/linux/eal_dev.c
@@ -217,10 +217,7 @@ static void
dev_delayed_unregister(void *param)
{
rte_intr_callback_unregister(intr_handle, dev_uev_handler, param);
- if (rte_intr_fd_get(intr_handle) >= 0) {
- close(rte_intr_fd_get(intr_handle));
- rte_intr_fd_set(intr_handle, -1);
- }
+ rte_intr_fd_close(intr_handle);
}
static void
--
2.54.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [RFC v3 5/5] interrupts: warn on leaked file descriptors
2026-09-07 12:13 [RFC v3 0/5] Interrupts API update David Marchand
` (3 preceding siblings ...)
2026-09-07 12:13 ` [RFC v3 4/5] interrupts: close interrupt FDs David Marchand
@ 2026-09-07 12:13 ` David Marchand
4 siblings, 0 replies; 8+ messages in thread
From: David Marchand @ 2026-09-07 12:13 UTC (permalink / raw)
To: dev, hkalra
Cc: Nipun Gupta, Nikhil Agarwal, Anatoly Burakov, Chenbo Xia,
Dariusz Sosnowski, Viacheslav Ovsiienko, Bing Zhao, Ori Kam,
Suanming Mou, Matan Azrad, Long Li, Wei Hu, Jie Liu,
Stephen Hemminger, Maxime Coquelin, Jakub Palider,
Tomasz Duszynski
Let's warn on interrupt handle that still reference what looks like a
valid file descriptor.
This will likely raise false positives, but it should help limiting FD
leaks on the long term.
Add missing reset to -1 in drivers, and document code.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
Changes since RFC v2:
- split code comments added by patch 3 in the RFC v2,
- added a check on leftover FD in a interrupt handle,
---
app/test/test_interrupts.c | 5 ++++-
drivers/bus/cdx/cdx_vfio.c | 4 ++++
drivers/bus/pci/linux/pci_vfio.c | 2 ++
drivers/common/mlx5/linux/mlx5_common_os.c | 6 +++++-
drivers/net/mana/mana.c | 1 +
drivers/net/mlx4/mlx4_intr.c | 1 +
drivers/net/sxe2/sxe2_irq.c | 5 ++++-
drivers/net/tap/rte_eth_tap.c | 1 +
drivers/net/virtio/virtio_user/virtio_user_dev.c | 2 ++
drivers/raw/cnxk_gpio/cnxk_gpio.c | 3 +++
drivers/vdpa/mlx5/mlx5_vdpa_event.c | 1 +
drivers/vdpa/mlx5/mlx5_vdpa_virtq.c | 1 +
lib/eal/common/eal_common_interrupts.c | 6 ++++++
13 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/app/test/test_interrupts.c b/app/test/test_interrupts.c
index 67f1e6429a..a737a9cd51 100644
--- a/app/test/test_interrupts.c
+++ b/app/test/test_interrupts.c
@@ -130,8 +130,11 @@ test_interrupt_deinit(void)
{
int i;
- for (i = 0; i < TEST_INTERRUPT_HANDLE_MAX; i++)
+ for (i = 0; i < TEST_INTERRUPT_HANDLE_MAX; i++) {
+ rte_intr_fd_set(intr_handles[i], -1);
+ rte_intr_dev_fd_set(intr_handles[i], -1);
rte_intr_instance_free(intr_handles[i]);
+ }
close(pfds.pipefd[0]);
close(pfds.pipefd[1]);
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 8d67058bfe..0c1b263a85 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -116,6 +116,8 @@ cdx_vfio_unmap_resource_primary(struct rte_cdx_device *dev)
vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
if (vfio_dev_fd < 0)
return -1;
+ /* vfio_dev_fd is owned by VFIO, only clear reference here. */
+ rte_intr_dev_fd_set(dev->intr_handle, -1);
ret = rte_vfio_release_device(RTE_CDX_BUS_DEVICES_PATH, dev->device.name,
vfio_dev_fd);
@@ -150,6 +152,8 @@ cdx_vfio_unmap_resource_secondary(struct rte_cdx_device *dev)
vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
if (vfio_dev_fd < 0)
return -1;
+ /* vfio_dev_fd is owned by VFIO, only clear reference here. */
+ rte_intr_dev_fd_set(dev->intr_handle, -1);
ret = rte_vfio_release_device(RTE_CDX_BUS_DEVICES_PATH, dev->device.name,
vfio_dev_fd);
diff --git a/drivers/bus/pci/linux/pci_vfio.c b/drivers/bus/pci/linux/pci_vfio.c
index 84c338c68e..b5f05e9f9f 100644
--- a/drivers/bus/pci/linux/pci_vfio.c
+++ b/drivers/bus/pci/linux/pci_vfio.c
@@ -356,6 +356,7 @@ pci_vfio_enable_notifier(struct rte_pci_device *dev, int vfio_dev_fd)
error:
rte_intr_fd_close(dev->vfio_req_intr_handle);
rte_intr_type_set(dev->vfio_req_intr_handle, RTE_INTR_HANDLE_UNKNOWN);
+ /* vfio_dev_fd is managed by VFIO layer, only clear reference here. */
rte_intr_dev_fd_set(dev->vfio_req_intr_handle, -1);
return -1;
@@ -383,6 +384,7 @@ pci_vfio_disable_notifier(struct rte_pci_device *dev)
rte_intr_fd_close(dev->vfio_req_intr_handle);
rte_intr_type_set(dev->vfio_req_intr_handle, RTE_INTR_HANDLE_UNKNOWN);
+ /* vfio_dev_fd is managed by VFIO layer, only clear reference here. */
rte_intr_dev_fd_set(dev->vfio_req_intr_handle, -1);
return 0;
diff --git a/drivers/common/mlx5/linux/mlx5_common_os.c b/drivers/common/mlx5/linux/mlx5_common_os.c
index 3e9cd86062..09d37f32cb 100644
--- a/drivers/common/mlx5/linux/mlx5_common_os.c
+++ b/drivers/common/mlx5/linux/mlx5_common_os.c
@@ -1108,6 +1108,7 @@ mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
}
return tmp_intr_handle;
err:
+ rte_intr_fd_set(tmp_intr_handle, -1);
rte_intr_instance_free(tmp_intr_handle);
return NULL;
}
@@ -1181,8 +1182,11 @@ void
mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
rte_intr_callback_fn cb, void *cb_arg)
{
- if (rte_intr_fd_get(intr_handle) >= 0)
+ if (rte_intr_fd_get(intr_handle) >= 0) {
mlx5_intr_callback_unregister(intr_handle, cb, cb_arg);
+ /* fd is not owned by the driver, only clear reference here. */
+ rte_intr_fd_set(intr_handle, -1);
+ }
rte_intr_instance_free(intr_handle);
}
diff --git a/drivers/net/mana/mana.c b/drivers/net/mana/mana.c
index 1864ba2a2b..f51598ea68 100644
--- a/drivers/net/mana/mana.c
+++ b/drivers/net/mana/mana.c
@@ -1964,6 +1964,7 @@ mana_intr_install(struct rte_eth_dev *eth_dev, struct mana_priv *priv)
mana_intr_handler, priv);
if (ret) {
DRV_LOG(ERR, "Failed to register intr callback");
+ /* fd is owned by ibverbs, only clear reference here. */
rte_intr_fd_set(priv->intr_handle, -1);
goto free_intr;
}
diff --git a/drivers/net/mlx4/mlx4_intr.c b/drivers/net/mlx4/mlx4_intr.c
index 01057482ec..c278dd5ecc 100644
--- a/drivers/net/mlx4/mlx4_intr.c
+++ b/drivers/net/mlx4/mlx4_intr.c
@@ -265,6 +265,7 @@ mlx4_intr_uninstall(struct mlx4_priv *priv)
(void (*)(void *))
mlx4_interrupt_handler,
priv);
+ /* fd is owned by ibverbs, only clear reference here. */
if (rte_intr_fd_set(priv->intr_handle, -1))
return -rte_errno;
}
diff --git a/drivers/net/sxe2/sxe2_irq.c b/drivers/net/sxe2/sxe2_irq.c
index 3306504761..c30a26d94e 100644
--- a/drivers/net/sxe2/sxe2_irq.c
+++ b/drivers/net/sxe2/sxe2_irq.c
@@ -377,8 +377,11 @@ static void sxe2_intr_handler_destroy(struct rte_intr_handle *intr_handle,
if (!intr_handle)
return;
- if (rte_intr_fd_get(intr_handle) >= 0)
+ if (rte_intr_fd_get(intr_handle) >= 0) {
(void)rte_intr_callback_unregister(intr_handle, cb, cb_arg);
+ /* fd is not owned by the driver, only clear reference here. */
+ rte_intr_fd_set(intr_handle, -1);
+ }
rte_intr_instance_free(intr_handle);
}
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 13114edba5..693be653ba 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1947,6 +1947,7 @@ tap_lsc_intr_handle_set(struct rte_eth_dev *dev, int set)
if (rte_intr_fd_get(pmd->intr_handle) >= 0) {
tap_nl_final(rte_intr_fd_get(pmd->intr_handle));
+ /* fd is not owned by the driver, only clear reference here. */
rte_intr_fd_set(pmd->intr_handle, -1);
}
diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.c b/drivers/net/virtio/virtio_user/virtio_user_dev.c
index f3df73c1f0..f89c871beb 100644
--- a/drivers/net/virtio/virtio_user/virtio_user_dev.c
+++ b/drivers/net/virtio/virtio_user/virtio_user_dev.c
@@ -858,6 +858,8 @@ virtio_user_dev_uninit(struct virtio_user_dev *dev)
{
struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
+ /* fd is not owned by the driver, only clear reference here. */
+ rte_intr_fd_set(eth_dev->intr_handle, -1);
rte_intr_instance_free(eth_dev->intr_handle);
eth_dev->intr_handle = NULL;
diff --git a/drivers/raw/cnxk_gpio/cnxk_gpio.c b/drivers/raw/cnxk_gpio/cnxk_gpio.c
index 0549e326f9..2b5ea0bf9f 100644
--- a/drivers/raw/cnxk_gpio/cnxk_gpio.c
+++ b/drivers/raw/cnxk_gpio/cnxk_gpio.c
@@ -442,6 +442,8 @@ cnxk_gpio_unregister_irq(struct cnxk_gpio *gpio)
if (ret)
return ret;
+ /* fd is owned by gpio, only clear reference here. */
+ rte_intr_fd_set(gpio->intr.intr_handle, -1);
rte_intr_instance_free(gpio->intr.intr_handle);
gpio->intr.intr_handle = NULL;
@@ -635,6 +637,7 @@ cnxk_gpio_register_irq_compat(struct cnxk_gpio *gpio, struct cnxk_gpio_irq *irq,
return 0;
out:
+ rte_intr_fd_set(intr_handle, -1);
rte_intr_instance_free(intr_handle);
return ret;
diff --git a/drivers/vdpa/mlx5/mlx5_vdpa_event.c b/drivers/vdpa/mlx5/mlx5_vdpa_event.c
index dee2ccc23d..d18cf7d7e5 100644
--- a/drivers/vdpa/mlx5/mlx5_vdpa_event.c
+++ b/drivers/vdpa/mlx5/mlx5_vdpa_event.c
@@ -487,6 +487,7 @@ mlx5_vdpa_err_event_unset(struct mlx5_vdpa_priv *priv)
rte_pause();
}
}
+ /* fd is owned by err_chnl, only clear reference here. */
rte_intr_fd_set(priv->err_intr_handle, -1);
if (priv->err_chnl) {
#ifdef HAVE_IBV_DEVX_EVENT
diff --git a/drivers/vdpa/mlx5/mlx5_vdpa_virtq.c b/drivers/vdpa/mlx5/mlx5_vdpa_virtq.c
index 093cdd08d2..9cad7e1df4 100644
--- a/drivers/vdpa/mlx5/mlx5_vdpa_virtq.c
+++ b/drivers/vdpa/mlx5/mlx5_vdpa_virtq.c
@@ -96,6 +96,7 @@ mlx5_vdpa_virtq_unregister_intr_handle(struct mlx5_vdpa_virtq *virtq)
pthread_mutex_lock(&virtq->virtq_lock);
}
}
+ /* fd is owned by vhost, only clear reference here. */
(void)rte_intr_fd_set(virtq->intr_handle, -1);
}
rte_intr_instance_free(virtq->intr_handle);
diff --git a/lib/eal/common/eal_common_interrupts.c b/lib/eal/common/eal_common_interrupts.c
index 8176eb089a..6368ef1771 100644
--- a/lib/eal/common/eal_common_interrupts.c
+++ b/lib/eal/common/eal_common_interrupts.c
@@ -187,6 +187,12 @@ void rte_intr_instance_free(struct rte_intr_handle *intr_handle)
{
if (intr_handle == NULL)
return;
+ if (rte_intr_fd_get(intr_handle) >= 0)
+ EAL_LOG(NOTICE, "Some interrupt handle is leaking a FD: %d",
+ rte_intr_fd_get(intr_handle));
+ if (rte_intr_dev_fd_get(intr_handle) >= 0)
+ EAL_LOG(NOTICE, "Some interrupt handle is leaking a device FD: %d",
+ rte_intr_dev_fd_get(intr_handle));
if (RTE_INTR_INSTANCE_USES_RTE_MEMORY(intr_handle->alloc_flags)) {
rte_free(intr_handle->efds);
rte_free(intr_handle->elist);
--
2.54.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [RFC v3 2/5] eal/freebsd: fix a FD leak in the alarm subsystem
2026-09-07 12:13 ` [RFC v3 2/5] eal/freebsd: fix a FD leak in the alarm subsystem David Marchand
@ 2026-09-07 12:35 ` Bruce Richardson
2026-09-07 12:47 ` David Marchand
0 siblings, 1 reply; 8+ messages in thread
From: Bruce Richardson @ 2026-09-07 12:35 UTC (permalink / raw)
To: David Marchand; +Cc: dev, hkalra, stable, Anatoly Burakov
On Mon, Sep 07, 2026 at 02:13:45PM +0200, David Marchand wrote:
> Caught by code review, while looking at rte_intr_instance_free() users.
>
> Even if the FD is not used, it must still be closed when uninitialising
> the alarm subsystem.
>
> Fixes: 26021a715067 ("eal/bsd: support alarm API")
> Cc: stable@dpdk.org
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
> lib/eal/freebsd/eal_alarm.c | 6 +++++-
> 1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/lib/eal/freebsd/eal_alarm.c b/lib/eal/freebsd/eal_alarm.c
> index c03e281e67..2905841b5e 100644
> --- a/lib/eal/freebsd/eal_alarm.c
> +++ b/lib/eal/freebsd/eal_alarm.c
> @@ -54,6 +54,8 @@ rte_eal_alarm_cleanup(void)
> int ret = rte_intr_callback_unregister_sync(intr_handle,
> eal_alarm_callback, (void *)-1);
> if (ret >= 0) {
> + close(rte_intr_fd_get(intr_handle));
> + rte_intr_fd_set(intr_handle, -1);
> rte_intr_instance_free(intr_handle);
> intr_handle = NULL;
> }
> @@ -62,7 +64,7 @@ rte_eal_alarm_cleanup(void)
> int
> rte_eal_alarm_init(void)
> {
> - int fd;
> + int fd = -1;
>
> intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
> if (intr_handle == NULL) {
> @@ -88,6 +90,8 @@ rte_eal_alarm_init(void)
>
> return 0;
> error:
> + if (fd >= 0)
> + close(fd);
> rte_intr_instance_free(intr_handle);
> return -1;
> }
> --
> 2.54.0
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC v3 2/5] eal/freebsd: fix a FD leak in the alarm subsystem
2026-09-07 12:35 ` Bruce Richardson
@ 2026-09-07 12:47 ` David Marchand
0 siblings, 0 replies; 8+ messages in thread
From: David Marchand @ 2026-09-07 12:47 UTC (permalink / raw)
To: Bruce Richardson; +Cc: dev, hkalra, stable, Anatoly Burakov
On Mon, 7 Sept 2026 at 14:35, Bruce Richardson
<bruce.richardson@intel.com> wrote:
>
> On Mon, Sep 07, 2026 at 02:13:45PM +0200, David Marchand wrote:
> > Caught by code review, while looking at rte_intr_instance_free() users.
> >
> > Even if the FD is not used, it must still be closed when uninitialising
> > the alarm subsystem.
> >
> > Fixes: 26021a715067 ("eal/bsd: support alarm API")
> > Cc: stable@dpdk.org
> >
> > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > ---
> Acked-by: Bruce Richardson <bruce.richardson@intel.com>
I'll fix compilation and resubmit..
--
David Marchand
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-07 12:48 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-07 12:13 [RFC v3 0/5] Interrupts API update David Marchand
2026-09-07 12:13 ` [RFC v3 1/5] vdpa/mlx5: fix check on err interrupt FD David Marchand
2026-09-07 12:13 ` [RFC v3 2/5] eal/freebsd: fix a FD leak in the alarm subsystem David Marchand
2026-09-07 12:35 ` Bruce Richardson
2026-09-07 12:47 ` David Marchand
2026-09-07 12:13 ` [RFC v3 3/5] interrupts: mark file descriptors invalid on allocation David Marchand
2026-09-07 12:13 ` [RFC v3 4/5] interrupts: close interrupt FDs David Marchand
2026-09-07 12:13 ` [RFC v3 5/5] interrupts: warn on leaked file descriptors David Marchand
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox