* [PATCH 00/13] Bus cleanup infrastructure and fixes
@ 2026-06-11 9:45 David Marchand
2026-06-11 9:45 ` [PATCH 01/13] bus: fix reference to plug callback David Marchand
` (16 more replies)
0 siblings, 17 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen
This is a followup of the previous bus refactoring.
See https://inbox.dpdk.org/dev/CAJFAV8zvFpLwz8SY8DUUezyJyM43eRZ17Yj30ex808eHC4ZE=g@mail.gmail.com/.
This series refactors the bus cleanup infrastructure to reduce code
duplication and fix resource leaks in several bus drivers.
It should address the leak Thomas pointed at.
The first part of the series (patches 1-8) addresses several bugs and
inconsistencies:
- Documentation and log message inconsistencies from earlier bus
refactoring
- Device list management issues in dma/idxd and bus/vdev
- Resource leaks in PCI and VMBUS bus cleanup (mappings and interrupts)
- Simplified device freeing in NXP buses (DPAA and FSLMC)
- Deferred interrupt allocation to probe time (NXP buses, VMBUS)
The core infrastructure changes (patches 9-10) introduce the generic
cleanup framework:
- Refactors unplug operations to be the counterpart of probe_device
- Implements rte_bus_generic_cleanup() to centralize cleanup logic
- Adds .free_device operation to struct rte_bus
- Adds compile-time verification that rte_device is at offset 0
The final patches (11-13) convert remaining buses to use the generic
cleanup helper:
- DPAA bus: add unplug support
- VMBUS bus: switch to embedded device name and add unplug support
After this series, most buses use the generic cleanup helper, eliminating
duplicated code and ensuring consistent cleanup behavior across the
codebase.
--
David Marchand
David Marchand (13):
bus: fix reference to plug callback
dma/idxd: remove next pointer in bus specific device
bus/vdev: remove driver setting in probe
drivers/bus: cleanup device freeing in NXP bus
drivers/bus: allocate interrupt during probing in NXP bus
bus/pci: fix mapping leak in bus cleanup
bus/vmbus: fix interrupt leak in cleanup
bus/vmbus: allocate interrupt during probing
bus: align unplug with device probe
bus: implement cleanup in EAL
bus/dpaa: support unplug
bus/vmbus: store name in bus specific device
bus/vmbus: support unplug
doc/guides/prog_guide/device_hotplug.rst | 20 +++--
doc/guides/rel_notes/release_26_07.rst | 8 ++
drivers/bus/auxiliary/auxiliary_common.c | 56 +++-----------
drivers/bus/cdx/cdx.c | 31 ++------
drivers/bus/dpaa/dpaa_bus.c | 96 ++++++++++--------------
drivers/bus/fslmc/fslmc_bus.c | 55 ++++++--------
drivers/bus/ifpga/ifpga_bus.c | 65 ++++------------
drivers/bus/pci/pci_common.c | 69 +++--------------
drivers/bus/platform/platform.c | 28 ++-----
drivers/bus/uacce/uacce.c | 61 ++-------------
drivers/bus/vdev/vdev.c | 71 ++++++------------
drivers/bus/vmbus/bus_vmbus_driver.h | 1 +
drivers/bus/vmbus/linux/vmbus_bus.c | 16 +---
drivers/bus/vmbus/vmbus_common.c | 56 ++++++++------
drivers/dma/idxd/idxd_bus.c | 3 +-
lib/eal/common/eal_common_bus.c | 33 +++++++-
lib/eal/common/eal_common_dev.c | 10 ++-
lib/eal/include/bus_driver.h | 42 ++++++++++-
18 files changed, 268 insertions(+), 453 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH 01/13] bus: fix reference to plug callback
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
@ 2026-06-11 9:45 ` David Marchand
2026-06-11 9:45 ` [PATCH 02/13] dma/idxd: remove next pointer in bus specific device David Marchand
` (15 subsequent siblings)
16 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen
Update documentation and some log following the callback rename.
Fixes: 76622feba9e6 ("bus: refactor device probe")
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
doc/guides/prog_guide/device_hotplug.rst | 2 +-
lib/eal/common/eal_common_dev.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/doc/guides/prog_guide/device_hotplug.rst b/doc/guides/prog_guide/device_hotplug.rst
index 9896a097f3..7eb7fbcc2b 100644
--- a/doc/guides/prog_guide/device_hotplug.rst
+++ b/doc/guides/prog_guide/device_hotplug.rst
@@ -234,7 +234,7 @@ When ``rte_dev_probe()`` is called, the following sequence occurs:
and the attach operation fails if the device is not found.
#. **Device Probe**:
- The bus's ``plug()`` method is called, which triggers the device driver's probe function.
+ The bus's ``probe_device()`` method is called, which triggers the device driver's probe function.
The probe function typically allocates device-specific resources,
maps device memory regions, initializes device hardware,
and registers the device with the appropriate subsystem (e.g., ethdev for network devices).
diff --git a/lib/eal/common/eal_common_dev.c b/lib/eal/common/eal_common_dev.c
index 48b631532a..2a2103ec57 100644
--- a/lib/eal/common/eal_common_dev.c
+++ b/lib/eal/common/eal_common_dev.c
@@ -193,7 +193,7 @@ local_dev_probe(const char *devargs, struct rte_device **new_dev)
goto err_devarg;
if (da->bus->probe_device == NULL) {
- EAL_LOG(ERR, "Function plug not supported by bus (%s)",
+ EAL_LOG(ERR, "Function probe_device not supported by bus (%s)",
da->bus->name);
ret = -ENOTSUP;
goto err_devarg;
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH 02/13] dma/idxd: remove next pointer in bus specific device
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
2026-06-11 9:45 ` [PATCH 01/13] bus: fix reference to plug callback David Marchand
@ 2026-06-11 9:45 ` David Marchand
2026-06-11 9:45 ` [PATCH 03/13] bus/vdev: remove driver setting in probe David Marchand
` (14 subsequent siblings)
16 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen, Kevin Laatz
The dma/idxd devices are now stored in a list of generic rte_device
objects.
Fixes: b4f0974a995b ("bus: factorize device list")
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/dma/idxd/idxd_bus.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/dma/idxd/idxd_bus.c b/drivers/dma/idxd/idxd_bus.c
index 4810d52f2a..2ec526ec09 100644
--- a/drivers/dma/idxd/idxd_bus.c
+++ b/drivers/dma/idxd/idxd_bus.c
@@ -34,7 +34,6 @@ struct dsa_wq_addr {
/** a DSA device instance */
struct rte_dsa_device {
struct rte_device device; /**< Inherit core device */
- TAILQ_ENTRY(rte_dsa_device) next; /**< next dev in list */
char wq_name[32]; /**< the workqueue name/number e.g. wq0.1 */
struct dsa_wq_addr addr; /**< Identifies the specific WQ */
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH 03/13] bus/vdev: remove driver setting in probe
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
2026-06-11 9:45 ` [PATCH 01/13] bus: fix reference to plug callback David Marchand
2026-06-11 9:45 ` [PATCH 02/13] dma/idxd: remove next pointer in bus specific device David Marchand
@ 2026-06-11 9:45 ` David Marchand
2026-06-11 9:45 ` [PATCH 04/13] drivers/bus: cleanup device freeing in NXP bus David Marchand
` (13 subsequent siblings)
16 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen
Setting the device driver field is now the responsibility of EAL
(see local_dev_probe).
Yet, because of the VDEV API, rte_vdev_init() must be updated to mark
the device as probed.
Fixes: f282771a04ef ("bus: factorize driver reference")
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/vdev/vdev.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 3bddf8938c..673e8a73b2 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -188,7 +188,6 @@ vdev_probe_device(struct rte_driver *drv, struct rte_device *dev)
struct rte_vdev_driver *vdev_drv = RTE_BUS_DRIVER(drv, *vdev_drv);
const char *name;
enum rte_iova_mode iova_mode;
- int ret;
name = rte_vdev_device_name(vdev_dev);
VDEV_LOG(DEBUG, "Search driver to probe device %s", name);
@@ -200,10 +199,7 @@ vdev_probe_device(struct rte_driver *drv, struct rte_device *dev)
return -1;
}
- ret = vdev_drv->probe(vdev_dev);
- if (ret == 0)
- vdev_dev->device.driver = &vdev_drv->driver;
- return ret;
+ return vdev_drv->probe(vdev_dev);
}
/* The caller shall be responsible for thread-safe */
@@ -337,6 +333,8 @@ rte_vdev_init(const char *name, const char *args)
free(dev);
} else if (ret > 0) {
goto next_driver;
+ } else {
+ dev->device.driver = drv;
}
}
rte_spinlock_recursive_unlock(&vdev_device_list_lock);
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH 04/13] drivers/bus: cleanup device freeing in NXP bus
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (2 preceding siblings ...)
2026-06-11 9:45 ` [PATCH 03/13] bus/vdev: remove driver setting in probe David Marchand
@ 2026-06-11 9:45 ` David Marchand
2026-06-11 9:45 ` [PATCH 05/13] drivers/bus: allocate interrupt during probing " David Marchand
` (12 subsequent siblings)
16 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, Hemant Agrawal,
Sachin Saxena
Following the scan/probe refactoring, in the DPAA bus driver scan method,
the device list is empty at the time the pthread key object is allocated.
This leaves only one location that wants to release the whole device
list, so remove the dpaa_clean_device_list() helper.
Remove the same helper in FSLMC bus for consistency.
Fixes: cdefd2e980bd ("drivers/bus: initialize NXP bus specifics in scan")
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/dpaa/dpaa_bus.c | 15 ++-------------
drivers/bus/fslmc/fslmc_bus.c | 21 ++++++---------------
2 files changed, 8 insertions(+), 28 deletions(-)
diff --git a/drivers/bus/dpaa/dpaa_bus.c b/drivers/bus/dpaa/dpaa_bus.c
index ee467b94d5..a439c22071 100644
--- a/drivers/bus/dpaa/dpaa_bus.c
+++ b/drivers/bus/dpaa/dpaa_bus.c
@@ -193,8 +193,6 @@ dpaa_sec_available(void)
return -1;
}
-static void dpaa_clean_device_list(void);
-
static int
dpaa_create_device_list(void)
{
@@ -336,21 +334,13 @@ dpaa_create_device_list(void)
return 0;
cleanup:
- dpaa_clean_device_list();
- return ret;
-}
-
-static void
-dpaa_clean_device_list(void)
-{
- struct rte_dpaa_device *dev = NULL;
-
RTE_BUS_FOREACH_DEV(dev, &rte_dpaa_bus) {
rte_bus_remove_device(&rte_dpaa_bus, &dev->device);
rte_intr_instance_free(dev->intr_handle);
free(dev);
- dev = NULL;
}
+
+ return ret;
}
RTE_EXPORT_INTERNAL_SYMBOL(rte_dpaa_portal_init)
@@ -699,7 +689,6 @@ rte_dpaa_bus_scan(void)
ret = pthread_key_create(&dpaa_portal_key, dpaa_portal_finish);
if (ret) {
DPAA_BUS_LOG(DEBUG, "Unable to create pthread key. (%d)", ret);
- dpaa_clean_device_list();
return ret;
}
diff --git a/drivers/bus/fslmc/fslmc_bus.c b/drivers/bus/fslmc/fslmc_bus.c
index 88511d4dc7..5870863189 100644
--- a/drivers/bus/fslmc/fslmc_bus.c
+++ b/drivers/bus/fslmc/fslmc_bus.c
@@ -43,19 +43,6 @@ rte_fslmc_get_device_count(enum rte_dpaa2_dev_type device_type)
return fslmc_bus_device_count[device_type];
}
-static void
-cleanup_fslmc_device_list(void)
-{
- struct rte_dpaa2_device *dev;
-
- RTE_BUS_FOREACH_DEV(dev, &rte_fslmc_bus) {
- rte_bus_remove_device(&rte_fslmc_bus, &dev->device);
- rte_intr_instance_free(dev->intr_handle);
- free(dev);
- dev = NULL;
- }
-}
-
static int
compare_dpaa2_devname(struct rte_dpaa2_device *dev1,
struct rte_dpaa2_device *dev2)
@@ -305,6 +292,7 @@ fslmc_dev_compare(const char *name1, const char *name2)
static int
rte_fslmc_scan(void)
{
+ struct rte_dpaa2_device *dev;
int ret;
char fslmc_dirpath[PATH_MAX];
DIR *dir;
@@ -314,7 +302,6 @@ rte_fslmc_scan(void)
char *group_name;
if (process_once) {
- struct rte_dpaa2_device *dev;
DPAA2_BUS_DEBUG("Fslmc bus already scanned. Not rescanning");
RTE_BUS_FOREACH_DEV(dev, &rte_fslmc_bus) {
@@ -416,7 +403,11 @@ rte_fslmc_scan(void)
closedir(dir);
/* Remove all devices in the list */
- cleanup_fslmc_device_list();
+ RTE_BUS_FOREACH_DEV(dev, &rte_fslmc_bus) {
+ rte_bus_remove_device(&rte_fslmc_bus, &dev->device);
+ rte_intr_instance_free(dev->intr_handle);
+ free(dev);
+ }
scan_fail:
DPAA2_BUS_DEBUG("FSLMC Bus Not Available. Skipping (%d)", ret);
/* Irrespective of failure, scan only return success */
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH 05/13] drivers/bus: allocate interrupt during probing in NXP bus
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (3 preceding siblings ...)
2026-06-11 9:45 ` [PATCH 04/13] drivers/bus: cleanup device freeing in NXP bus David Marchand
@ 2026-06-11 9:45 ` David Marchand
2026-06-11 9:45 ` [PATCH 06/13] bus/pci: fix mapping leak in bus cleanup David Marchand
` (11 subsequent siblings)
16 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, Hemant Agrawal,
Sachin Saxena
Allocating the interrupt handle is a waste of memory if no device is
probed later (like for example, if a allowlist is passed).
Instead, allocate this handle at the time probe_device is called.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/dpaa/dpaa_bus.c | 35 +++++++++++++----------------------
drivers/bus/fslmc/fslmc_bus.c | 27 +++++++++++++--------------
2 files changed, 26 insertions(+), 36 deletions(-)
diff --git a/drivers/bus/dpaa/dpaa_bus.c b/drivers/bus/dpaa/dpaa_bus.c
index a439c22071..3915e0a8b7 100644
--- a/drivers/bus/dpaa/dpaa_bus.c
+++ b/drivers/bus/dpaa/dpaa_bus.c
@@ -215,16 +215,6 @@ dpaa_create_device_list(void)
dev->device.numa_node = SOCKET_ID_ANY;
- /* Allocate interrupt handle instance */
- dev->intr_handle =
- rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
- if (dev->intr_handle == NULL) {
- DPAA_BUS_LOG(ERR, "Failed to allocate intr handle");
- ret = -ENOMEM;
- free(dev);
- goto cleanup;
- }
-
cfg = &dpaa_netcfg->port_cfg[i];
fman_intf = cfg->fman_if;
@@ -276,16 +266,6 @@ dpaa_create_device_list(void)
goto cleanup;
}
- /* Allocate interrupt handle instance */
- dev->intr_handle =
- rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
- if (dev->intr_handle == NULL) {
- DPAA_BUS_LOG(ERR, "Failed to allocate intr handle");
- ret = -ENOMEM;
- free(dev);
- goto cleanup;
- }
-
dev->device_type = FSL_DPAA_CRYPTO;
dev->id.dev_id = dpaa_bus.device_count + i;
@@ -336,7 +316,6 @@ dpaa_create_device_list(void)
cleanup:
RTE_BUS_FOREACH_DEV(dev, &rte_dpaa_bus) {
rte_bus_remove_device(&rte_dpaa_bus, &dev->device);
- rte_intr_instance_free(dev->intr_handle);
free(dev);
}
@@ -788,9 +767,19 @@ dpaa_bus_probe_device(struct rte_driver *drv, struct rte_device *dev)
struct rte_dpaa_driver *dpaa_drv = RTE_BUS_DRIVER(drv, *dpaa_drv);
int ret;
+ /* Allocate interrupt handle instance */
+ dpaa_dev->intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
+ if (dpaa_dev->intr_handle == NULL) {
+ DPAA_BUS_LOG(ERR, "Failed to allocate intr handle");
+ return -ENOMEM;
+ }
+
ret = dpaa_drv->probe(dpaa_drv, dpaa_dev);
- if (ret != 0)
+ if (ret != 0) {
+ rte_intr_instance_free(dpaa_dev->intr_handle);
+ dpaa_dev->intr_handle = NULL;
DPAA_BUS_ERR("unable to probe: %s", dpaa_dev->name);
+ }
return ret;
}
@@ -815,6 +804,8 @@ dpaa_bus_cleanup(void)
rte_errno = errno;
return -1;
}
+ rte_intr_instance_free(dev->intr_handle);
+ dev->intr_handle = NULL;
dev->device.driver = NULL;
}
dpaa_portal_finish((void *)DPAA_PER_LCORE_PORTAL);
diff --git a/drivers/bus/fslmc/fslmc_bus.c b/drivers/bus/fslmc/fslmc_bus.c
index 5870863189..fdc8bcb276 100644
--- a/drivers/bus/fslmc/fslmc_bus.c
+++ b/drivers/bus/fslmc/fslmc_bus.c
@@ -130,15 +130,6 @@ scan_one_fslmc_device(char *dev_name)
dev->device.numa_node = SOCKET_ID_ANY;
- /* Allocate interrupt instance */
- dev->intr_handle =
- rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
- if (dev->intr_handle == NULL) {
- DPAA2_BUS_ERR("Failed to allocate intr handle");
- ret = -ENOMEM;
- goto cleanup;
- }
-
/* Parse the device name and ID */
t_ptr = strtok(dup_dev_name, ".");
if (!t_ptr) {
@@ -199,10 +190,7 @@ scan_one_fslmc_device(char *dev_name)
return 0;
cleanup:
free(dup_dev_name);
- if (dev) {
- rte_intr_instance_free(dev->intr_handle);
- free(dev);
- }
+ free(dev);
return ret;
}
@@ -405,7 +393,6 @@ rte_fslmc_scan(void)
/* Remove all devices in the list */
RTE_BUS_FOREACH_DEV(dev, &rte_fslmc_bus) {
rte_bus_remove_device(&rte_fslmc_bus, &dev->device);
- rte_intr_instance_free(dev->intr_handle);
free(dev);
}
scan_fail:
@@ -511,9 +498,19 @@ fslmc_bus_probe_device(struct rte_driver *driver, struct rte_device *rte_dev)
return 0;
}
+ /* Allocate interrupt instance */
+ dev->intr_handle =
+ rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
+ if (dev->intr_handle == NULL) {
+ DPAA2_BUS_ERR("Failed to allocate intr handle");
+ return -ENOMEM;
+ }
+
ret = drv->probe(drv, dev);
if (ret != 0) {
DPAA2_BUS_ERR("Unable to probe");
+ rte_intr_instance_free(dev->intr_handle);
+ dev->intr_handle = NULL;
} else {
DPAA2_BUS_INFO("%s Plugged", dev->device.name);
}
@@ -529,6 +526,8 @@ fslmc_bus_unplug(struct rte_device *rte_dev)
if (drv->remove != NULL) {
drv->remove(dev);
+ rte_intr_instance_free(dev->intr_handle);
+ dev->intr_handle = NULL;
dev->device.driver = NULL;
DPAA2_BUS_INFO("%s Un-Plugged", dev->device.name);
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH 06/13] bus/pci: fix mapping leak in bus cleanup
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (4 preceding siblings ...)
2026-06-11 9:45 ` [PATCH 05/13] drivers/bus: allocate interrupt during probing " David Marchand
@ 2026-06-11 9:45 ` David Marchand
2026-06-11 9:45 ` [PATCH 07/13] bus/vmbus: fix interrupt leak in cleanup David Marchand
` (10 subsequent siblings)
16 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, stable,
Chenbo Xia, Nipun Gupta, Morten Brørup, Kevin Laatz
When calling this bus cleanup, PCI resources were not unmapped.
Fixes: 1cab1a40ea9b ("bus: cleanup devices on shutdown")
Cc: stable@dpdk.org
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/pci/pci_common.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index fd18b8772b..791e9a7b49 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -344,6 +344,10 @@ pci_cleanup(void)
rte_errno = errno;
error = -1;
}
+
+ if (drv->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+ rte_pci_unmap_device(dev);
+
dev->device.driver = NULL;
free:
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH 07/13] bus/vmbus: fix interrupt leak in cleanup
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (5 preceding siblings ...)
2026-06-11 9:45 ` [PATCH 06/13] bus/pci: fix mapping leak in bus cleanup David Marchand
@ 2026-06-11 9:45 ` David Marchand
2026-06-11 9:45 ` [PATCH 08/13] bus/vmbus: allocate interrupt during probing David Marchand
` (9 subsequent siblings)
16 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, stable, Long Li,
Wei Hu
When calling this bus cleanup, interrupt handle was not released.
Fixes: 65780eada9d9 ("bus/vmbus: support cleanup")
Cc: stable@dpdk.org
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/vmbus/vmbus_common.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index 01573927ce..74c1ddff69 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -150,6 +150,7 @@ rte_vmbus_cleanup(void)
error = -1;
rte_vmbus_unmap_device(dev);
+ rte_intr_instance_free(dev->intr_handle);
dev->device.driver = NULL;
rte_bus_remove_device(&rte_vmbus_bus, &dev->device);
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH 08/13] bus/vmbus: allocate interrupt during probing
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (6 preceding siblings ...)
2026-06-11 9:45 ` [PATCH 07/13] bus/vmbus: fix interrupt leak in cleanup David Marchand
@ 2026-06-11 9:45 ` David Marchand
2026-06-15 19:13 ` [EXTERNAL] " Long Li
2026-06-11 9:45 ` [PATCH 09/13] bus: align unplug with device probe David Marchand
` (8 subsequent siblings)
16 siblings, 1 reply; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen, Long Li, Wei Hu
Allocating the interrupt handle is a waste of memory if no device is
probed later (like for example, if a allowlist is passed).
Instead, allocate this handle at the time probe_device is called.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/vmbus/linux/vmbus_bus.c | 6 ------
drivers/bus/vmbus/vmbus_common.c | 18 +++++++++++++++++-
2 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/drivers/bus/vmbus/linux/vmbus_bus.c b/drivers/bus/vmbus/linux/vmbus_bus.c
index 0af10f6a69..77d904ad6d 100644
--- a/drivers/bus/vmbus/linux/vmbus_bus.c
+++ b/drivers/bus/vmbus/linux/vmbus_bus.c
@@ -345,12 +345,6 @@ vmbus_scan_one(const char *name)
}
}
- /* Allocate interrupt handle instance */
- dev->intr_handle =
- rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
- if (dev->intr_handle == NULL)
- goto error;
-
/* device is valid, add in list (sorted) */
VMBUS_LOG(DEBUG, "Adding vmbus device %s", name);
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index 74c1ddff69..b6ae82915f 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -108,11 +108,27 @@ vmbus_probe_device(struct rte_driver *drv, struct rte_device *dev)
if (vmbus_dev->device.numa_node < 0 && rte_socket_count() > 1)
VMBUS_LOG(INFO, "Device %s is not NUMA-aware", guid);
+ /* Allocate interrupt handle instance */
+ vmbus_dev->intr_handle =
+ rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
+ if (vmbus_dev->intr_handle == NULL) {
+ ret = -ENOMEM;
+ goto unmap;
+ }
+
/* call the driver probe() function */
VMBUS_LOG(INFO, " probe driver: %s", vmbus_drv->driver.name);
ret = vmbus_drv->probe(vmbus_drv, vmbus_dev);
if (ret != 0)
- rte_vmbus_unmap_device(vmbus_dev);
+ goto free_intr;
+
+ return 0;
+
+free_intr:
+ rte_intr_instance_free(vmbus_dev->intr_handle);
+ vmbus_dev->intr_handle = NULL;
+unmap:
+ rte_vmbus_unmap_device(vmbus_dev);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH 09/13] bus: align unplug with device probe
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (7 preceding siblings ...)
2026-06-11 9:45 ` [PATCH 08/13] bus/vmbus: allocate interrupt during probing David Marchand
@ 2026-06-11 9:45 ` David Marchand
2026-06-11 9:45 ` [PATCH 10/13] bus: implement cleanup in EAL David Marchand
` (7 subsequent siblings)
16 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, Parav Pandit,
Xueming Li, Nipun Gupta, Nikhil Agarwal, Hemant Agrawal,
Sachin Saxena, Rosen Xu, Chenbo Xia, Tomasz Duszynski
Refactor bus unplug operations to be the counterpart of probe_device.
The (renamed) unplug operation now only handles:
- Driver removal (calling the driver's remove callback)
- Freeing probe-allocated resources (interrupts, mappings)
Device deletion (devargs removal, bus removal, freeing device
structure) is now handled only during bus cleanup, not in unplug.
Additionally, move driver pointer clearing from individual bus unplug
operations to EAL's local_dev_remove() where the unplug operation is
invoked. This centralizes driver lifecycle management and eliminates
code duplication across bus drivers.
For vdev, add a check in rte_vdev_uninit() since this public API can
be called on devices without a driver attached.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
doc/guides/prog_guide/device_hotplug.rst | 18 ++++---
drivers/bus/auxiliary/auxiliary_common.c | 46 ++++++----------
drivers/bus/cdx/cdx.c | 29 ++--------
drivers/bus/fslmc/fslmc_bus.c | 5 +-
drivers/bus/ifpga/ifpga_bus.c | 63 ++++++++++------------
drivers/bus/pci/pci_common.c | 57 ++++----------------
drivers/bus/platform/platform.c | 16 +++---
drivers/bus/uacce/uacce.c | 67 ++++++++----------------
drivers/bus/vdev/vdev.c | 53 ++++++++-----------
lib/eal/common/eal_common_dev.c | 8 +--
lib/eal/include/bus_driver.h | 4 +-
11 files changed, 127 insertions(+), 239 deletions(-)
diff --git a/doc/guides/prog_guide/device_hotplug.rst b/doc/guides/prog_guide/device_hotplug.rst
index 7eb7fbcc2b..d21ba0c244 100644
--- a/doc/guides/prog_guide/device_hotplug.rst
+++ b/doc/guides/prog_guide/device_hotplug.rst
@@ -165,7 +165,7 @@ using ``rte_dev_event_callback_register()`` function.
on the device in question.
When ``RTE_DEV_EVENT_REMOVE`` event is delivered,
it indicates that the kernel has removed the device;
- the application should call ``rte_dev_remove()`` to clean up EAL resources.
+ the application should call ``rte_dev_remove()`` to unplug the device driver.
Event Notification Usage
@@ -256,13 +256,17 @@ When ``rte_dev_remove()`` is called, the following sequence occurs:
See `Multi-process Synchronization`_ for details.
#. **Device Unplug**:
- The bus's ``unplug()`` method is called (``dev->bus->unplug()``),
- which triggers the driver's remove function.
- This typically stops device operations, releases device resources,
- unmaps memory regions, and unregisters from subsystems.
+ The bus's ``unplug_device()`` method is called (``dev->bus->unplug_device()``),
+ which triggers the driver's remove function
+ and releases resources allocated during probe
+ (such as interrupt handles and device memory mappings).
-#. **Devargs Cleanup**:
- The devargs associated with the device are removed from the global list.
+.. note::
+
+ The device structure, its devargs, and its entry in the bus device list
+ are NOT freed during ``rte_dev_remove()``.
+ They remain in memory until ``rte_eal_cleanup()`` is called,
+ at which point the bus's ``cleanup()`` method handles complete device deletion.
Multi-process Synchronization
diff --git a/drivers/bus/auxiliary/auxiliary_common.c b/drivers/bus/auxiliary/auxiliary_common.c
index 048aacf254..10f466e57a 100644
--- a/drivers/bus/auxiliary/auxiliary_common.c
+++ b/drivers/bus/auxiliary/auxiliary_common.c
@@ -122,13 +122,11 @@ auxiliary_probe_device(struct rte_driver *drv, struct rte_device *dev)
return ret;
}
-/*
- * Call the remove() function of the driver.
- */
static int
-rte_auxiliary_driver_remove_dev(struct rte_auxiliary_device *dev)
+auxiliary_unplug_device(struct rte_device *rte_dev)
{
- const struct rte_auxiliary_driver *drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
+ const struct rte_auxiliary_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
+ struct rte_auxiliary_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
int ret = 0;
AUXILIARY_LOG(DEBUG, "Driver %s remove auxiliary device %s on NUMA node %i",
@@ -140,8 +138,8 @@ rte_auxiliary_driver_remove_dev(struct rte_auxiliary_device *dev)
return ret;
}
- /* clear driver structure */
- dev->device.driver = NULL;
+ rte_intr_instance_free(dev->intr_handle);
+ dev->intr_handle = NULL;
return 0;
}
@@ -181,22 +179,6 @@ rte_auxiliary_unregister(struct rte_auxiliary_driver *driver)
rte_bus_remove_driver(&auxiliary_bus, &driver->driver);
}
-static int
-auxiliary_unplug(struct rte_device *dev)
-{
- struct rte_auxiliary_device *adev = RTE_BUS_DEVICE(dev, *adev);
- int ret;
-
- ret = rte_auxiliary_driver_remove_dev(adev);
- if (ret == 0) {
- rte_bus_remove_device(&auxiliary_bus, &adev->device);
- rte_devargs_remove(dev->devargs);
- rte_intr_instance_free(adev->intr_handle);
- free(adev);
- }
- return ret;
-}
-
static int
auxiliary_cleanup(void)
{
@@ -206,13 +188,17 @@ auxiliary_cleanup(void)
RTE_BUS_FOREACH_DEV(dev, &auxiliary_bus) {
int ret;
- if (!rte_dev_is_probed(&dev->device))
- continue;
- ret = auxiliary_unplug(&dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = auxiliary_unplug_device(&dev->device);
+ if (ret < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
}
+
+ rte_devargs_remove(dev->device.devargs);
+ rte_bus_remove_device(&auxiliary_bus, &dev->device);
+ free(dev);
}
return error;
@@ -265,7 +251,7 @@ struct rte_bus auxiliary_bus = {
.find_device = rte_bus_generic_find_device,
.match = auxiliary_bus_match,
.probe_device = auxiliary_probe_device,
- .unplug = auxiliary_unplug,
+ .unplug_device = auxiliary_unplug_device,
.parse = auxiliary_parse,
.dma_map = auxiliary_dma_map,
.dma_unmap = auxiliary_dma_unmap,
diff --git a/drivers/bus/cdx/cdx.c b/drivers/bus/cdx/cdx.c
index 2443161e1a..c0b46a41ad 100644
--- a/drivers/bus/cdx/cdx.c
+++ b/drivers/bus/cdx/cdx.c
@@ -374,14 +374,11 @@ rte_cdx_unregister(struct rte_cdx_driver *driver)
rte_bus_remove_driver(&rte_cdx_bus, &driver->driver);
}
-/*
- * If vendor/device ID match, call the remove() function of the
- * driver.
- */
static int
-cdx_detach_dev(struct rte_cdx_device *dev)
+cdx_unplug_device(struct rte_device *rte_dev)
{
- const struct rte_cdx_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
+ const struct rte_cdx_driver *dr = RTE_BUS_DRIVER(rte_dev->driver, *dr);
+ struct rte_cdx_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
int ret = 0;
CDX_BUS_DEBUG("detach device %s using driver: %s",
@@ -393,9 +390,6 @@ cdx_detach_dev(struct rte_cdx_device *dev)
return ret;
}
- /* clear driver structure */
- dev->device.driver = NULL;
-
rte_cdx_unmap_device(dev);
rte_intr_instance_free(dev->intr_handle);
@@ -404,21 +398,6 @@ cdx_detach_dev(struct rte_cdx_device *dev)
return 0;
}
-static int
-cdx_unplug(struct rte_device *dev)
-{
- struct rte_cdx_device *cdx_dev = RTE_BUS_DEVICE(dev, *cdx_dev);
- int ret;
-
- ret = cdx_detach_dev(cdx_dev);
- if (ret == 0) {
- rte_bus_remove_device(&rte_cdx_bus, &cdx_dev->device);
- rte_devargs_remove(dev->devargs);
- free(cdx_dev);
- }
- return ret;
-}
-
static int
cdx_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
{
@@ -452,7 +431,7 @@ static struct rte_bus rte_cdx_bus = {
.find_device = rte_bus_generic_find_device,
.match = cdx_bus_match,
.probe_device = cdx_probe_device,
- .unplug = cdx_unplug,
+ .unplug_device = cdx_unplug_device,
.parse = cdx_parse,
.dma_map = cdx_dma_map,
.dma_unmap = cdx_dma_unmap,
diff --git a/drivers/bus/fslmc/fslmc_bus.c b/drivers/bus/fslmc/fslmc_bus.c
index fdc8bcb276..15164796ec 100644
--- a/drivers/bus/fslmc/fslmc_bus.c
+++ b/drivers/bus/fslmc/fslmc_bus.c
@@ -519,7 +519,7 @@ fslmc_bus_probe_device(struct rte_driver *driver, struct rte_device *rte_dev)
}
static int
-fslmc_bus_unplug(struct rte_device *rte_dev)
+fslmc_bus_unplug_device(struct rte_device *rte_dev)
{
struct rte_dpaa2_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
const struct rte_dpaa2_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
@@ -528,7 +528,6 @@ fslmc_bus_unplug(struct rte_device *rte_dev)
drv->remove(dev);
rte_intr_instance_free(dev->intr_handle);
dev->intr_handle = NULL;
- dev->device.driver = NULL;
DPAA2_BUS_INFO("%s Un-Plugged", dev->device.name);
return 0;
}
@@ -546,7 +545,7 @@ struct rte_bus rte_fslmc_bus = {
.get_iommu_class = rte_dpaa2_get_iommu_class,
.match = fslmc_bus_match,
.probe_device = fslmc_bus_probe_device,
- .unplug = fslmc_bus_unplug,
+ .unplug_device = fslmc_bus_unplug_device,
.dev_iterate = rte_bus_generic_dev_iterate,
};
diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c
index 2c22329f65..394b777916 100644
--- a/drivers/bus/ifpga/ifpga_bus.c
+++ b/drivers/bus/ifpga/ifpga_bus.c
@@ -276,6 +276,25 @@ ifpga_probe_device(struct rte_driver *drv, struct rte_device *dev)
return afu_drv->probe(afu_dev);
}
+static int
+ifpga_unplug_device(struct rte_device *dev)
+{
+ const struct rte_afu_driver *afu_drv = RTE_BUS_DRIVER(dev->driver, *afu_drv);
+ struct rte_afu_device *afu_dev = RTE_BUS_DEVICE(dev, *afu_dev);
+ int ret = 0;
+
+ if (afu_drv->remove) {
+ ret = afu_drv->remove(afu_dev);
+ if (ret)
+ return ret;
+ }
+
+ rte_intr_instance_free(afu_dev->intr_handle);
+ afu_dev->intr_handle = NULL;
+
+ return 0;
+}
+
/*
* Cleanup the content of the Intel FPGA bus, and call the remove() function
* for all registered devices.
@@ -287,52 +306,24 @@ ifpga_cleanup(void)
int error = 0;
RTE_BUS_FOREACH_DEV(afu_dev, &rte_ifpga_bus) {
- const struct rte_afu_driver *drv;
int ret = 0;
- if (!rte_dev_is_probed(&afu_dev->device))
- goto free;
- drv = RTE_BUS_DRIVER(afu_dev->device.driver, *drv);
- if (drv->remove == NULL)
- goto free;
-
- ret = drv->remove(afu_dev);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
+ if (rte_dev_is_probed(&afu_dev->device)) {
+ ret = ifpga_unplug_device(&afu_dev->device);
+ if (ret < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
}
- afu_dev->device.driver = NULL;
-free:
- rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
rte_devargs_remove(afu_dev->device.devargs);
- rte_intr_instance_free(afu_dev->intr_handle);
+ rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
free(afu_dev);
}
return error;
}
-static int
-ifpga_unplug(struct rte_device *dev)
-{
- struct rte_afu_device *afu_dev = RTE_BUS_DEVICE(dev, *afu_dev);
- const struct rte_afu_driver *afu_drv = RTE_BUS_DRIVER(dev->driver, *afu_drv);
- int ret;
-
- ret = afu_drv->remove(afu_dev);
- if (ret)
- return ret;
-
- rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
-
- rte_devargs_remove(dev->devargs);
- rte_intr_instance_free(afu_dev->intr_handle);
- free(afu_dev);
- return 0;
-
-}
-
static int
ifpga_parse(const char *name, void *addr)
{
@@ -384,7 +375,7 @@ static struct rte_bus rte_ifpga_bus = {
.find_device = rte_bus_generic_find_device,
.match = ifpga_bus_match,
.probe_device = ifpga_probe_device,
- .unplug = ifpga_unplug,
+ .unplug_device = ifpga_unplug_device,
.parse = ifpga_parse,
};
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 791e9a7b49..bf4822f7ec 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -282,13 +282,10 @@ pci_probe_device(struct rte_driver *drv, struct rte_device *dev)
return ret;
}
-/*
- * If vendor/device ID match, call the remove() function of the
- * driver.
- */
static int
-rte_pci_detach_dev(struct rte_pci_device *dev)
+pci_unplug_device(struct rte_device *rte_dev)
{
+ struct rte_pci_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
struct rte_pci_addr *loc;
const struct rte_pci_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
int ret = 0;
@@ -308,9 +305,6 @@ rte_pci_detach_dev(struct rte_pci_device *dev)
return ret;
}
- /* clear driver structure */
- dev->device.driver = NULL;
-
if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
/* unmap resources for devices that use igb_uio */
rte_pci_unmap_device(dev);
@@ -330,33 +324,17 @@ pci_cleanup(void)
int error = 0;
RTE_BUS_FOREACH_DEV(dev, &rte_pci_bus) {
- const struct rte_pci_driver *drv;
int ret = 0;
- if (!rte_dev_is_probed(&dev->device))
- goto free;
- drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
- if (drv->remove == NULL)
- goto free;
-
- ret = drv->remove(dev);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = pci_unplug_device(&dev->device);
+ if (ret < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
}
- if (drv->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
- rte_pci_unmap_device(dev);
-
- dev->device.driver = NULL;
-
-free:
- /* free interrupt handles */
- rte_intr_instance_free(dev->intr_handle);
- dev->intr_handle = NULL;
- rte_intr_instance_free(dev->vfio_req_intr_handle);
- dev->vfio_req_intr_handle = NULL;
-
+ rte_devargs_remove(dev->device.devargs);
rte_bus_remove_device(&rte_pci_bus, &dev->device);
pci_free(RTE_PCI_DEVICE_INTERNAL(dev));
}
@@ -521,21 +499,6 @@ pci_sigbus_handler(const void *failure_addr)
return ret;
}
-static int
-pci_unplug(struct rte_device *dev)
-{
- struct rte_pci_device *pdev = RTE_BUS_DEVICE(dev, *pdev);
- int ret;
-
- ret = rte_pci_detach_dev(pdev);
- if (ret == 0) {
- rte_bus_remove_device(&rte_pci_bus, &pdev->device);
- rte_devargs_remove(dev->devargs);
- pci_free(RTE_PCI_DEVICE_INTERNAL(pdev));
- }
- return ret;
-}
-
static int
pci_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
{
@@ -784,7 +747,7 @@ struct rte_bus rte_pci_bus = {
.find_device = rte_bus_generic_find_device,
.match = pci_bus_match,
.probe_device = pci_probe_device,
- .unplug = pci_unplug,
+ .unplug_device = pci_unplug_device,
.parse = pci_parse,
.dev_compare = pci_dev_compare,
.devargs_parse = rte_pci_devargs_parse,
diff --git a/drivers/bus/platform/platform.c b/drivers/bus/platform/platform.c
index 170a2e03d0..5b3c78a505 100644
--- a/drivers/bus/platform/platform.c
+++ b/drivers/bus/platform/platform.c
@@ -416,19 +416,15 @@ device_release_driver(struct rte_platform_device *pdev)
if (ret)
PLATFORM_LOG_LINE(WARNING, "failed to remove %s", pdev->name);
}
-
- pdev->device.driver = NULL;
}
static int
-platform_bus_unplug(struct rte_device *dev)
+platform_bus_unplug_device(struct rte_device *dev)
{
struct rte_platform_device *pdev = RTE_BUS_DEVICE(dev, *pdev);
device_release_driver(pdev);
device_cleanup(pdev);
- rte_devargs_remove(pdev->device.devargs);
- free(pdev);
return 0;
}
@@ -501,10 +497,12 @@ platform_bus_cleanup(void)
struct rte_platform_device *pdev;
RTE_BUS_FOREACH_DEV(pdev, &platform_bus) {
+ if (rte_dev_is_probed(&pdev->device))
+ platform_bus_unplug_device(&pdev->device);
+
+ rte_devargs_remove(pdev->device.devargs);
rte_bus_remove_device(&platform_bus, &pdev->device);
- if (!rte_dev_is_probed(&pdev->device))
- continue;
- platform_bus_unplug(&pdev->device);
+ free(pdev);
}
return 0;
@@ -516,7 +514,7 @@ static struct rte_bus platform_bus = {
.find_device = rte_bus_generic_find_device,
.match = platform_bus_match,
.probe_device = platform_bus_probe_device,
- .unplug = platform_bus_unplug,
+ .unplug_device = platform_bus_unplug_device,
.parse = platform_bus_parse,
.dma_map = platform_bus_dma_map,
.dma_unmap = platform_bus_dma_unmap,
diff --git a/drivers/bus/uacce/uacce.c b/drivers/bus/uacce/uacce.c
index 8a3c55b248..bfe1f26557 100644
--- a/drivers/bus/uacce/uacce.c
+++ b/drivers/bus/uacce/uacce.c
@@ -385,40 +385,10 @@ uacce_probe_device(struct rte_driver *drv, struct rte_device *dev)
}
static int
-uacce_cleanup(void)
+uacce_unplug_device(struct rte_device *rte_dev)
{
- struct rte_uacce_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &uacce_bus) {
- const struct rte_uacce_driver *dr;
- int ret = 0;
-
- if (!rte_dev_is_probed(&dev->device))
- goto free;
- dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
- if (dr->remove == NULL)
- goto free;
-
- ret = dr->remove(dev);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- dev->device.driver = NULL;
-
-free:
- rte_bus_remove_device(&uacce_bus, &dev->device);
- free(dev);
- }
-
- return error;
-}
-
-static int
-uacce_detach_dev(struct rte_uacce_device *dev)
-{
- const struct rte_uacce_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
+ const struct rte_uacce_driver *dr = RTE_BUS_DRIVER(rte_dev->driver, *dr);
+ struct rte_uacce_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
int ret = 0;
UACCE_BUS_DEBUG("detach device %s using driver: %s", dev->device.name, dr->driver.name);
@@ -429,25 +399,32 @@ uacce_detach_dev(struct rte_uacce_device *dev)
return ret;
}
- dev->device.driver = NULL;
-
return 0;
}
static int
-uacce_unplug(struct rte_device *dev)
+uacce_cleanup(void)
{
- struct rte_uacce_device *uacce_dev = RTE_BUS_DEVICE(dev, *uacce_dev);
- int ret;
+ struct rte_uacce_device *dev;
+ int error = 0;
- ret = uacce_detach_dev(uacce_dev);
- if (ret == 0) {
- rte_bus_remove_device(&uacce_bus, &uacce_dev->device);
- rte_devargs_remove(dev->devargs);
- free(uacce_dev);
+ RTE_BUS_FOREACH_DEV(dev, &uacce_bus) {
+ int ret = 0;
+
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = uacce_unplug_device(&dev->device);
+ if (ret < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
+ }
+
+ rte_devargs_remove(dev->device.devargs);
+ rte_bus_remove_device(&uacce_bus, &dev->device);
+ free(dev);
}
- return ret;
+ return error;
}
static int
@@ -577,7 +554,7 @@ static struct rte_bus uacce_bus = {
.cleanup = uacce_cleanup,
.match = uacce_bus_match,
.probe_device = uacce_probe_device,
- .unplug = uacce_unplug,
+ .unplug_device = uacce_unplug_device,
.find_device = rte_bus_generic_find_device,
.parse = uacce_parse,
.dev_iterate = rte_bus_generic_dev_iterate,
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 673e8a73b2..c2cd642119 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -342,19 +342,15 @@ rte_vdev_init(const char *name, const char *args)
}
static int
-vdev_remove_driver(struct rte_vdev_device *dev)
+vdev_unplug_device(struct rte_device *rte_dev)
{
- const char *name = rte_vdev_device_name(dev);
- const struct rte_vdev_driver *driver;
+ const struct rte_vdev_driver *driver = RTE_BUS_DRIVER(rte_dev->driver, *driver);
+ struct rte_vdev_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
- if (!dev->device.driver) {
- VDEV_LOG(DEBUG, "no driver attach to device %s", name);
- return 1;
- }
+ if (driver->remove)
+ return driver->remove(dev);
- driver = RTE_BUS_DRIVER(dev->device.driver, *driver);
-
- return driver->remove(dev);
+ return 0;
}
RTE_EXPORT_SYMBOL(rte_vdev_uninit)
@@ -375,7 +371,12 @@ rte_vdev_uninit(const char *name)
goto unlock;
}
- ret = vdev_remove_driver(dev);
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = vdev_unplug_device(&dev->device);
+ } else {
+ VDEV_LOG(DEBUG, "no driver attach to device %s", name);
+ ret = 1;
+ }
if (ret)
goto unlock;
@@ -552,27 +553,21 @@ vdev_cleanup(void)
struct rte_vdev_device *dev;
int error = 0;
+ rte_spinlock_recursive_lock(&vdev_device_list_lock);
RTE_BUS_FOREACH_DEV(dev, &rte_vdev_bus) {
- const struct rte_vdev_driver *drv;
int ret;
- if (!rte_dev_is_probed(&dev->device))
- goto free;
-
- drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
-
- if (drv->remove == NULL)
- goto free;
-
- ret = drv->remove(dev);
- if (ret < 0)
- error = -1;
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = vdev_unplug_device(&dev->device);
+ if (ret < 0)
+ error = -1;
+ }
- dev->device.driver = NULL;
-free:
+ rte_devargs_remove(dev->device.devargs);
rte_bus_remove_device(&rte_vdev_bus, &dev->device);
free(dev);
}
+ rte_spinlock_recursive_unlock(&vdev_device_list_lock);
return error;
}
@@ -590,12 +585,6 @@ vdev_find_device(const struct rte_bus *bus, const struct rte_device *start,
return dev;
}
-static int
-vdev_unplug(struct rte_device *dev)
-{
- return rte_vdev_uninit(dev->name);
-}
-
static enum rte_iova_mode
vdev_get_iommu_class(void)
{
@@ -622,7 +611,7 @@ static struct rte_bus rte_vdev_bus = {
.find_device = vdev_find_device,
.match = vdev_bus_match,
.probe_device = vdev_probe_device,
- .unplug = vdev_unplug,
+ .unplug_device = vdev_unplug_device,
.parse = vdev_parse,
.dma_map = vdev_dma_map,
.dma_unmap = vdev_dma_unmap,
diff --git a/lib/eal/common/eal_common_dev.c b/lib/eal/common/eal_common_dev.c
index 2a2103ec57..762ed09e21 100644
--- a/lib/eal/common/eal_common_dev.c
+++ b/lib/eal/common/eal_common_dev.c
@@ -385,19 +385,21 @@ local_dev_remove(struct rte_device *dev)
{
int ret;
- if (dev->bus->unplug == NULL) {
- EAL_LOG(ERR, "Function unplug not supported by bus (%s)",
+ if (dev->bus->unplug_device == NULL) {
+ EAL_LOG(ERR, "Function unplug_device not supported by bus (%s)",
dev->bus->name);
return -ENOTSUP;
}
- ret = dev->bus->unplug(dev);
+ ret = dev->bus->unplug_device(dev);
if (ret) {
EAL_LOG(ERR, "Driver cannot detach the device (%s)",
dev->name);
return (ret < 0) ? ret : -ENOENT;
}
+ dev->driver = NULL;
+
return 0;
}
diff --git a/lib/eal/include/bus_driver.h b/lib/eal/include/bus_driver.h
index 0a7e23d98d..1baf024539 100644
--- a/lib/eal/include/bus_driver.h
+++ b/lib/eal/include/bus_driver.h
@@ -114,7 +114,7 @@ typedef int (*rte_bus_probe_device_t)(struct rte_driver *drv, struct rte_device
* 0 on success.
* !0 on error.
*/
-typedef int (*rte_bus_unplug_t)(struct rte_device *dev);
+typedef int (*rte_bus_unplug_device_t)(struct rte_device *dev);
/**
* Bus specific parsing function.
@@ -336,7 +336,7 @@ struct rte_bus {
rte_bus_find_device_t find_device; /**< Find a device on the bus */
rte_bus_match_t match; /**< Check if driver matches device */
rte_bus_probe_device_t probe_device; /**< Probe single device with driver */
- rte_bus_unplug_t unplug; /**< Remove single device from driver */
+ rte_bus_unplug_device_t unplug_device; /**< Remove single device from driver */
rte_bus_parse_t parse; /**< Parse a device name */
rte_bus_dev_compare_t dev_compare; /**< Compare two device names */
rte_bus_devargs_parse_t devargs_parse; /**< Parse bus devargs */
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH 10/13] bus: implement cleanup in EAL
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (8 preceding siblings ...)
2026-06-11 9:45 ` [PATCH 09/13] bus: align unplug with device probe David Marchand
@ 2026-06-11 9:45 ` David Marchand
2026-06-11 9:45 ` [PATCH 11/13] bus/dpaa: support unplug David Marchand
` (6 subsequent siblings)
16 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, Parav Pandit,
Xueming Li, Nipun Gupta, Nikhil Agarwal, Hemant Agrawal,
Sachin Saxena, Rosen Xu, Chenbo Xia, Tomasz Duszynski, Long Li,
Wei Hu, Kevin Laatz
Introduce a generic cleanup helper rte_bus_generic_cleanup() that
eliminates code duplication across bus cleanup implementations:
unplug probed devices, remove devargs, remove from bus list,
and free device structures.
Add .free_device operation to struct rte_bus to allow buses to specify
how to free their device structures.
Add compile-time check in RTE_REGISTER_BUS macro to verify rte_device
is at offset 0.
Update all buses for the new .cleanup and RTE_REGISTER_BUS prototypes.
Convert to rte_bus_generic_cleanup() the buses that have both a .cleanup
and .unplug: this requires implementing .free_device for them.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/auxiliary/auxiliary_common.c | 30 ++-----------------
drivers/bus/cdx/cdx.c | 2 +-
drivers/bus/dpaa/dpaa_bus.c | 6 ++--
drivers/bus/fslmc/fslmc_bus.c | 4 +--
drivers/bus/ifpga/ifpga_bus.c | 34 ++-------------------
drivers/bus/pci/pci_common.c | 30 ++++---------------
drivers/bus/platform/platform.c | 22 ++------------
drivers/bus/uacce/uacce.c | 30 ++-----------------
drivers/bus/vdev/vdev.c | 22 ++++----------
drivers/bus/vmbus/vmbus_common.c | 8 ++---
drivers/dma/idxd/idxd_bus.c | 2 +-
lib/eal/common/eal_common_bus.c | 33 +++++++++++++++++++-
lib/eal/include/bus_driver.h | 38 ++++++++++++++++++++++--
13 files changed, 102 insertions(+), 159 deletions(-)
diff --git a/drivers/bus/auxiliary/auxiliary_common.c b/drivers/bus/auxiliary/auxiliary_common.c
index 10f466e57a..6a1fc14d59 100644
--- a/drivers/bus/auxiliary/auxiliary_common.c
+++ b/drivers/bus/auxiliary/auxiliary_common.c
@@ -179,31 +179,6 @@ rte_auxiliary_unregister(struct rte_auxiliary_driver *driver)
rte_bus_remove_driver(&auxiliary_bus, &driver->driver);
}
-static int
-auxiliary_cleanup(void)
-{
- struct rte_auxiliary_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &auxiliary_bus) {
- int ret;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = auxiliary_unplug_device(&dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&auxiliary_bus, &dev->device);
- free(dev);
- }
-
- return error;
-}
-
static int
auxiliary_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
{
@@ -247,7 +222,8 @@ auxiliary_get_iommu_class(void)
struct rte_bus auxiliary_bus = {
.scan = auxiliary_scan,
.probe = rte_bus_generic_probe,
- .cleanup = auxiliary_cleanup,
+ .free_device = free,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = auxiliary_bus_match,
.probe_device = auxiliary_probe_device,
@@ -259,5 +235,5 @@ struct rte_bus auxiliary_bus = {
.dev_iterate = rte_bus_generic_dev_iterate,
};
-RTE_REGISTER_BUS(auxiliary, auxiliary_bus);
+RTE_REGISTER_BUS(auxiliary, auxiliary_bus, struct rte_auxiliary_device);
RTE_LOG_REGISTER_DEFAULT(auxiliary_bus_logtype, NOTICE);
diff --git a/drivers/bus/cdx/cdx.c b/drivers/bus/cdx/cdx.c
index c0b46a41ad..d070e3b2a8 100644
--- a/drivers/bus/cdx/cdx.c
+++ b/drivers/bus/cdx/cdx.c
@@ -439,5 +439,5 @@ static struct rte_bus rte_cdx_bus = {
.dev_iterate = rte_bus_generic_dev_iterate,
};
-RTE_REGISTER_BUS(cdx, rte_cdx_bus);
+RTE_REGISTER_BUS(cdx, rte_cdx_bus, struct rte_cdx_device);
RTE_LOG_REGISTER_DEFAULT(cdx_logtype_bus, NOTICE);
diff --git a/drivers/bus/dpaa/dpaa_bus.c b/drivers/bus/dpaa/dpaa_bus.c
index 3915e0a8b7..69f071d007 100644
--- a/drivers/bus/dpaa/dpaa_bus.c
+++ b/drivers/bus/dpaa/dpaa_bus.c
@@ -785,12 +785,12 @@ dpaa_bus_probe_device(struct rte_driver *drv, struct rte_device *dev)
}
static int
-dpaa_bus_cleanup(void)
+dpaa_bus_cleanup(struct rte_bus *bus)
{
struct rte_dpaa_device *dev;
BUS_INIT_FUNC_TRACE();
- RTE_BUS_FOREACH_DEV(dev, &rte_dpaa_bus) {
+ RTE_BUS_FOREACH_DEV(dev, bus) {
const struct rte_dpaa_driver *drv;
int ret = 0;
@@ -853,5 +853,5 @@ static struct rte_dpaa_bus_private dpaa_bus = {
.device_count = 0,
};
-RTE_REGISTER_BUS(dpaa_bus, rte_dpaa_bus);
+RTE_REGISTER_BUS(dpaa_bus, rte_dpaa_bus, struct rte_dpaa_device);
RTE_LOG_REGISTER_DEFAULT(dpaa_logtype_bus, NOTICE);
diff --git a/drivers/bus/fslmc/fslmc_bus.c b/drivers/bus/fslmc/fslmc_bus.c
index 15164796ec..17350d69b8 100644
--- a/drivers/bus/fslmc/fslmc_bus.c
+++ b/drivers/bus/fslmc/fslmc_bus.c
@@ -414,7 +414,7 @@ fslmc_bus_match(const struct rte_driver *drv, const struct rte_device *dev)
}
static int
-rte_fslmc_close(void)
+rte_fslmc_close(struct rte_bus *bus __rte_unused)
{
int ret = 0;
@@ -549,5 +549,5 @@ struct rte_bus rte_fslmc_bus = {
.dev_iterate = rte_bus_generic_dev_iterate,
};
-RTE_REGISTER_BUS(fslmc, rte_fslmc_bus);
+RTE_REGISTER_BUS(fslmc, rte_fslmc_bus, struct rte_dpaa2_device);
RTE_LOG_REGISTER_DEFAULT(dpaa2_logtype_bus, NOTICE);
diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c
index 394b777916..e62cf371bd 100644
--- a/drivers/bus/ifpga/ifpga_bus.c
+++ b/drivers/bus/ifpga/ifpga_bus.c
@@ -295,35 +295,6 @@ ifpga_unplug_device(struct rte_device *dev)
return 0;
}
-/*
- * Cleanup the content of the Intel FPGA bus, and call the remove() function
- * for all registered devices.
- */
-static int
-ifpga_cleanup(void)
-{
- struct rte_afu_device *afu_dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(afu_dev, &rte_ifpga_bus) {
- int ret = 0;
-
- if (rte_dev_is_probed(&afu_dev->device)) {
- ret = ifpga_unplug_device(&afu_dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(afu_dev->device.devargs);
- rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
- free(afu_dev);
- }
-
- return error;
-}
-
static int
ifpga_parse(const char *name, void *addr)
{
@@ -371,7 +342,8 @@ ifpga_parse(const char *name, void *addr)
static struct rte_bus rte_ifpga_bus = {
.scan = ifpga_scan,
.probe = rte_bus_generic_probe,
- .cleanup = ifpga_cleanup,
+ .free_device = free,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = ifpga_bus_match,
.probe_device = ifpga_probe_device,
@@ -379,7 +351,7 @@ static struct rte_bus rte_ifpga_bus = {
.parse = ifpga_parse,
};
-RTE_REGISTER_BUS(ifpga, rte_ifpga_bus);
+RTE_REGISTER_BUS(ifpga, rte_ifpga_bus, struct rte_afu_device);
RTE_INIT(ifpga_bus_init)
{
RTE_VERIFY(strcmp(rte_ifpga_bus.name, RTE_STR(IFPGA_BUS_NAME)) == 0);
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index bf4822f7ec..dcc94b6bbd 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -317,29 +317,10 @@ pci_unplug_device(struct rte_device *rte_dev)
return 0;
}
-static int
-pci_cleanup(void)
+static void
+pci_free_device(void *dev)
{
- struct rte_pci_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &rte_pci_bus) {
- int ret = 0;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = pci_unplug_device(&dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&rte_pci_bus, &dev->device);
- pci_free(RTE_PCI_DEVICE_INTERNAL(dev));
- }
-
- return error;
+ pci_free(RTE_PCI_DEVICE_INTERNAL(dev));
}
/* dump one device */
@@ -743,7 +724,8 @@ struct rte_bus rte_pci_bus = {
.allow_multi_probe = true,
.scan = rte_pci_scan,
.probe = rte_bus_generic_probe,
- .cleanup = pci_cleanup,
+ .free_device = pci_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = pci_bus_match,
.probe_device = pci_probe_device,
@@ -759,5 +741,5 @@ struct rte_bus rte_pci_bus = {
.sigbus_handler = pci_sigbus_handler,
};
-RTE_REGISTER_BUS(pci, rte_pci_bus);
+RTE_REGISTER_BUS(pci, rte_pci_bus, struct rte_pci_device);
RTE_LOG_REGISTER_DEFAULT(pci_bus_logtype, NOTICE);
diff --git a/drivers/bus/platform/platform.c b/drivers/bus/platform/platform.c
index 5b3c78a505..cb315144b8 100644
--- a/drivers/bus/platform/platform.c
+++ b/drivers/bus/platform/platform.c
@@ -491,26 +491,11 @@ platform_bus_get_iommu_class(void)
return RTE_IOVA_DC;
}
-static int
-platform_bus_cleanup(void)
-{
- struct rte_platform_device *pdev;
-
- RTE_BUS_FOREACH_DEV(pdev, &platform_bus) {
- if (rte_dev_is_probed(&pdev->device))
- platform_bus_unplug_device(&pdev->device);
-
- rte_devargs_remove(pdev->device.devargs);
- rte_bus_remove_device(&platform_bus, &pdev->device);
- free(pdev);
- }
-
- return 0;
-}
-
static struct rte_bus platform_bus = {
.scan = platform_bus_scan,
.probe = rte_bus_generic_probe,
+ .free_device = free,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = platform_bus_match,
.probe_device = platform_bus_probe_device,
@@ -520,8 +505,7 @@ static struct rte_bus platform_bus = {
.dma_unmap = platform_bus_dma_unmap,
.get_iommu_class = platform_bus_get_iommu_class,
.dev_iterate = rte_bus_generic_dev_iterate,
- .cleanup = platform_bus_cleanup,
};
-RTE_REGISTER_BUS(platform, platform_bus);
+RTE_REGISTER_BUS(platform, platform_bus, struct rte_platform_device);
RTE_LOG_REGISTER_DEFAULT(platform_bus_logtype, NOTICE);
diff --git a/drivers/bus/uacce/uacce.c b/drivers/bus/uacce/uacce.c
index bfe1f26557..e2763b26d5 100644
--- a/drivers/bus/uacce/uacce.c
+++ b/drivers/bus/uacce/uacce.c
@@ -402,31 +402,6 @@ uacce_unplug_device(struct rte_device *rte_dev)
return 0;
}
-static int
-uacce_cleanup(void)
-{
- struct rte_uacce_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &uacce_bus) {
- int ret = 0;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = uacce_unplug_device(&dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&uacce_bus, &dev->device);
- free(dev);
- }
-
- return error;
-}
-
static int
uacce_parse(const char *name, void *addr)
{
@@ -551,7 +526,8 @@ rte_uacce_unregister(struct rte_uacce_driver *driver)
static struct rte_bus uacce_bus = {
.scan = uacce_scan,
.probe = rte_bus_generic_probe,
- .cleanup = uacce_cleanup,
+ .free_device = free,
+ .cleanup = rte_bus_generic_cleanup,
.match = uacce_bus_match,
.probe_device = uacce_probe_device,
.unplug_device = uacce_unplug_device,
@@ -560,5 +536,5 @@ static struct rte_bus uacce_bus = {
.dev_iterate = rte_bus_generic_dev_iterate,
};
-RTE_REGISTER_BUS(uacce, uacce_bus);
+RTE_REGISTER_BUS(uacce, uacce_bus, struct rte_uacce_device);
RTE_LOG_REGISTER_DEFAULT(uacce_bus_logtype, NOTICE);
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index c2cd642119..bb536803e4 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -548,25 +548,12 @@ vdev_scan(void)
}
static int
-vdev_cleanup(void)
+vdev_cleanup(struct rte_bus *bus)
{
- struct rte_vdev_device *dev;
- int error = 0;
+ int error;
rte_spinlock_recursive_lock(&vdev_device_list_lock);
- RTE_BUS_FOREACH_DEV(dev, &rte_vdev_bus) {
- int ret;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = vdev_unplug_device(&dev->device);
- if (ret < 0)
- error = -1;
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&rte_vdev_bus, &dev->device);
- free(dev);
- }
+ error = rte_bus_generic_cleanup(bus);
rte_spinlock_recursive_unlock(&vdev_device_list_lock);
return error;
@@ -607,6 +594,7 @@ vdev_get_iommu_class(void)
static struct rte_bus rte_vdev_bus = {
.scan = vdev_scan,
.probe = rte_bus_generic_probe,
+ .free_device = free,
.cleanup = vdev_cleanup,
.find_device = vdev_find_device,
.match = vdev_bus_match,
@@ -619,5 +607,5 @@ static struct rte_bus rte_vdev_bus = {
.dev_iterate = rte_bus_generic_dev_iterate,
};
-RTE_REGISTER_BUS(vdev, rte_vdev_bus);
+RTE_REGISTER_BUS(vdev, rte_vdev_bus, struct rte_vdev_device);
RTE_LOG_REGISTER_DEFAULT(vdev_logtype_bus, NOTICE);
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index b6ae82915f..4c4170a4b5 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -146,12 +146,12 @@ rte_vmbus_probe(void)
}
static int
-rte_vmbus_cleanup(void)
+rte_vmbus_cleanup(struct rte_bus *bus)
{
struct rte_vmbus_device *dev;
int error = 0;
- RTE_BUS_FOREACH_DEV(dev, &rte_vmbus_bus) {
+ RTE_BUS_FOREACH_DEV(dev, bus) {
const struct rte_vmbus_driver *drv;
int ret;
@@ -169,7 +169,7 @@ rte_vmbus_cleanup(void)
rte_intr_instance_free(dev->intr_handle);
dev->device.driver = NULL;
- rte_bus_remove_device(&rte_vmbus_bus, &dev->device);
+ rte_bus_remove_device(bus, &dev->device);
free(dev);
}
@@ -232,5 +232,5 @@ struct rte_bus rte_vmbus_bus = {
.dev_compare = vmbus_dev_compare,
};
-RTE_REGISTER_BUS(vmbus, rte_vmbus_bus);
+RTE_REGISTER_BUS(vmbus, rte_vmbus_bus, struct rte_vmbus_device);
RTE_LOG_REGISTER_DEFAULT(vmbus_logtype_bus, NOTICE);
diff --git a/drivers/dma/idxd/idxd_bus.c b/drivers/dma/idxd/idxd_bus.c
index 2ec526ec09..34fd9f90c9 100644
--- a/drivers/dma/idxd/idxd_bus.c
+++ b/drivers/dma/idxd/idxd_bus.c
@@ -346,7 +346,7 @@ dsa_addr_parse(const char *name, void *addr)
return 0;
}
-RTE_REGISTER_BUS(dsa, dsa_bus);
+RTE_REGISTER_BUS(dsa, dsa_bus, struct rte_dsa_device);
RTE_INIT(dsa_bus_init)
{
rte_bus_add_driver(&dsa_bus, &dsa_driver);
diff --git a/lib/eal/common/eal_common_bus.c b/lib/eal/common/eal_common_bus.c
index ca13ccce5b..9ba23516ee 100644
--- a/lib/eal/common/eal_common_bus.c
+++ b/lib/eal/common/eal_common_bus.c
@@ -124,6 +124,37 @@ rte_bus_generic_probe(struct rte_bus *bus)
return (probed && probed == failed) ? -1 : 0;
}
+/*
+ * Generic cleanup function for buses.
+ * Iterates through all devices on the bus, unplugs probed devices,
+ * removes devargs, removes devices from the bus list, and frees device structures.
+ */
+RTE_EXPORT_INTERNAL_SYMBOL(rte_bus_generic_cleanup)
+int
+rte_bus_generic_cleanup(struct rte_bus *bus)
+{
+ struct rte_device *dev;
+ int error = 0;
+
+ RTE_VERIFY(bus->free_device);
+ RTE_VERIFY(bus->unplug_device);
+
+ while ((dev = TAILQ_FIRST(&bus->device_list)) != NULL) {
+ if (rte_dev_is_probed(dev)) {
+ if (bus->unplug_device && bus->unplug_device(dev) < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
+ }
+
+ rte_devargs_remove(dev->devargs);
+ rte_bus_remove_device(bus, dev);
+ bus->free_device(dev);
+ }
+
+ return error;
+}
+
/* Probe all devices of all buses */
RTE_EXPORT_SYMBOL(rte_bus_probe)
int
@@ -164,7 +195,7 @@ eal_bus_cleanup(void)
TAILQ_FOREACH(bus, &rte_bus_list, next) {
if (bus->cleanup == NULL)
continue;
- if (bus->cleanup() != 0)
+ if (bus->cleanup(bus) != 0)
ret = -1;
}
diff --git a/lib/eal/include/bus_driver.h b/lib/eal/include/bus_driver.h
index 1baf024539..c7b956833c 100644
--- a/lib/eal/include/bus_driver.h
+++ b/lib/eal/include/bus_driver.h
@@ -6,6 +6,7 @@
#define BUS_DRIVER_H
#include <rte_bus.h>
+#include <rte_common.h>
#include <rte_compat.h>
#include <rte_dev.h>
#include <rte_eal.h>
@@ -239,17 +240,31 @@ typedef int (*rte_bus_hot_unplug_handler_t)(struct rte_device *dev);
*/
typedef int (*rte_bus_sigbus_handler_t)(const void *failure_addr);
+/**
+ * Free a bus-specific device structure.
+ *
+ * @param device
+ * Generic device pointer to free (will be cast to bus-specific type).
+ */
+typedef void (*rte_bus_free_device_t)(void *device);
+
/**
* Implementation specific cleanup function which is responsible for cleaning up
* devices on that bus with applicable drivers.
*
+ * The cleanup operation is the counterpart to scan, removing all devices added
+ * during scan.
+ *
* This is called while iterating over each registered bus.
*
+ * @param bus
+ * Pointer to the bus to cleanup.
+ *
* @return
* 0 for successful cleanup
* !0 for any error during cleanup
*/
-typedef int (*rte_bus_cleanup_t)(void);
+typedef int (*rte_bus_cleanup_t)(struct rte_bus *bus);
/**
* Check if a driver matches a device.
@@ -349,6 +364,7 @@ struct rte_bus {
/**< handle hot-unplug failure on the bus */
rte_bus_sigbus_handler_t sigbus_handler;
/**< handle sigbus error on the bus */
+ rte_bus_free_device_t free_device; /**< Free bus-specific device */
rte_bus_cleanup_t cleanup; /**< Cleanup devices on bus */
RTE_TAILQ_HEAD(, rte_device) device_list; /**< List of devices on the bus */
RTE_TAILQ_HEAD(, rte_driver) driver_list; /**< List of drivers on the bus */
@@ -414,9 +430,10 @@ void *rte_bus_generic_dev_iterate(const struct rte_bus *bus,
* Helper for Bus registration.
* The constructor has higher priority than PMD constructors.
*/
-#define RTE_REGISTER_BUS(nm, bus) \
+#define RTE_REGISTER_BUS(nm, bus, bus_dev_type) \
RTE_INIT_PRIO(businitfn_ ##nm, BUS) \
{\
+ RTE_BUILD_BUG_ON(offsetof(typeof(bus_dev_type), device) != 0); \
(bus).name = RTE_STR(nm);\
rte_bus_register(&bus); \
}
@@ -637,6 +654,23 @@ struct rte_driver *rte_bus_find_driver(const struct rte_bus *bus, const struct r
__rte_internal
int rte_bus_generic_probe(struct rte_bus *bus);
+/**
+ * Generic cleanup function for buses.
+ *
+ * Iterates through all devices on the bus, unplugs probed devices,
+ * removes devargs, removes devices from the bus list, and frees device structures.
+ *
+ * This function can be used by buses that don't require special cleanup
+ * logic and just need the standard device cleanup sequence.
+ *
+ * @param bus
+ * Pointer to the bus to cleanup.
+ * @return
+ * 0 on success, -1 if any errors occurred during cleanup.
+ */
+__rte_internal
+int rte_bus_generic_cleanup(struct rte_bus *bus);
+
#ifdef __cplusplus
}
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH 11/13] bus/dpaa: support unplug
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (9 preceding siblings ...)
2026-06-11 9:45 ` [PATCH 10/13] bus: implement cleanup in EAL David Marchand
@ 2026-06-11 9:45 ` David Marchand
2026-06-11 9:45 ` [PATCH 12/13] bus/vmbus: store name in bus specific device David Marchand
` (5 subsequent siblings)
16 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, Hemant Agrawal,
Sachin Saxena
Add .unplug callback to handle driver removal and interrupt cleanup.
This enables use of the generic bus cleanup helper while preserving
bus-specific cleanup (portal finish, global init reset).
The cleanup function was already performing these operations, so it
seems safe to expose them through the unplug operation.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
doc/guides/rel_notes/release_26_07.rst | 4 +++
drivers/bus/dpaa/dpaa_bus.c | 48 +++++++++++++++-----------
2 files changed, 31 insertions(+), 21 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 5d7aa8d1bf..966f6501b4 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -114,6 +114,10 @@ New Features
Added no-IOMMU mode for devices without or not enabling IOMMU/SVA.
+* **bus/dpaa: Added unplug operation support.**
+
+ Implemented device unplug operation to allow runtime removal of DPAA devices.
+
* **Added selective Rx in ethdev API.**
Some parts of packets may be discarded in Rx
diff --git a/drivers/bus/dpaa/dpaa_bus.c b/drivers/bus/dpaa/dpaa_bus.c
index 69f071d007..6d4bec3751 100644
--- a/drivers/bus/dpaa/dpaa_bus.c
+++ b/drivers/bus/dpaa/dpaa_bus.c
@@ -785,34 +785,38 @@ dpaa_bus_probe_device(struct rte_driver *drv, struct rte_device *dev)
}
static int
-dpaa_bus_cleanup(struct rte_bus *bus)
+dpaa_bus_unplug_device(struct rte_device *rte_dev)
{
- struct rte_dpaa_device *dev;
+ const struct rte_dpaa_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
+ struct rte_dpaa_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
+ int ret = 0;
- BUS_INIT_FUNC_TRACE();
- RTE_BUS_FOREACH_DEV(dev, bus) {
- const struct rte_dpaa_driver *drv;
- int ret = 0;
-
- if (!rte_dev_is_probed(&dev->device))
- continue;
- drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
- if (drv->remove == NULL)
- continue;
+ if (drv->remove != NULL) {
ret = drv->remove(dev);
- if (ret < 0) {
- rte_errno = errno;
- return -1;
- }
- rte_intr_instance_free(dev->intr_handle);
- dev->intr_handle = NULL;
- dev->device.driver = NULL;
+ if (ret < 0)
+ return ret;
}
+
+ rte_intr_instance_free(dev->intr_handle);
+ dev->intr_handle = NULL;
+
+ return 0;
+}
+
+static int
+dpaa_bus_cleanup(struct rte_bus *bus)
+{
+ int ret;
+
+ BUS_INIT_FUNC_TRACE();
+
+ ret = rte_bus_generic_cleanup(bus);
+
dpaa_portal_finish((void *)DPAA_PER_LCORE_PORTAL);
dpaa_bus_global_init = 0;
DPAA_BUS_DEBUG("Bus cleanup done");
- return 0;
+ return ret;
}
/* Adding destructor for double check in case non-gracefully
@@ -838,14 +842,16 @@ RTE_FINI_PRIO(dpaa_cleanup, 102)
static struct rte_bus rte_dpaa_bus = {
.scan = rte_dpaa_bus_scan,
.probe = rte_bus_generic_probe,
+ .free_device = free,
+ .cleanup = dpaa_bus_cleanup,
.parse = rte_dpaa_bus_parse,
.dev_compare = dpaa_bus_dev_compare,
.find_device = rte_bus_generic_find_device,
.get_iommu_class = rte_dpaa_get_iommu_class,
.match = dpaa_bus_match,
.probe_device = dpaa_bus_probe_device,
+ .unplug_device = dpaa_bus_unplug_device,
.dev_iterate = rte_bus_generic_dev_iterate,
- .cleanup = dpaa_bus_cleanup,
};
static struct rte_dpaa_bus_private dpaa_bus = {
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH 12/13] bus/vmbus: store name in bus specific device
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (10 preceding siblings ...)
2026-06-11 9:45 ` [PATCH 11/13] bus/dpaa: support unplug David Marchand
@ 2026-06-11 9:45 ` David Marchand
2026-06-11 9:45 ` [PATCH 13/13] bus/vmbus: support unplug David Marchand
` (4 subsequent siblings)
16 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen, Long Li, Wei Hu
The device name is allocated with strdup() during scan and freed in
several places. However, when this bus cleanup is converted to use the
EAL generic helper, freeing the device object will require a custom
helper to also free the device name (and for this, a cast will be
needed).
Instead, add an embedded name array to rte_vmbus_device structure
(char name[RTE_DEV_NAME_MAX_LEN]) which is sufficient for all VMBUS
device names (UUID format: 36 characters, or shorter legacy format).
This simplifies the device freeing to a simple free() call.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/vmbus/bus_vmbus_driver.h | 1 +
drivers/bus/vmbus/linux/vmbus_bus.c | 10 +++-------
2 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/bus/vmbus/bus_vmbus_driver.h b/drivers/bus/vmbus/bus_vmbus_driver.h
index 888d856141..706ff1fcf5 100644
--- a/drivers/bus/vmbus/bus_vmbus_driver.h
+++ b/drivers/bus/vmbus/bus_vmbus_driver.h
@@ -38,6 +38,7 @@ enum hv_uio_map {
*/
struct rte_vmbus_device {
struct rte_device device; /**< Inherit core device */
+ char name[RTE_DEV_NAME_MAX_LEN]; /**< VMBUS device name */
rte_uuid_t device_id; /**< VMBUS device id */
rte_uuid_t class_id; /**< VMBUS device type */
uint32_t relid; /**< id for primary */
diff --git a/drivers/bus/vmbus/linux/vmbus_bus.c b/drivers/bus/vmbus/linux/vmbus_bus.c
index 77d904ad6d..779ea50b92 100644
--- a/drivers/bus/vmbus/linux/vmbus_bus.c
+++ b/drivers/bus/vmbus/linux/vmbus_bus.c
@@ -280,15 +280,14 @@ vmbus_scan_one(const char *name)
char filename[PATH_MAX];
char dirname[PATH_MAX];
unsigned long tmp;
- char *dev_name;
dev = calloc(1, sizeof(*dev));
if (dev == NULL)
return -1;
- dev->device.name = dev_name = strdup(name);
- if (!dev->device.name)
+ if (rte_strscpy(dev->name, name, sizeof(dev->name)) < 0)
goto error;
+ dev->device.name = dev->name;
/* sysfs base directory
* /sys/bus/vmbus/devices/7a08391f-f5a0-4ac0-9802-d13fd964f8df
@@ -305,7 +304,6 @@ vmbus_scan_one(const char *name)
/* skip non-network devices */
if (rte_uuid_compare(dev->class_id, vmbus_nic_uuid) != 0) {
- free(dev_name);
free(dev);
return 0;
}
@@ -330,7 +328,7 @@ vmbus_scan_one(const char *name)
dev->monitor_id = UINT8_MAX;
}
- dev->device.devargs = rte_bus_find_devargs(&rte_vmbus_bus, dev_name);
+ dev->device.devargs = rte_bus_find_devargs(&rte_vmbus_bus, dev->name);
dev->device.numa_node = SOCKET_ID_ANY;
if (vmbus_use_numa(dev)) {
@@ -360,7 +358,6 @@ vmbus_scan_one(const char *name)
} else { /* already registered */
VMBUS_LOG(NOTICE,
"%s already registered", name);
- free(dev_name);
free(dev);
}
return 0;
@@ -371,7 +368,6 @@ vmbus_scan_one(const char *name)
error:
VMBUS_LOG(DEBUG, "failed");
- free(dev_name);
free(dev);
return -1;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH 13/13] bus/vmbus: support unplug
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (11 preceding siblings ...)
2026-06-11 9:45 ` [PATCH 12/13] bus/vmbus: store name in bus specific device David Marchand
@ 2026-06-11 9:45 ` David Marchand
2026-06-11 10:09 ` [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (3 subsequent siblings)
16 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 9:45 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen, Long Li, Wei Hu
Add .unplug callback to handle driver removal, device unmapping, and
interrupt cleanup. This enables use of the generic bus cleanup helper.
The cleanup function was already performing these operations, so it
seems safe to expose them through the unplug operation.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
doc/guides/rel_notes/release_26_07.rst | 4 +++
drivers/bus/vmbus/vmbus_common.c | 37 ++++++++++----------------
2 files changed, 18 insertions(+), 23 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 966f6501b4..38e4dd87b3 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -118,6 +118,10 @@ New Features
Implemented device unplug operation to allow runtime removal of DPAA devices.
+* **bus/vmbus: Added unplug operation support.**
+
+ Implemented device unplug operation to allow runtime removal of VMBUS devices.
+
* **Added selective Rx in ethdev API.**
Some parts of packets may be discarded in Rx
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index 4c4170a4b5..419eb9b895 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -146,34 +146,23 @@ rte_vmbus_probe(void)
}
static int
-rte_vmbus_cleanup(struct rte_bus *bus)
+vmbus_unplug_device(struct rte_device *rte_dev)
{
- struct rte_vmbus_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, bus) {
- const struct rte_vmbus_driver *drv;
- int ret;
-
- if (!rte_dev_is_probed(&dev->device))
- continue;
- drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
- if (drv->remove == NULL)
- continue;
+ const struct rte_vmbus_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
+ struct rte_vmbus_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
+ int ret = 0;
+ if (drv->remove != NULL) {
ret = drv->remove(dev);
if (ret < 0)
- error = -1;
-
- rte_vmbus_unmap_device(dev);
- rte_intr_instance_free(dev->intr_handle);
-
- dev->device.driver = NULL;
- rte_bus_remove_device(bus, &dev->device);
- free(dev);
+ return ret;
}
- return error;
+ rte_vmbus_unmap_device(dev);
+ rte_intr_instance_free(dev->intr_handle);
+ dev->intr_handle = NULL;
+
+ return 0;
}
static int
@@ -224,10 +213,12 @@ rte_vmbus_unregister(struct rte_vmbus_driver *driver)
struct rte_bus rte_vmbus_bus = {
.scan = rte_vmbus_scan,
.probe = rte_bus_generic_probe,
- .cleanup = rte_vmbus_cleanup,
+ .free_device = free,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = vmbus_bus_match,
.probe_device = vmbus_probe_device,
+ .unplug_device = vmbus_unplug_device,
.parse = vmbus_parse,
.dev_compare = vmbus_dev_compare,
};
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [PATCH 00/13] Bus cleanup infrastructure and fixes
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (12 preceding siblings ...)
2026-06-11 9:45 ` [PATCH 13/13] bus/vmbus: support unplug David Marchand
@ 2026-06-11 10:09 ` David Marchand
2026-06-15 19:14 ` [EXTERNAL] " Long Li
` (2 subsequent siblings)
16 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-11 10:09 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen
On Thu, 11 Jun 2026 at 11:46, David Marchand <david.marchand@redhat.com> wrote:
>
> This is a followup of the previous bus refactoring.
> See https://inbox.dpdk.org/dev/CAJFAV8zvFpLwz8SY8DUUezyJyM43eRZ17Yj30ex808eHC4ZE=g@mail.gmail.com/.
>
> This series refactors the bus cleanup infrastructure to reduce code
> duplication and fix resource leaks in several bus drivers.
> It should address the leak Thomas pointed at.
>
> The first part of the series (patches 1-8) addresses several bugs and
> inconsistencies:
> - Documentation and log message inconsistencies from earlier bus
> refactoring
> - Device list management issues in dma/idxd and bus/vdev
> - Resource leaks in PCI and VMBUS bus cleanup (mappings and interrupts)
> - Simplified device freeing in NXP buses (DPAA and FSLMC)
> - Deferred interrupt allocation to probe time (NXP buses, VMBUS)
>
> The core infrastructure changes (patches 9-10) introduce the generic
> cleanup framework:
> - Refactors unplug operations to be the counterpart of probe_device
> - Implements rte_bus_generic_cleanup() to centralize cleanup logic
> - Adds .free_device operation to struct rte_bus
> - Adds compile-time verification that rte_device is at offset 0
>
> The final patches (11-13) convert remaining buses to use the generic
> cleanup helper:
> - DPAA bus: add unplug support
> - VMBUS bus: switch to embedded device name and add unplug support
>
> After this series, most buses use the generic cleanup helper, eliminating
> duplicated code and ensuring consistent cleanup behavior across the
> codebase.
The remaining bus that do not use the generic helper are:
- dma/idxd which has no unplug support,
- bus/cdx which has unplug support, but no cleanup (it should not be
that complex to achieve, but I did not try),
- bus/fslmc which has unplug support, but a strange cleanup that
does not do much except release some hw resources,
One important point is that the series in its current form induces a
change in behavior.
rte_dev_remove (iow unplugging a device) now leaves the dev object in
the bus list.
I chose this implementation as it makes the API more symmetric
(allocations in .scan are released in .cleanup, allocations in
.probe_device are released in .unplug_device).
I wonder if this would be problematic for the vdev bus in some usecase
where many ports are hotplugged then unplugged and never reused.
--
David Marchand
^ permalink raw reply [flat|nested] 55+ messages in thread
* RE: [EXTERNAL] [PATCH 08/13] bus/vmbus: allocate interrupt during probing
2026-06-11 9:45 ` [PATCH 08/13] bus/vmbus: allocate interrupt during probing David Marchand
@ 2026-06-15 19:13 ` Long Li
0 siblings, 0 replies; 55+ messages in thread
From: Long Li @ 2026-06-15 19:13 UTC (permalink / raw)
To: David Marchand, dev@dpdk.org
Cc: thomas@monjalon.net, stephen@networkplumber.org,
bruce.richardson@intel.com, fengchengwen@huawei.com, Wei Hu
> Allocating the interrupt handle is a waste of memory if no device is probed
> later (like for example, if a allowlist is passed).
> Instead, allocate this handle at the time probe_device is called.
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
> drivers/bus/vmbus/linux/vmbus_bus.c | 6 ------
> drivers/bus/vmbus/vmbus_common.c | 18 +++++++++++++++++-
> 2 files changed, 17 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/bus/vmbus/linux/vmbus_bus.c
> b/drivers/bus/vmbus/linux/vmbus_bus.c
> index 0af10f6a69..77d904ad6d 100644
> --- a/drivers/bus/vmbus/linux/vmbus_bus.c
> +++ b/drivers/bus/vmbus/linux/vmbus_bus.c
> @@ -345,12 +345,6 @@ vmbus_scan_one(const char *name)
> }
> }
>
> - /* Allocate interrupt handle instance */
> - dev->intr_handle =
> - rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
> - if (dev->intr_handle == NULL)
> - goto error;
> -
> /* device is valid, add in list (sorted) */
> VMBUS_LOG(DEBUG, "Adding vmbus device %s", name);
>
> diff --git a/drivers/bus/vmbus/vmbus_common.c
> b/drivers/bus/vmbus/vmbus_common.c
> index 74c1ddff69..b6ae82915f 100644
> --- a/drivers/bus/vmbus/vmbus_common.c
> +++ b/drivers/bus/vmbus/vmbus_common.c
> @@ -108,11 +108,27 @@ vmbus_probe_device(struct rte_driver *drv, struct
> rte_device *dev)
> if (vmbus_dev->device.numa_node < 0 && rte_socket_count() > 1)
> VMBUS_LOG(INFO, "Device %s is not NUMA-aware", guid);
>
> + /* Allocate interrupt handle instance */
> + vmbus_dev->intr_handle =
> + rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
> + if (vmbus_dev->intr_handle == NULL) {
> + ret = -ENOMEM;
> + goto unmap;
> + }
> +
> /* call the driver probe() function */
> VMBUS_LOG(INFO, " probe driver: %s", vmbus_drv->driver.name);
> ret = vmbus_drv->probe(vmbus_drv, vmbus_dev);
> if (ret != 0)
> - rte_vmbus_unmap_device(vmbus_dev);
> + goto free_intr;
> +
> + return 0;
> +
> +free_intr:
> + rte_intr_instance_free(vmbus_dev->intr_handle);
> + vmbus_dev->intr_handle = NULL;
> +unmap:
> + rte_vmbus_unmap_device(vmbus_dev);
>
> return ret;
> }
> --
> 2.53.0
rte_vmbus_map_device() needs intr_handle to already exist, so need to move rte_intr_instance_alloc to earlier before calling rte_vmbus_map_device(),
something like this:
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index 419eb9b895..f3bcb90e46 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -100,35 +100,33 @@ vmbus_probe_device(struct rte_driver *drv, struct rte_device *dev)
return 1;
}
+ /* Allocate interrupt handle instance */
+ vmbus_dev->intr_handle =
+ rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
+ if (vmbus_dev->intr_handle == NULL)
+ return -ENOMEM;
+
/* map resources for device */
ret = rte_vmbus_map_device(vmbus_dev);
if (ret != 0)
- return ret;
+ goto free_intr;
if (vmbus_dev->device.numa_node < 0 && rte_socket_count() > 1)
VMBUS_LOG(INFO, "Device %s is not NUMA-aware", guid);
- /* Allocate interrupt handle instance */
- vmbus_dev->intr_handle =
- rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
- if (vmbus_dev->intr_handle == NULL) {
- ret = -ENOMEM;
- goto unmap;
- }
-
/* call the driver probe() function */
VMBUS_LOG(INFO, " probe driver: %s", vmbus_drv->driver.name);
ret = vmbus_drv->probe(vmbus_drv, vmbus_dev);
if (ret != 0)
- goto free_intr;
+ goto unmap;
return 0;
+unmap:
+ rte_vmbus_unmap_device(vmbus_dev);
free_intr:
rte_intr_instance_free(vmbus_dev->intr_handle);
vmbus_dev->intr_handle = NULL;
-unmap:
- rte_vmbus_unmap_device(vmbus_dev);
return ret;
}
^ permalink raw reply related [flat|nested] 55+ messages in thread
* RE: [EXTERNAL] [PATCH 00/13] Bus cleanup infrastructure and fixes
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (13 preceding siblings ...)
2026-06-11 10:09 ` [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
@ 2026-06-15 19:14 ` Long Li
2026-06-15 23:55 ` Long Li
2026-06-18 15:28 ` [PATCH v2 00/10] " David Marchand
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
16 siblings, 1 reply; 55+ messages in thread
From: Long Li @ 2026-06-15 19:14 UTC (permalink / raw)
To: David Marchand, dev@dpdk.org
Cc: thomas@monjalon.net, stephen@networkplumber.org,
bruce.richardson@intel.com, fengchengwen@huawei.com
> This is a followup of the previous bus refactoring.
> See
> https://inbox.dp/
> dk.org%2Fdev%2FCAJFAV8zvFpLwz8SY8DUUezyJyM43eRZ17Yj30ex808eHC4ZE%
> 3Dg%40mail.gmail.com%2F&data=05%7C02%7Clongli%40microsoft.com%7C2b
> fea821d6064273513d08dec79e460d%7C72f988bf86f141af91ab2d7cd011db47%
> 7C1%7C0%7C639167679756696197%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0e
> U1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIl
> dUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=wW8q%2FAt1AsVp2OHaK3OCLJrJo
> ar4KrjdKtf78hnDUyY%3D&reserved=0.
>
> This series refactors the bus cleanup infrastructure to reduce code duplication
> and fix resource leaks in several bus drivers.
> It should address the leak Thomas pointed at.
>
> The first part of the series (patches 1-8) addresses several bugs and
> inconsistencies:
> - Documentation and log message inconsistencies from earlier bus
> refactoring
> - Device list management issues in dma/idxd and bus/vdev
> - Resource leaks in PCI and VMBUS bus cleanup (mappings and interrupts)
> - Simplified device freeing in NXP buses (DPAA and FSLMC)
> - Deferred interrupt allocation to probe time (NXP buses, VMBUS)
>
> The core infrastructure changes (patches 9-10) introduce the generic cleanup
> framework:
> - Refactors unplug operations to be the counterpart of probe_device
> - Implements rte_bus_generic_cleanup() to centralize cleanup logic
> - Adds .free_device operation to struct rte_bus
> - Adds compile-time verification that rte_device is at offset 0
>
> The final patches (11-13) convert remaining buses to use the generic cleanup
> helper:
> - DPAA bus: add unplug support
> - VMBUS bus: switch to embedded device name and add unplug support
There is a hung on vmbus during device shutdown after applying the series, I'm looking into it.
^ permalink raw reply [flat|nested] 55+ messages in thread
* RE: [EXTERNAL] [PATCH 00/13] Bus cleanup infrastructure and fixes
2026-06-15 19:14 ` [EXTERNAL] " Long Li
@ 2026-06-15 23:55 ` Long Li
2026-06-16 6:55 ` David Marchand
0 siblings, 1 reply; 55+ messages in thread
From: Long Li @ 2026-06-15 23:55 UTC (permalink / raw)
To: David Marchand, dev@dpdk.org
Cc: thomas@monjalon.net, stephen@networkplumber.org,
bruce.richardson@intel.com, fengchengwen@huawei.com
>
> > This series refactors the bus cleanup infrastructure to reduce code
> > duplication and fix resource leaks in several bus drivers.
> > It should address the leak Thomas pointed at.
> >
> > The first part of the series (patches 1-8) addresses several bugs and
> > inconsistencies:
> > - Documentation and log message inconsistencies from earlier bus
> > refactoring
> > - Device list management issues in dma/idxd and bus/vdev
> > - Resource leaks in PCI and VMBUS bus cleanup (mappings and
> > interrupts)
> > - Simplified device freeing in NXP buses (DPAA and FSLMC)
> > - Deferred interrupt allocation to probe time (NXP buses, VMBUS)
> >
> > The core infrastructure changes (patches 9-10) introduce the generic
> > cleanup
> > framework:
> > - Refactors unplug operations to be the counterpart of probe_device
> > - Implements rte_bus_generic_cleanup() to centralize cleanup logic
> > - Adds .free_device operation to struct rte_bus
> > - Adds compile-time verification that rte_device is at offset 0
> >
> > The final patches (11-13) convert remaining buses to use the generic
> > cleanup
> > helper:
> > - DPAA bus: add unplug support
> > - VMBUS bus: switch to embedded device name and add unplug support
>
> There is a hung on vmbus during device shutdown after applying the series, I'm
> looking into it.
Turned out to be a test issue. Please see my comments on patch 08, the patch set tested well after that fix.
Long
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [EXTERNAL] [PATCH 00/13] Bus cleanup infrastructure and fixes
2026-06-15 23:55 ` Long Li
@ 2026-06-16 6:55 ` David Marchand
2026-06-16 7:47 ` David Marchand
0 siblings, 1 reply; 55+ messages in thread
From: David Marchand @ 2026-06-16 6:55 UTC (permalink / raw)
To: Long Li
Cc: dev@dpdk.org, thomas@monjalon.net, stephen@networkplumber.org,
bruce.richardson@intel.com, fengchengwen@huawei.com
On Tue, 16 Jun 2026 at 01:55, Long Li <longli@microsoft.com> wrote:
>
> >
> > > This series refactors the bus cleanup infrastructure to reduce code
> > > duplication and fix resource leaks in several bus drivers.
> > > It should address the leak Thomas pointed at.
> > >
> > > The first part of the series (patches 1-8) addresses several bugs and
> > > inconsistencies:
> > > - Documentation and log message inconsistencies from earlier bus
> > > refactoring
> > > - Device list management issues in dma/idxd and bus/vdev
> > > - Resource leaks in PCI and VMBUS bus cleanup (mappings and
> > > interrupts)
> > > - Simplified device freeing in NXP buses (DPAA and FSLMC)
> > > - Deferred interrupt allocation to probe time (NXP buses, VMBUS)
> > >
> > > The core infrastructure changes (patches 9-10) introduce the generic
> > > cleanup
> > > framework:
> > > - Refactors unplug operations to be the counterpart of probe_device
> > > - Implements rte_bus_generic_cleanup() to centralize cleanup logic
> > > - Adds .free_device operation to struct rte_bus
> > > - Adds compile-time verification that rte_device is at offset 0
> > >
> > > The final patches (11-13) convert remaining buses to use the generic
> > > cleanup
> > > helper:
> > > - DPAA bus: add unplug support
> > > - VMBUS bus: switch to embedded device name and add unplug support
> >
> > There is a hung on vmbus during device shutdown after applying the series, I'm
> > looking into it.
>
> Turned out to be a test issue. Please see my comments on patch 08, the patch set tested well after that fix.
Thanks a lot for testing!
I'll fix this regression in the next revision.
--
David Marchand
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [EXTERNAL] [PATCH 00/13] Bus cleanup infrastructure and fixes
2026-06-16 6:55 ` David Marchand
@ 2026-06-16 7:47 ` David Marchand
2026-06-17 9:16 ` Hemant Agrawal
0 siblings, 1 reply; 55+ messages in thread
From: David Marchand @ 2026-06-16 7:47 UTC (permalink / raw)
To: Hemant Agrawal
Cc: dev@dpdk.org, thomas@monjalon.net, stephen@networkplumber.org,
bruce.richardson@intel.com, fengchengwen@huawei.com, Long Li
On Tue, 16 Jun 2026 at 08:55, David Marchand <david.marchand@redhat.com> wrote:
>
> On Tue, 16 Jun 2026 at 01:55, Long Li <longli@microsoft.com> wrote:
> >
> > >
> > > > This series refactors the bus cleanup infrastructure to reduce code
> > > > duplication and fix resource leaks in several bus drivers.
> > > > It should address the leak Thomas pointed at.
> > > >
> > > > The first part of the series (patches 1-8) addresses several bugs and
> > > > inconsistencies:
> > > > - Documentation and log message inconsistencies from earlier bus
> > > > refactoring
> > > > - Device list management issues in dma/idxd and bus/vdev
> > > > - Resource leaks in PCI and VMBUS bus cleanup (mappings and
> > > > interrupts)
> > > > - Simplified device freeing in NXP buses (DPAA and FSLMC)
> > > > - Deferred interrupt allocation to probe time (NXP buses, VMBUS)
> > > >
> > > > The core infrastructure changes (patches 9-10) introduce the generic
> > > > cleanup
> > > > framework:
> > > > - Refactors unplug operations to be the counterpart of probe_device
> > > > - Implements rte_bus_generic_cleanup() to centralize cleanup logic
> > > > - Adds .free_device operation to struct rte_bus
> > > > - Adds compile-time verification that rte_device is at offset 0
> > > >
> > > > The final patches (11-13) convert remaining buses to use the generic
> > > > cleanup
> > > > helper:
> > > > - DPAA bus: add unplug support
> > > > - VMBUS bus: switch to embedded device name and add unplug support
> > >
> > > There is a hung on vmbus during device shutdown after applying the series, I'm
> > > looking into it.
> >
> > Turned out to be a test issue. Please see my comments on patch 08, the patch set tested well after that fix.
>
> Thanks a lot for testing!
>
> I'll fix this regression in the next revision.
Fyi Hemant, this series has a similar regression for dpaa/fslmc bus
(interrupt handle allocated too late in the device probing flow).
The implications seem greater than fixing vmbus though, as I am now
finding bugs on the cleanup side (interrupt eventfd are never closed,
for example).
I'll think about how to fix it in the next revision, one option may be
to leave dpaa/fslmc alone.. ?
But in the long run, all bus drivers should behave consistently.
I'll get back in this thread once I have a better view of the situation.
--
David Marchand
^ permalink raw reply [flat|nested] 55+ messages in thread
* RE: [EXTERNAL] [PATCH 00/13] Bus cleanup infrastructure and fixes
2026-06-16 7:47 ` David Marchand
@ 2026-06-17 9:16 ` Hemant Agrawal
2026-06-18 8:39 ` David Marchand
0 siblings, 1 reply; 55+ messages in thread
From: Hemant Agrawal @ 2026-06-17 9:16 UTC (permalink / raw)
To: David Marchand
Cc: dev@dpdk.org, thomas@monjalon.net, stephen@networkplumber.org,
bruce.richardson@intel.com, fengchengwen@huawei.com, Long Li
> -----Original Message-----
> From: David Marchand <david.marchand@redhat.com>
> Sent: 16 June 2026 13:17
> To: Hemant Agrawal <hemant.agrawal@nxp.com>
> Cc: dev@dpdk.org; thomas@monjalon.net; stephen@networkplumber.org;
> bruce.richardson@intel.com; fengchengwen@huawei.com; Long Li
> <longli@microsoft.com>
> Subject: Re: [EXTERNAL] [PATCH 00/13] Bus cleanup infrastructure and fixes
> Importance: High
>
> On Tue, 16 Jun 2026 at 08:55, David Marchand
> <david.marchand@redhat.com> wrote:
> >
> > On Tue, 16 Jun 2026 at 01:55, Long Li <longli@microsoft.com> wrote:
> > >
> > > >
> > > > > This series refactors the bus cleanup infrastructure to reduce
> > > > > code duplication and fix resource leaks in several bus drivers.
> > > > > It should address the leak Thomas pointed at.
> > > > >
> > > > > The first part of the series (patches 1-8) addresses several
> > > > > bugs and
> > > > > inconsistencies:
> > > > > - Documentation and log message inconsistencies from earlier bus
> > > > > refactoring
> > > > > - Device list management issues in dma/idxd and bus/vdev
> > > > > - Resource leaks in PCI and VMBUS bus cleanup (mappings and
> > > > > interrupts)
> > > > > - Simplified device freeing in NXP buses (DPAA and FSLMC)
> > > > > - Deferred interrupt allocation to probe time (NXP buses, VMBUS)
> > > > >
> > > > > The core infrastructure changes (patches 9-10) introduce the
> > > > > generic cleanup
> > > > > framework:
> > > > > - Refactors unplug operations to be the counterpart of
> > > > > probe_device
> > > > > - Implements rte_bus_generic_cleanup() to centralize cleanup
> > > > > logic
> > > > > - Adds .free_device operation to struct rte_bus
> > > > > - Adds compile-time verification that rte_device is at offset 0
> > > > >
> > > > > The final patches (11-13) convert remaining buses to use the
> > > > > generic cleanup
> > > > > helper:
> > > > > - DPAA bus: add unplug support
> > > > > - VMBUS bus: switch to embedded device name and add unplug
> > > > > support
> > > >
> > > > There is a hung on vmbus during device shutdown after applying the
> > > > series, I'm looking into it.
> > >
> > > Turned out to be a test issue. Please see my comments on patch 08, the
> patch set tested well after that fix.
> >
> > Thanks a lot for testing!
> >
> > I'll fix this regression in the next revision.
>
> Fyi Hemant, this series has a similar regression for dpaa/fslmc bus (interrupt
> handle allocated too late in the device probing flow).
> The implications seem greater than fixing vmbus though, as I am now finding
> bugs on the cleanup side (interrupt eventfd are never closed, for example).
>
> I'll think about how to fix it in the next revision, one option may be to leave
> dpaa/fslmc alone.. ?
> But in the long run, all bus drivers should behave consistently.
>
> I'll get back in this thread once I have a better view of the situation.
>
HI David,
Give me some time to get this tested on the hardware.
Regards
Hemant
>
> --
> David Marchand
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [EXTERNAL] [PATCH 00/13] Bus cleanup infrastructure and fixes
2026-06-17 9:16 ` Hemant Agrawal
@ 2026-06-18 8:39 ` David Marchand
2026-06-18 15:28 ` David Marchand
0 siblings, 1 reply; 55+ messages in thread
From: David Marchand @ 2026-06-18 8:39 UTC (permalink / raw)
To: Hemant Agrawal
Cc: dev@dpdk.org, thomas@monjalon.net, stephen@networkplumber.org,
bruce.richardson@intel.com, fengchengwen@huawei.com, Long Li
Hello Hemant,
On Wed, 17 Jun 2026 at 11:16, Hemant Agrawal <hemant.agrawal@nxp.com> wrote:
> > > > > There is a hung on vmbus during device shutdown after applying the
> > > > > series, I'm looking into it.
> > > >
> > > > Turned out to be a test issue. Please see my comments on patch 08, the
> > patch set tested well after that fix.
> > >
> > > Thanks a lot for testing!
> > >
> > > I'll fix this regression in the next revision.
> >
> > Fyi Hemant, this series has a similar regression for dpaa/fslmc bus (interrupt
> > handle allocated too late in the device probing flow).
> > The implications seem greater than fixing vmbus though, as I am now finding
> > bugs on the cleanup side (interrupt eventfd are never closed, for example).
> >
> > I'll think about how to fix it in the next revision, one option may be to leave
> > dpaa/fslmc alone.. ?
> > But in the long run, all bus drivers should behave consistently.
> >
> > I'll get back in this thread once I have a better view of the situation.
> >
>
> HI David,
> Give me some time to get this tested on the hardware.
Thanks!
If you did not start testing yet, please wait a bit more, I have a v2
that should address my concerns.
I hope I can send it in the next hours.
--
David Marchand
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v2 00/10] Bus cleanup infrastructure and fixes
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (14 preceding siblings ...)
2026-06-15 19:14 ` [EXTERNAL] " Long Li
@ 2026-06-18 15:28 ` David Marchand
2026-06-18 15:28 ` [PATCH v2 01/10] bus: fix reference to plug callback David Marchand
` (9 more replies)
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
16 siblings, 10 replies; 55+ messages in thread
From: David Marchand @ 2026-06-18 15:28 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal
This is a followup of the previous bus refactoring.
See https://inbox.dpdk.org/dev/CAJFAV8zvFpLwz8SY8DUUezyJyM43eRZ17Yj30ex808eHC4ZE=g@mail.gmail.com/.
This series refactors the bus cleanup infrastructure to reduce code
duplication and fix resource leaks in several bus drivers.
It should address the leak Thomas pointed at.
The first part of the series (patches 1-6) addresses several bugs and
inconsistencies:
- Documentation and log message inconsistencies from earlier bus
refactoring
- Device list management issues in dma/idxd and bus/vdev
- Resource leaks in PCI and VMBUS bus cleanup (mappings and interrupts)
- Deferred interrupt allocation to probe time (VMBUS)
The core infrastructure changes (patches 7-8) introduce the generic
cleanup framework:
- Refactors unplug operations to be the counterpart of probe_device
- Implements rte_bus_generic_cleanup() to centralize cleanup logic
- Adds .free_device operation to struct rte_bus
The final patches (9-10) convert the VMBUS bus to use the generic
cleanup helper.
After this series, most buses use the generic cleanup helper, eliminating
duplicated code and ensuring consistent cleanup behavior across the
codebase.
NXP bus drivers require more (leak) fixes and refactoring and
are left untouched.
--
David Marchand
Changes since v1:
- dropped all changes on DPAA and FSLMC bus,
- added one more cleanup on the first patch,
- changed coding style in rte_vdev_init,
- implemented explicit .free_device instead of hack for calling free(),
- reordered interrupt handle allocation in VMBUS bus,
David Marchand (10):
bus: fix reference to plug callback
dma/idxd: remove next pointer in bus specific device
bus/vdev: remove driver setting in probe
bus/pci: fix mapping leak in bus cleanup
bus/vmbus: fix interrupt leak in cleanup
bus/vmbus: allocate interrupt during probing
bus: align unplug with device probe
bus: implement cleanup in EAL
bus/vmbus: store name in bus specific device
bus/vmbus: support unplug
doc/guides/prog_guide/device_hotplug.rst | 20 ++++---
doc/guides/rel_notes/release_26_07.rst | 4 ++
drivers/bus/auxiliary/auxiliary_common.c | 54 ++++-------------
drivers/bus/cdx/cdx.c | 29 ++-------
drivers/bus/dpaa/dpaa_bus.c | 4 +-
drivers/bus/fslmc/fslmc_bus.c | 9 +--
drivers/bus/ifpga/ifpga_bus.c | 67 ++++++---------------
drivers/bus/pci/pci_common.c | 68 +++------------------
drivers/bus/platform/platform.c | 26 +++-----
drivers/bus/uacce/uacce.c | 59 +++---------------
drivers/bus/vdev/vdev.c | 76 +++++++++---------------
drivers/bus/vmbus/bus_vmbus_driver.h | 1 +
drivers/bus/vmbus/linux/vmbus_bus.c | 16 +----
drivers/bus/vmbus/vmbus_common.c | 58 +++++++++++-------
drivers/dma/idxd/idxd_bus.c | 1 -
lib/eal/common/eal_common_bus.c | 33 +++++++++-
lib/eal/common/eal_common_dev.c | 10 ++--
lib/eal/include/bus_driver.h | 51 +++++++++++-----
18 files changed, 222 insertions(+), 364 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v2 01/10] bus: fix reference to plug callback
2026-06-18 15:28 ` [PATCH v2 00/10] " David Marchand
@ 2026-06-18 15:28 ` David Marchand
2026-06-22 9:49 ` Bruce Richardson
2026-06-18 15:28 ` [PATCH v2 02/10] dma/idxd: remove next pointer in bus specific device David Marchand
` (8 subsequent siblings)
9 siblings, 1 reply; 55+ messages in thread
From: David Marchand @ 2026-06-18 15:28 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal
Remove now unused typedef, update documentation
and some log following the callback rename.
Fixes: 76622feba9e6 ("bus: refactor device probe")
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
Changes since v1:
- remove missed rte_bus_plug_t typedef,
---
doc/guides/prog_guide/device_hotplug.rst | 2 +-
lib/eal/common/eal_common_dev.c | 2 +-
lib/eal/include/bus_driver.h | 13 -------------
3 files changed, 2 insertions(+), 15 deletions(-)
diff --git a/doc/guides/prog_guide/device_hotplug.rst b/doc/guides/prog_guide/device_hotplug.rst
index 9896a097f3..7eb7fbcc2b 100644
--- a/doc/guides/prog_guide/device_hotplug.rst
+++ b/doc/guides/prog_guide/device_hotplug.rst
@@ -234,7 +234,7 @@ When ``rte_dev_probe()`` is called, the following sequence occurs:
and the attach operation fails if the device is not found.
#. **Device Probe**:
- The bus's ``plug()`` method is called, which triggers the device driver's probe function.
+ The bus's ``probe_device()`` method is called, which triggers the device driver's probe function.
The probe function typically allocates device-specific resources,
maps device memory regions, initializes device hardware,
and registers the device with the appropriate subsystem (e.g., ethdev for network devices).
diff --git a/lib/eal/common/eal_common_dev.c b/lib/eal/common/eal_common_dev.c
index 48b631532a..2a2103ec57 100644
--- a/lib/eal/common/eal_common_dev.c
+++ b/lib/eal/common/eal_common_dev.c
@@ -193,7 +193,7 @@ local_dev_probe(const char *devargs, struct rte_device **new_dev)
goto err_devarg;
if (da->bus->probe_device == NULL) {
- EAL_LOG(ERR, "Function plug not supported by bus (%s)",
+ EAL_LOG(ERR, "Function probe_device not supported by bus (%s)",
da->bus->name);
ret = -ENOTSUP;
goto err_devarg;
diff --git a/lib/eal/include/bus_driver.h b/lib/eal/include/bus_driver.h
index 0a7e23d98d..9711e6712b 100644
--- a/lib/eal/include/bus_driver.h
+++ b/lib/eal/include/bus_driver.h
@@ -75,19 +75,6 @@ typedef struct rte_device *
(*rte_bus_find_device_t)(const struct rte_bus *bus, const struct rte_device *start,
rte_dev_cmp_t cmp, const void *data);
-/**
- * Implementation specific probe function which is responsible for linking
- * devices on that bus with applicable drivers.
- *
- * @param dev
- * Device pointer that was returned by a previous call to find_device.
- *
- * @return
- * 0 on success.
- * !0 on error.
- */
-typedef int (*rte_bus_plug_t)(struct rte_device *dev);
-
/**
* Implementation specific probe function which is responsible for linking
* devices on that bus with applicable drivers.
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v2 02/10] dma/idxd: remove next pointer in bus specific device
2026-06-18 15:28 ` [PATCH v2 00/10] " David Marchand
2026-06-18 15:28 ` [PATCH v2 01/10] bus: fix reference to plug callback David Marchand
@ 2026-06-18 15:28 ` David Marchand
2026-06-22 9:48 ` Bruce Richardson
2026-06-18 15:28 ` [PATCH v2 03/10] bus/vdev: remove driver setting in probe David Marchand
` (7 subsequent siblings)
9 siblings, 1 reply; 55+ messages in thread
From: David Marchand @ 2026-06-18 15:28 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Kevin Laatz
The dma/idxd devices are now stored in a list of generic rte_device
objects.
Fixes: b4f0974a995b ("bus: factorize device list")
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/dma/idxd/idxd_bus.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/dma/idxd/idxd_bus.c b/drivers/dma/idxd/idxd_bus.c
index 4810d52f2a..2ec526ec09 100644
--- a/drivers/dma/idxd/idxd_bus.c
+++ b/drivers/dma/idxd/idxd_bus.c
@@ -34,7 +34,6 @@ struct dsa_wq_addr {
/** a DSA device instance */
struct rte_dsa_device {
struct rte_device device; /**< Inherit core device */
- TAILQ_ENTRY(rte_dsa_device) next; /**< next dev in list */
char wq_name[32]; /**< the workqueue name/number e.g. wq0.1 */
struct dsa_wq_addr addr; /**< Identifies the specific WQ */
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v2 03/10] bus/vdev: remove driver setting in probe
2026-06-18 15:28 ` [PATCH v2 00/10] " David Marchand
2026-06-18 15:28 ` [PATCH v2 01/10] bus: fix reference to plug callback David Marchand
2026-06-18 15:28 ` [PATCH v2 02/10] dma/idxd: remove next pointer in bus specific device David Marchand
@ 2026-06-18 15:28 ` David Marchand
2026-06-18 15:28 ` [PATCH v2 04/10] bus/pci: fix mapping leak in bus cleanup David Marchand
` (6 subsequent siblings)
9 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-18 15:28 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal
Setting the device driver field is not the responsibility of the
probe_device callback anymore, but that of EAL (see local_dev_probe).
Yet, because of the VDEV API, rte_vdev_init() must be updated to mark
the device as probed.
Fixes: f282771a04ef ("bus: factorize driver reference")
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
Changes since v1:
- implement the same way as EAL,
---
drivers/bus/vdev/vdev.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 3bddf8938c..09221ccdea 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -188,7 +188,6 @@ vdev_probe_device(struct rte_driver *drv, struct rte_device *dev)
struct rte_vdev_driver *vdev_drv = RTE_BUS_DRIVER(drv, *vdev_drv);
const char *name;
enum rte_iova_mode iova_mode;
- int ret;
name = rte_vdev_device_name(vdev_dev);
VDEV_LOG(DEBUG, "Search driver to probe device %s", name);
@@ -200,10 +199,7 @@ vdev_probe_device(struct rte_driver *drv, struct rte_device *dev)
return -1;
}
- ret = vdev_drv->probe(vdev_dev);
- if (ret == 0)
- vdev_dev->device.driver = &vdev_drv->driver;
- return ret;
+ return vdev_drv->probe(vdev_dev);
}
/* The caller shall be responsible for thread-safe */
@@ -328,7 +324,10 @@ rte_vdev_init(const char *name, const char *args)
} else if (rte_dev_is_probed(&dev->device)) {
ret = -EEXIST;
} else {
+ dev->device.driver = drv;
ret = rte_vdev_bus.probe_device(drv, &dev->device);
+ if (ret != 0)
+ dev->device.driver = NULL;
}
if (ret < 0) {
/* If fails, remove it from vdev list */
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v2 04/10] bus/pci: fix mapping leak in bus cleanup
2026-06-18 15:28 ` [PATCH v2 00/10] " David Marchand
` (2 preceding siblings ...)
2026-06-18 15:28 ` [PATCH v2 03/10] bus/vdev: remove driver setting in probe David Marchand
@ 2026-06-18 15:28 ` David Marchand
2026-06-18 15:28 ` [PATCH v2 05/10] bus/vmbus: fix interrupt leak in cleanup David Marchand
` (5 subsequent siblings)
9 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-18 15:28 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, stable, Chenbo Xia, Nipun Gupta,
Morten Brørup, Kevin Laatz
When calling this bus cleanup, PCI resources were not unmapped.
Fixes: 1cab1a40ea9b ("bus: cleanup devices on shutdown")
Cc: stable@dpdk.org
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/pci/pci_common.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index fd18b8772b..791e9a7b49 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -344,6 +344,10 @@ pci_cleanup(void)
rte_errno = errno;
error = -1;
}
+
+ if (drv->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+ rte_pci_unmap_device(dev);
+
dev->device.driver = NULL;
free:
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [EXTERNAL] [PATCH 00/13] Bus cleanup infrastructure and fixes
2026-06-18 8:39 ` David Marchand
@ 2026-06-18 15:28 ` David Marchand
0 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-18 15:28 UTC (permalink / raw)
To: Hemant Agrawal
Cc: dev@dpdk.org, thomas@monjalon.net, stephen@networkplumber.org,
bruce.richardson@intel.com, fengchengwen@huawei.com, Long Li
On Thu, 18 Jun 2026 at 10:39, David Marchand <david.marchand@redhat.com> wrote:
>
> Hello Hemant,
>
> On Wed, 17 Jun 2026 at 11:16, Hemant Agrawal <hemant.agrawal@nxp.com> wrote:
> > > > > > There is a hung on vmbus during device shutdown after applying the
> > > > > > series, I'm looking into it.
> > > > >
> > > > > Turned out to be a test issue. Please see my comments on patch 08, the
> > > patch set tested well after that fix.
> > > >
> > > > Thanks a lot for testing!
> > > >
> > > > I'll fix this regression in the next revision.
> > >
> > > Fyi Hemant, this series has a similar regression for dpaa/fslmc bus (interrupt
> > > handle allocated too late in the device probing flow).
> > > The implications seem greater than fixing vmbus though, as I am now finding
> > > bugs on the cleanup side (interrupt eventfd are never closed, for example).
> > >
> > > I'll think about how to fix it in the next revision, one option may be to leave
> > > dpaa/fslmc alone.. ?
> > > But in the long run, all bus drivers should behave consistently.
> > >
> > > I'll get back in this thread once I have a better view of the situation.
> > >
> >
> > HI David,
> > Give me some time to get this tested on the hardware.
>
> Thanks!
>
> If you did not start testing yet, please wait a bit more, I have a v2
> that should address my concerns.
> I hope I can send it in the next hours.
There are more complications and I am running out of time for this release.
I dropped all changes on dpaa and fslmc bus drivers for now.
v2, incoming.
--
David Marchand
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v2 05/10] bus/vmbus: fix interrupt leak in cleanup
2026-06-18 15:28 ` [PATCH v2 00/10] " David Marchand
` (3 preceding siblings ...)
2026-06-18 15:28 ` [PATCH v2 04/10] bus/pci: fix mapping leak in bus cleanup David Marchand
@ 2026-06-18 15:28 ` David Marchand
2026-06-19 22:04 ` [EXTERNAL] " Long Li
2026-06-18 15:28 ` [PATCH v2 06/10] bus/vmbus: allocate interrupt during probing David Marchand
` (4 subsequent siblings)
9 siblings, 1 reply; 55+ messages in thread
From: David Marchand @ 2026-06-18 15:28 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, stable, Wei Hu
When calling this bus cleanup, interrupt handle was not released.
Fixes: 65780eada9d9 ("bus/vmbus: support cleanup")
Cc: stable@dpdk.org
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/vmbus/vmbus_common.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index 01573927ce..74c1ddff69 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -150,6 +150,7 @@ rte_vmbus_cleanup(void)
error = -1;
rte_vmbus_unmap_device(dev);
+ rte_intr_instance_free(dev->intr_handle);
dev->device.driver = NULL;
rte_bus_remove_device(&rte_vmbus_bus, &dev->device);
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v2 06/10] bus/vmbus: allocate interrupt during probing
2026-06-18 15:28 ` [PATCH v2 00/10] " David Marchand
` (4 preceding siblings ...)
2026-06-18 15:28 ` [PATCH v2 05/10] bus/vmbus: fix interrupt leak in cleanup David Marchand
@ 2026-06-18 15:28 ` David Marchand
2026-06-19 22:05 ` [EXTERNAL] " Long Li
2026-06-18 15:28 ` [PATCH v2 07/10] bus: align unplug with device probe David Marchand
` (3 subsequent siblings)
9 siblings, 1 reply; 55+ messages in thread
From: David Marchand @ 2026-06-18 15:28 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Wei Hu
Allocating the interrupt handle is a waste of memory if no device is
probed later (like for example, if a allowlist is passed).
Instead, allocate this handle at the time probe_device is called.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
Changes since v1:
- fixed/reordered interrupt handle allocation,
---
drivers/bus/vmbus/linux/vmbus_bus.c | 6 ------
drivers/bus/vmbus/vmbus_common.c | 18 ++++++++++++++++--
2 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/drivers/bus/vmbus/linux/vmbus_bus.c b/drivers/bus/vmbus/linux/vmbus_bus.c
index 0af10f6a69..77d904ad6d 100644
--- a/drivers/bus/vmbus/linux/vmbus_bus.c
+++ b/drivers/bus/vmbus/linux/vmbus_bus.c
@@ -345,12 +345,6 @@ vmbus_scan_one(const char *name)
}
}
- /* Allocate interrupt handle instance */
- dev->intr_handle =
- rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
- if (dev->intr_handle == NULL)
- goto error;
-
/* device is valid, add in list (sorted) */
VMBUS_LOG(DEBUG, "Adding vmbus device %s", name);
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index 74c1ddff69..bfb45e963c 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -100,10 +100,16 @@ vmbus_probe_device(struct rte_driver *drv, struct rte_device *dev)
return 1;
}
+ /* allocate interrupt handle instance */
+ vmbus_dev->intr_handle =
+ rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
+ if (vmbus_dev->intr_handle == NULL)
+ return -ENOMEM;
+
/* map resources for device */
ret = rte_vmbus_map_device(vmbus_dev);
if (ret != 0)
- return ret;
+ goto free_intr;
if (vmbus_dev->device.numa_node < 0 && rte_socket_count() > 1)
VMBUS_LOG(INFO, "Device %s is not NUMA-aware", guid);
@@ -112,7 +118,15 @@ vmbus_probe_device(struct rte_driver *drv, struct rte_device *dev)
VMBUS_LOG(INFO, " probe driver: %s", vmbus_drv->driver.name);
ret = vmbus_drv->probe(vmbus_drv, vmbus_dev);
if (ret != 0)
- rte_vmbus_unmap_device(vmbus_dev);
+ goto unmap;
+
+ return 0;
+
+unmap:
+ rte_vmbus_unmap_device(vmbus_dev);
+free_intr:
+ rte_intr_instance_free(vmbus_dev->intr_handle);
+ vmbus_dev->intr_handle = NULL;
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v2 07/10] bus: align unplug with device probe
2026-06-18 15:28 ` [PATCH v2 00/10] " David Marchand
` (5 preceding siblings ...)
2026-06-18 15:28 ` [PATCH v2 06/10] bus/vmbus: allocate interrupt during probing David Marchand
@ 2026-06-18 15:28 ` David Marchand
2026-06-22 10:19 ` Bruce Richardson
2026-06-18 15:28 ` [PATCH v2 08/10] bus: implement cleanup in EAL David Marchand
` (2 subsequent siblings)
9 siblings, 1 reply; 55+ messages in thread
From: David Marchand @ 2026-06-18 15:28 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Parav Pandit, Xueming Li, Nipun Gupta,
Nikhil Agarwal, Sachin Saxena, Rosen Xu, Chenbo Xia,
Tomasz Duszynski
Refactor bus unplug operations to be the counterpart of probe_device.
The (renamed) unplug operation now only handles:
- Driver removal (calling the driver's remove callback)
- Freeing probe-allocated resources (interrupts, mappings)
Device deletion (devargs removal, bus removal, freeing device
structure) is now handled only during bus cleanup, not in unplug.
Additionally, move driver pointer clearing from individual bus unplug
operations to EAL's local_dev_remove() where the unplug operation is
invoked. This centralizes driver lifecycle management and eliminates
code duplication across bus drivers.
For vdev, add a check in rte_vdev_uninit() since this public API can
be called on devices without a driver attached.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
doc/guides/prog_guide/device_hotplug.rst | 18 ++++---
drivers/bus/auxiliary/auxiliary_common.c | 46 ++++++----------
drivers/bus/cdx/cdx.c | 29 ++--------
drivers/bus/fslmc/fslmc_bus.c | 7 +--
drivers/bus/ifpga/ifpga_bus.c | 63 ++++++++++------------
drivers/bus/pci/pci_common.c | 57 ++++----------------
drivers/bus/platform/platform.c | 16 +++---
drivers/bus/uacce/uacce.c | 67 ++++++++----------------
drivers/bus/vdev/vdev.c | 53 ++++++++-----------
lib/eal/common/eal_common_dev.c | 8 +--
lib/eal/include/bus_driver.h | 4 +-
11 files changed, 129 insertions(+), 239 deletions(-)
diff --git a/doc/guides/prog_guide/device_hotplug.rst b/doc/guides/prog_guide/device_hotplug.rst
index 7eb7fbcc2b..d21ba0c244 100644
--- a/doc/guides/prog_guide/device_hotplug.rst
+++ b/doc/guides/prog_guide/device_hotplug.rst
@@ -165,7 +165,7 @@ using ``rte_dev_event_callback_register()`` function.
on the device in question.
When ``RTE_DEV_EVENT_REMOVE`` event is delivered,
it indicates that the kernel has removed the device;
- the application should call ``rte_dev_remove()`` to clean up EAL resources.
+ the application should call ``rte_dev_remove()`` to unplug the device driver.
Event Notification Usage
@@ -256,13 +256,17 @@ When ``rte_dev_remove()`` is called, the following sequence occurs:
See `Multi-process Synchronization`_ for details.
#. **Device Unplug**:
- The bus's ``unplug()`` method is called (``dev->bus->unplug()``),
- which triggers the driver's remove function.
- This typically stops device operations, releases device resources,
- unmaps memory regions, and unregisters from subsystems.
+ The bus's ``unplug_device()`` method is called (``dev->bus->unplug_device()``),
+ which triggers the driver's remove function
+ and releases resources allocated during probe
+ (such as interrupt handles and device memory mappings).
-#. **Devargs Cleanup**:
- The devargs associated with the device are removed from the global list.
+.. note::
+
+ The device structure, its devargs, and its entry in the bus device list
+ are NOT freed during ``rte_dev_remove()``.
+ They remain in memory until ``rte_eal_cleanup()`` is called,
+ at which point the bus's ``cleanup()`` method handles complete device deletion.
Multi-process Synchronization
diff --git a/drivers/bus/auxiliary/auxiliary_common.c b/drivers/bus/auxiliary/auxiliary_common.c
index 048aacf254..10f466e57a 100644
--- a/drivers/bus/auxiliary/auxiliary_common.c
+++ b/drivers/bus/auxiliary/auxiliary_common.c
@@ -122,13 +122,11 @@ auxiliary_probe_device(struct rte_driver *drv, struct rte_device *dev)
return ret;
}
-/*
- * Call the remove() function of the driver.
- */
static int
-rte_auxiliary_driver_remove_dev(struct rte_auxiliary_device *dev)
+auxiliary_unplug_device(struct rte_device *rte_dev)
{
- const struct rte_auxiliary_driver *drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
+ const struct rte_auxiliary_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
+ struct rte_auxiliary_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
int ret = 0;
AUXILIARY_LOG(DEBUG, "Driver %s remove auxiliary device %s on NUMA node %i",
@@ -140,8 +138,8 @@ rte_auxiliary_driver_remove_dev(struct rte_auxiliary_device *dev)
return ret;
}
- /* clear driver structure */
- dev->device.driver = NULL;
+ rte_intr_instance_free(dev->intr_handle);
+ dev->intr_handle = NULL;
return 0;
}
@@ -181,22 +179,6 @@ rte_auxiliary_unregister(struct rte_auxiliary_driver *driver)
rte_bus_remove_driver(&auxiliary_bus, &driver->driver);
}
-static int
-auxiliary_unplug(struct rte_device *dev)
-{
- struct rte_auxiliary_device *adev = RTE_BUS_DEVICE(dev, *adev);
- int ret;
-
- ret = rte_auxiliary_driver_remove_dev(adev);
- if (ret == 0) {
- rte_bus_remove_device(&auxiliary_bus, &adev->device);
- rte_devargs_remove(dev->devargs);
- rte_intr_instance_free(adev->intr_handle);
- free(adev);
- }
- return ret;
-}
-
static int
auxiliary_cleanup(void)
{
@@ -206,13 +188,17 @@ auxiliary_cleanup(void)
RTE_BUS_FOREACH_DEV(dev, &auxiliary_bus) {
int ret;
- if (!rte_dev_is_probed(&dev->device))
- continue;
- ret = auxiliary_unplug(&dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = auxiliary_unplug_device(&dev->device);
+ if (ret < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
}
+
+ rte_devargs_remove(dev->device.devargs);
+ rte_bus_remove_device(&auxiliary_bus, &dev->device);
+ free(dev);
}
return error;
@@ -265,7 +251,7 @@ struct rte_bus auxiliary_bus = {
.find_device = rte_bus_generic_find_device,
.match = auxiliary_bus_match,
.probe_device = auxiliary_probe_device,
- .unplug = auxiliary_unplug,
+ .unplug_device = auxiliary_unplug_device,
.parse = auxiliary_parse,
.dma_map = auxiliary_dma_map,
.dma_unmap = auxiliary_dma_unmap,
diff --git a/drivers/bus/cdx/cdx.c b/drivers/bus/cdx/cdx.c
index 2443161e1a..c0b46a41ad 100644
--- a/drivers/bus/cdx/cdx.c
+++ b/drivers/bus/cdx/cdx.c
@@ -374,14 +374,11 @@ rte_cdx_unregister(struct rte_cdx_driver *driver)
rte_bus_remove_driver(&rte_cdx_bus, &driver->driver);
}
-/*
- * If vendor/device ID match, call the remove() function of the
- * driver.
- */
static int
-cdx_detach_dev(struct rte_cdx_device *dev)
+cdx_unplug_device(struct rte_device *rte_dev)
{
- const struct rte_cdx_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
+ const struct rte_cdx_driver *dr = RTE_BUS_DRIVER(rte_dev->driver, *dr);
+ struct rte_cdx_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
int ret = 0;
CDX_BUS_DEBUG("detach device %s using driver: %s",
@@ -393,9 +390,6 @@ cdx_detach_dev(struct rte_cdx_device *dev)
return ret;
}
- /* clear driver structure */
- dev->device.driver = NULL;
-
rte_cdx_unmap_device(dev);
rte_intr_instance_free(dev->intr_handle);
@@ -404,21 +398,6 @@ cdx_detach_dev(struct rte_cdx_device *dev)
return 0;
}
-static int
-cdx_unplug(struct rte_device *dev)
-{
- struct rte_cdx_device *cdx_dev = RTE_BUS_DEVICE(dev, *cdx_dev);
- int ret;
-
- ret = cdx_detach_dev(cdx_dev);
- if (ret == 0) {
- rte_bus_remove_device(&rte_cdx_bus, &cdx_dev->device);
- rte_devargs_remove(dev->devargs);
- free(cdx_dev);
- }
- return ret;
-}
-
static int
cdx_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
{
@@ -452,7 +431,7 @@ static struct rte_bus rte_cdx_bus = {
.find_device = rte_bus_generic_find_device,
.match = cdx_bus_match,
.probe_device = cdx_probe_device,
- .unplug = cdx_unplug,
+ .unplug_device = cdx_unplug_device,
.parse = cdx_parse,
.dma_map = cdx_dma_map,
.dma_unmap = cdx_dma_unmap,
diff --git a/drivers/bus/fslmc/fslmc_bus.c b/drivers/bus/fslmc/fslmc_bus.c
index c7549a361a..dca4c5b182 100644
--- a/drivers/bus/fslmc/fslmc_bus.c
+++ b/drivers/bus/fslmc/fslmc_bus.c
@@ -520,6 +520,7 @@ fslmc_bus_probe_device(struct rte_driver *driver, struct rte_device *rte_dev)
return 0;
}
+ /* FIXME: probe_device should allocate intr_handle */
ret = drv->probe(drv, dev);
if (ret != 0) {
DPAA2_BUS_ERR("Unable to probe");
@@ -531,7 +532,7 @@ fslmc_bus_probe_device(struct rte_driver *driver, struct rte_device *rte_dev)
}
static int
-fslmc_bus_unplug(struct rte_device *rte_dev)
+fslmc_bus_unplug_device(struct rte_device *rte_dev)
{
struct rte_dpaa2_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
const struct rte_dpaa2_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
@@ -540,7 +541,7 @@ fslmc_bus_unplug(struct rte_device *rte_dev)
int ret = drv->remove(dev);
if (ret != 0)
return ret;
- dev->device.driver = NULL;
+ /* FIXME: unplug_device should free intr_handle */
DPAA2_BUS_INFO("%s Un-Plugged", dev->device.name);
return 0;
}
@@ -558,7 +559,7 @@ struct rte_bus rte_fslmc_bus = {
.get_iommu_class = rte_dpaa2_get_iommu_class,
.match = fslmc_bus_match,
.probe_device = fslmc_bus_probe_device,
- .unplug = fslmc_bus_unplug,
+ .unplug_device = fslmc_bus_unplug_device,
.dev_iterate = rte_bus_generic_dev_iterate,
};
diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c
index 2c22329f65..394b777916 100644
--- a/drivers/bus/ifpga/ifpga_bus.c
+++ b/drivers/bus/ifpga/ifpga_bus.c
@@ -276,6 +276,25 @@ ifpga_probe_device(struct rte_driver *drv, struct rte_device *dev)
return afu_drv->probe(afu_dev);
}
+static int
+ifpga_unplug_device(struct rte_device *dev)
+{
+ const struct rte_afu_driver *afu_drv = RTE_BUS_DRIVER(dev->driver, *afu_drv);
+ struct rte_afu_device *afu_dev = RTE_BUS_DEVICE(dev, *afu_dev);
+ int ret = 0;
+
+ if (afu_drv->remove) {
+ ret = afu_drv->remove(afu_dev);
+ if (ret)
+ return ret;
+ }
+
+ rte_intr_instance_free(afu_dev->intr_handle);
+ afu_dev->intr_handle = NULL;
+
+ return 0;
+}
+
/*
* Cleanup the content of the Intel FPGA bus, and call the remove() function
* for all registered devices.
@@ -287,52 +306,24 @@ ifpga_cleanup(void)
int error = 0;
RTE_BUS_FOREACH_DEV(afu_dev, &rte_ifpga_bus) {
- const struct rte_afu_driver *drv;
int ret = 0;
- if (!rte_dev_is_probed(&afu_dev->device))
- goto free;
- drv = RTE_BUS_DRIVER(afu_dev->device.driver, *drv);
- if (drv->remove == NULL)
- goto free;
-
- ret = drv->remove(afu_dev);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
+ if (rte_dev_is_probed(&afu_dev->device)) {
+ ret = ifpga_unplug_device(&afu_dev->device);
+ if (ret < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
}
- afu_dev->device.driver = NULL;
-free:
- rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
rte_devargs_remove(afu_dev->device.devargs);
- rte_intr_instance_free(afu_dev->intr_handle);
+ rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
free(afu_dev);
}
return error;
}
-static int
-ifpga_unplug(struct rte_device *dev)
-{
- struct rte_afu_device *afu_dev = RTE_BUS_DEVICE(dev, *afu_dev);
- const struct rte_afu_driver *afu_drv = RTE_BUS_DRIVER(dev->driver, *afu_drv);
- int ret;
-
- ret = afu_drv->remove(afu_dev);
- if (ret)
- return ret;
-
- rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
-
- rte_devargs_remove(dev->devargs);
- rte_intr_instance_free(afu_dev->intr_handle);
- free(afu_dev);
- return 0;
-
-}
-
static int
ifpga_parse(const char *name, void *addr)
{
@@ -384,7 +375,7 @@ static struct rte_bus rte_ifpga_bus = {
.find_device = rte_bus_generic_find_device,
.match = ifpga_bus_match,
.probe_device = ifpga_probe_device,
- .unplug = ifpga_unplug,
+ .unplug_device = ifpga_unplug_device,
.parse = ifpga_parse,
};
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 791e9a7b49..bf4822f7ec 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -282,13 +282,10 @@ pci_probe_device(struct rte_driver *drv, struct rte_device *dev)
return ret;
}
-/*
- * If vendor/device ID match, call the remove() function of the
- * driver.
- */
static int
-rte_pci_detach_dev(struct rte_pci_device *dev)
+pci_unplug_device(struct rte_device *rte_dev)
{
+ struct rte_pci_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
struct rte_pci_addr *loc;
const struct rte_pci_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
int ret = 0;
@@ -308,9 +305,6 @@ rte_pci_detach_dev(struct rte_pci_device *dev)
return ret;
}
- /* clear driver structure */
- dev->device.driver = NULL;
-
if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
/* unmap resources for devices that use igb_uio */
rte_pci_unmap_device(dev);
@@ -330,33 +324,17 @@ pci_cleanup(void)
int error = 0;
RTE_BUS_FOREACH_DEV(dev, &rte_pci_bus) {
- const struct rte_pci_driver *drv;
int ret = 0;
- if (!rte_dev_is_probed(&dev->device))
- goto free;
- drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
- if (drv->remove == NULL)
- goto free;
-
- ret = drv->remove(dev);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = pci_unplug_device(&dev->device);
+ if (ret < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
}
- if (drv->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
- rte_pci_unmap_device(dev);
-
- dev->device.driver = NULL;
-
-free:
- /* free interrupt handles */
- rte_intr_instance_free(dev->intr_handle);
- dev->intr_handle = NULL;
- rte_intr_instance_free(dev->vfio_req_intr_handle);
- dev->vfio_req_intr_handle = NULL;
-
+ rte_devargs_remove(dev->device.devargs);
rte_bus_remove_device(&rte_pci_bus, &dev->device);
pci_free(RTE_PCI_DEVICE_INTERNAL(dev));
}
@@ -521,21 +499,6 @@ pci_sigbus_handler(const void *failure_addr)
return ret;
}
-static int
-pci_unplug(struct rte_device *dev)
-{
- struct rte_pci_device *pdev = RTE_BUS_DEVICE(dev, *pdev);
- int ret;
-
- ret = rte_pci_detach_dev(pdev);
- if (ret == 0) {
- rte_bus_remove_device(&rte_pci_bus, &pdev->device);
- rte_devargs_remove(dev->devargs);
- pci_free(RTE_PCI_DEVICE_INTERNAL(pdev));
- }
- return ret;
-}
-
static int
pci_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
{
@@ -784,7 +747,7 @@ struct rte_bus rte_pci_bus = {
.find_device = rte_bus_generic_find_device,
.match = pci_bus_match,
.probe_device = pci_probe_device,
- .unplug = pci_unplug,
+ .unplug_device = pci_unplug_device,
.parse = pci_parse,
.dev_compare = pci_dev_compare,
.devargs_parse = rte_pci_devargs_parse,
diff --git a/drivers/bus/platform/platform.c b/drivers/bus/platform/platform.c
index 170a2e03d0..5b3c78a505 100644
--- a/drivers/bus/platform/platform.c
+++ b/drivers/bus/platform/platform.c
@@ -416,19 +416,15 @@ device_release_driver(struct rte_platform_device *pdev)
if (ret)
PLATFORM_LOG_LINE(WARNING, "failed to remove %s", pdev->name);
}
-
- pdev->device.driver = NULL;
}
static int
-platform_bus_unplug(struct rte_device *dev)
+platform_bus_unplug_device(struct rte_device *dev)
{
struct rte_platform_device *pdev = RTE_BUS_DEVICE(dev, *pdev);
device_release_driver(pdev);
device_cleanup(pdev);
- rte_devargs_remove(pdev->device.devargs);
- free(pdev);
return 0;
}
@@ -501,10 +497,12 @@ platform_bus_cleanup(void)
struct rte_platform_device *pdev;
RTE_BUS_FOREACH_DEV(pdev, &platform_bus) {
+ if (rte_dev_is_probed(&pdev->device))
+ platform_bus_unplug_device(&pdev->device);
+
+ rte_devargs_remove(pdev->device.devargs);
rte_bus_remove_device(&platform_bus, &pdev->device);
- if (!rte_dev_is_probed(&pdev->device))
- continue;
- platform_bus_unplug(&pdev->device);
+ free(pdev);
}
return 0;
@@ -516,7 +514,7 @@ static struct rte_bus platform_bus = {
.find_device = rte_bus_generic_find_device,
.match = platform_bus_match,
.probe_device = platform_bus_probe_device,
- .unplug = platform_bus_unplug,
+ .unplug_device = platform_bus_unplug_device,
.parse = platform_bus_parse,
.dma_map = platform_bus_dma_map,
.dma_unmap = platform_bus_dma_unmap,
diff --git a/drivers/bus/uacce/uacce.c b/drivers/bus/uacce/uacce.c
index 8a3c55b248..bfe1f26557 100644
--- a/drivers/bus/uacce/uacce.c
+++ b/drivers/bus/uacce/uacce.c
@@ -385,40 +385,10 @@ uacce_probe_device(struct rte_driver *drv, struct rte_device *dev)
}
static int
-uacce_cleanup(void)
+uacce_unplug_device(struct rte_device *rte_dev)
{
- struct rte_uacce_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &uacce_bus) {
- const struct rte_uacce_driver *dr;
- int ret = 0;
-
- if (!rte_dev_is_probed(&dev->device))
- goto free;
- dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
- if (dr->remove == NULL)
- goto free;
-
- ret = dr->remove(dev);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- dev->device.driver = NULL;
-
-free:
- rte_bus_remove_device(&uacce_bus, &dev->device);
- free(dev);
- }
-
- return error;
-}
-
-static int
-uacce_detach_dev(struct rte_uacce_device *dev)
-{
- const struct rte_uacce_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
+ const struct rte_uacce_driver *dr = RTE_BUS_DRIVER(rte_dev->driver, *dr);
+ struct rte_uacce_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
int ret = 0;
UACCE_BUS_DEBUG("detach device %s using driver: %s", dev->device.name, dr->driver.name);
@@ -429,25 +399,32 @@ uacce_detach_dev(struct rte_uacce_device *dev)
return ret;
}
- dev->device.driver = NULL;
-
return 0;
}
static int
-uacce_unplug(struct rte_device *dev)
+uacce_cleanup(void)
{
- struct rte_uacce_device *uacce_dev = RTE_BUS_DEVICE(dev, *uacce_dev);
- int ret;
+ struct rte_uacce_device *dev;
+ int error = 0;
- ret = uacce_detach_dev(uacce_dev);
- if (ret == 0) {
- rte_bus_remove_device(&uacce_bus, &uacce_dev->device);
- rte_devargs_remove(dev->devargs);
- free(uacce_dev);
+ RTE_BUS_FOREACH_DEV(dev, &uacce_bus) {
+ int ret = 0;
+
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = uacce_unplug_device(&dev->device);
+ if (ret < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
+ }
+
+ rte_devargs_remove(dev->device.devargs);
+ rte_bus_remove_device(&uacce_bus, &dev->device);
+ free(dev);
}
- return ret;
+ return error;
}
static int
@@ -577,7 +554,7 @@ static struct rte_bus uacce_bus = {
.cleanup = uacce_cleanup,
.match = uacce_bus_match,
.probe_device = uacce_probe_device,
- .unplug = uacce_unplug,
+ .unplug_device = uacce_unplug_device,
.find_device = rte_bus_generic_find_device,
.parse = uacce_parse,
.dev_iterate = rte_bus_generic_dev_iterate,
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 09221ccdea..7e94f86e28 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -343,19 +343,15 @@ rte_vdev_init(const char *name, const char *args)
}
static int
-vdev_remove_driver(struct rte_vdev_device *dev)
+vdev_unplug_device(struct rte_device *rte_dev)
{
- const char *name = rte_vdev_device_name(dev);
- const struct rte_vdev_driver *driver;
+ const struct rte_vdev_driver *driver = RTE_BUS_DRIVER(rte_dev->driver, *driver);
+ struct rte_vdev_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
- if (!dev->device.driver) {
- VDEV_LOG(DEBUG, "no driver attach to device %s", name);
- return 1;
- }
+ if (driver->remove)
+ return driver->remove(dev);
- driver = RTE_BUS_DRIVER(dev->device.driver, *driver);
-
- return driver->remove(dev);
+ return 0;
}
RTE_EXPORT_SYMBOL(rte_vdev_uninit)
@@ -376,7 +372,12 @@ rte_vdev_uninit(const char *name)
goto unlock;
}
- ret = vdev_remove_driver(dev);
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = vdev_unplug_device(&dev->device);
+ } else {
+ VDEV_LOG(DEBUG, "no driver attach to device %s", name);
+ ret = 1;
+ }
if (ret)
goto unlock;
@@ -553,27 +554,21 @@ vdev_cleanup(void)
struct rte_vdev_device *dev;
int error = 0;
+ rte_spinlock_recursive_lock(&vdev_device_list_lock);
RTE_BUS_FOREACH_DEV(dev, &rte_vdev_bus) {
- const struct rte_vdev_driver *drv;
int ret;
- if (!rte_dev_is_probed(&dev->device))
- goto free;
-
- drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
-
- if (drv->remove == NULL)
- goto free;
-
- ret = drv->remove(dev);
- if (ret < 0)
- error = -1;
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = vdev_unplug_device(&dev->device);
+ if (ret < 0)
+ error = -1;
+ }
- dev->device.driver = NULL;
-free:
+ rte_devargs_remove(dev->device.devargs);
rte_bus_remove_device(&rte_vdev_bus, &dev->device);
free(dev);
}
+ rte_spinlock_recursive_unlock(&vdev_device_list_lock);
return error;
}
@@ -591,12 +586,6 @@ vdev_find_device(const struct rte_bus *bus, const struct rte_device *start,
return dev;
}
-static int
-vdev_unplug(struct rte_device *dev)
-{
- return rte_vdev_uninit(dev->name);
-}
-
static enum rte_iova_mode
vdev_get_iommu_class(void)
{
@@ -623,7 +612,7 @@ static struct rte_bus rte_vdev_bus = {
.find_device = vdev_find_device,
.match = vdev_bus_match,
.probe_device = vdev_probe_device,
- .unplug = vdev_unplug,
+ .unplug_device = vdev_unplug_device,
.parse = vdev_parse,
.dma_map = vdev_dma_map,
.dma_unmap = vdev_dma_unmap,
diff --git a/lib/eal/common/eal_common_dev.c b/lib/eal/common/eal_common_dev.c
index 2a2103ec57..762ed09e21 100644
--- a/lib/eal/common/eal_common_dev.c
+++ b/lib/eal/common/eal_common_dev.c
@@ -385,19 +385,21 @@ local_dev_remove(struct rte_device *dev)
{
int ret;
- if (dev->bus->unplug == NULL) {
- EAL_LOG(ERR, "Function unplug not supported by bus (%s)",
+ if (dev->bus->unplug_device == NULL) {
+ EAL_LOG(ERR, "Function unplug_device not supported by bus (%s)",
dev->bus->name);
return -ENOTSUP;
}
- ret = dev->bus->unplug(dev);
+ ret = dev->bus->unplug_device(dev);
if (ret) {
EAL_LOG(ERR, "Driver cannot detach the device (%s)",
dev->name);
return (ret < 0) ? ret : -ENOENT;
}
+ dev->driver = NULL;
+
return 0;
}
diff --git a/lib/eal/include/bus_driver.h b/lib/eal/include/bus_driver.h
index 9711e6712b..fde55ff06d 100644
--- a/lib/eal/include/bus_driver.h
+++ b/lib/eal/include/bus_driver.h
@@ -101,7 +101,7 @@ typedef int (*rte_bus_probe_device_t)(struct rte_driver *drv, struct rte_device
* 0 on success.
* !0 on error.
*/
-typedef int (*rte_bus_unplug_t)(struct rte_device *dev);
+typedef int (*rte_bus_unplug_device_t)(struct rte_device *dev);
/**
* Bus specific parsing function.
@@ -323,7 +323,7 @@ struct rte_bus {
rte_bus_find_device_t find_device; /**< Find a device on the bus */
rte_bus_match_t match; /**< Check if driver matches device */
rte_bus_probe_device_t probe_device; /**< Probe single device with driver */
- rte_bus_unplug_t unplug; /**< Remove single device from driver */
+ rte_bus_unplug_device_t unplug_device; /**< Remove single device from driver */
rte_bus_parse_t parse; /**< Parse a device name */
rte_bus_dev_compare_t dev_compare; /**< Compare two device names */
rte_bus_devargs_parse_t devargs_parse; /**< Parse bus devargs */
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v2 08/10] bus: implement cleanup in EAL
2026-06-18 15:28 ` [PATCH v2 00/10] " David Marchand
` (6 preceding siblings ...)
2026-06-18 15:28 ` [PATCH v2 07/10] bus: align unplug with device probe David Marchand
@ 2026-06-18 15:28 ` David Marchand
2026-06-22 10:26 ` Bruce Richardson
2026-06-18 15:28 ` [PATCH v2 09/10] bus/vmbus: store name in bus specific device David Marchand
2026-06-18 15:28 ` [PATCH v2 10/10] bus/vmbus: support unplug David Marchand
9 siblings, 1 reply; 55+ messages in thread
From: David Marchand @ 2026-06-18 15:28 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Parav Pandit, Xueming Li, Sachin Saxena, Rosen Xu,
Chenbo Xia, Nipun Gupta, Tomasz Duszynski, Wei Hu
Introduce a generic cleanup helper rte_bus_generic_cleanup() that
eliminates code duplication across bus cleanup implementations:
unplug probed devices, remove devargs, remove from bus list,
and free device structures.
Add .free_device operation to struct rte_bus to allow buses to specify
how to free their device structures.
Update all buses for the new .cleanup and RTE_REGISTER_BUS prototypes.
Convert to rte_bus_generic_cleanup() the buses that have both a .cleanup
and .unplug_device: this requires implementing .free_device for them.
Untouched buses are:
- dma/idxd which has no unplug support,
- bus/cdx which has unplug support, but no cleanup was implemented so
far,
- NXP buses:
- bus/dpaa and bus/fslmc have many issues on interrupt
allocation/setup/freeing or VFIO setup/release,
- bus/fslmc cleanup callback is actually implemented in its internal
VFIO layer and requires too much refactoring,
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
Changes since v1:
- dropped hack on using free() and the check in RTE_REGISTER_BUS,
---
drivers/bus/auxiliary/auxiliary_common.c | 28 ++++---------------
drivers/bus/dpaa/dpaa_bus.c | 4 +--
drivers/bus/fslmc/fslmc_bus.c | 2 +-
drivers/bus/ifpga/ifpga_bus.c | 32 ++++------------------
drivers/bus/pci/pci_common.c | 29 +++++---------------
drivers/bus/platform/platform.c | 20 ++++----------
drivers/bus/uacce/uacce.c | 28 ++++---------------
drivers/bus/vdev/vdev.c | 26 +++++++-----------
drivers/bus/vmbus/vmbus_common.c | 6 ++---
lib/eal/common/eal_common_bus.c | 33 ++++++++++++++++++++++-
lib/eal/include/bus_driver.h | 34 +++++++++++++++++++++++-
11 files changed, 107 insertions(+), 135 deletions(-)
diff --git a/drivers/bus/auxiliary/auxiliary_common.c b/drivers/bus/auxiliary/auxiliary_common.c
index 10f466e57a..80b90a4961 100644
--- a/drivers/bus/auxiliary/auxiliary_common.c
+++ b/drivers/bus/auxiliary/auxiliary_common.c
@@ -179,29 +179,10 @@ rte_auxiliary_unregister(struct rte_auxiliary_driver *driver)
rte_bus_remove_driver(&auxiliary_bus, &driver->driver);
}
-static int
-auxiliary_cleanup(void)
+static void
+auxiliary_free_device(struct rte_device *dev)
{
- struct rte_auxiliary_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &auxiliary_bus) {
- int ret;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = auxiliary_unplug_device(&dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&auxiliary_bus, &dev->device);
- free(dev);
- }
-
- return error;
+ free(RTE_BUS_DEVICE(dev, struct rte_auxiliary_device));
}
static int
@@ -247,7 +228,8 @@ auxiliary_get_iommu_class(void)
struct rte_bus auxiliary_bus = {
.scan = auxiliary_scan,
.probe = rte_bus_generic_probe,
- .cleanup = auxiliary_cleanup,
+ .free_device = auxiliary_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = auxiliary_bus_match,
.probe_device = auxiliary_probe_device,
diff --git a/drivers/bus/dpaa/dpaa_bus.c b/drivers/bus/dpaa/dpaa_bus.c
index ee467b94d5..54779f82f7 100644
--- a/drivers/bus/dpaa/dpaa_bus.c
+++ b/drivers/bus/dpaa/dpaa_bus.c
@@ -807,12 +807,12 @@ dpaa_bus_probe_device(struct rte_driver *drv, struct rte_device *dev)
}
static int
-dpaa_bus_cleanup(void)
+dpaa_bus_cleanup(struct rte_bus *bus)
{
struct rte_dpaa_device *dev;
BUS_INIT_FUNC_TRACE();
- RTE_BUS_FOREACH_DEV(dev, &rte_dpaa_bus) {
+ RTE_BUS_FOREACH_DEV(dev, bus) {
const struct rte_dpaa_driver *drv;
int ret = 0;
diff --git a/drivers/bus/fslmc/fslmc_bus.c b/drivers/bus/fslmc/fslmc_bus.c
index dca4c5b182..1a0eca30b4 100644
--- a/drivers/bus/fslmc/fslmc_bus.c
+++ b/drivers/bus/fslmc/fslmc_bus.c
@@ -436,7 +436,7 @@ fslmc_bus_match(const struct rte_driver *drv, const struct rte_device *dev)
}
static int
-rte_fslmc_close(void)
+rte_fslmc_close(struct rte_bus *bus __rte_unused)
{
int ret = 0;
diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c
index 394b777916..f8e0e7770d 100644
--- a/drivers/bus/ifpga/ifpga_bus.c
+++ b/drivers/bus/ifpga/ifpga_bus.c
@@ -295,33 +295,10 @@ ifpga_unplug_device(struct rte_device *dev)
return 0;
}
-/*
- * Cleanup the content of the Intel FPGA bus, and call the remove() function
- * for all registered devices.
- */
-static int
-ifpga_cleanup(void)
+static void
+ifpga_free_device(struct rte_device *dev)
{
- struct rte_afu_device *afu_dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(afu_dev, &rte_ifpga_bus) {
- int ret = 0;
-
- if (rte_dev_is_probed(&afu_dev->device)) {
- ret = ifpga_unplug_device(&afu_dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(afu_dev->device.devargs);
- rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
- free(afu_dev);
- }
-
- return error;
+ free(RTE_BUS_DEVICE(dev, struct rte_afu_device));
}
static int
@@ -371,7 +348,8 @@ ifpga_parse(const char *name, void *addr)
static struct rte_bus rte_ifpga_bus = {
.scan = ifpga_scan,
.probe = rte_bus_generic_probe,
- .cleanup = ifpga_cleanup,
+ .free_device = ifpga_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = ifpga_bus_match,
.probe_device = ifpga_probe_device,
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index bf4822f7ec..0f635e1537 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -317,29 +317,11 @@ pci_unplug_device(struct rte_device *rte_dev)
return 0;
}
-static int
-pci_cleanup(void)
+static void
+pci_free_device(struct rte_device *dev)
{
- struct rte_pci_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &rte_pci_bus) {
- int ret = 0;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = pci_unplug_device(&dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&rte_pci_bus, &dev->device);
- pci_free(RTE_PCI_DEVICE_INTERNAL(dev));
- }
-
- return error;
+ struct rte_pci_device *pdev = RTE_BUS_DEVICE(dev, *pdev);
+ pci_free(RTE_PCI_DEVICE_INTERNAL(pdev));
}
/* dump one device */
@@ -743,7 +725,8 @@ struct rte_bus rte_pci_bus = {
.allow_multi_probe = true,
.scan = rte_pci_scan,
.probe = rte_bus_generic_probe,
- .cleanup = pci_cleanup,
+ .free_device = pci_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = pci_bus_match,
.probe_device = pci_probe_device,
diff --git a/drivers/bus/platform/platform.c b/drivers/bus/platform/platform.c
index 5b3c78a505..90d865a8df 100644
--- a/drivers/bus/platform/platform.c
+++ b/drivers/bus/platform/platform.c
@@ -491,26 +491,17 @@ platform_bus_get_iommu_class(void)
return RTE_IOVA_DC;
}
-static int
-platform_bus_cleanup(void)
+static void
+platform_free_device(struct rte_device *dev)
{
- struct rte_platform_device *pdev;
-
- RTE_BUS_FOREACH_DEV(pdev, &platform_bus) {
- if (rte_dev_is_probed(&pdev->device))
- platform_bus_unplug_device(&pdev->device);
-
- rte_devargs_remove(pdev->device.devargs);
- rte_bus_remove_device(&platform_bus, &pdev->device);
- free(pdev);
- }
-
- return 0;
+ free(RTE_BUS_DEVICE(dev, struct rte_platform_device));
}
static struct rte_bus platform_bus = {
.scan = platform_bus_scan,
.probe = rte_bus_generic_probe,
+ .free_device = platform_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = platform_bus_match,
.probe_device = platform_bus_probe_device,
@@ -520,7 +511,6 @@ static struct rte_bus platform_bus = {
.dma_unmap = platform_bus_dma_unmap,
.get_iommu_class = platform_bus_get_iommu_class,
.dev_iterate = rte_bus_generic_dev_iterate,
- .cleanup = platform_bus_cleanup,
};
RTE_REGISTER_BUS(platform, platform_bus);
diff --git a/drivers/bus/uacce/uacce.c b/drivers/bus/uacce/uacce.c
index bfe1f26557..99a6fb314d 100644
--- a/drivers/bus/uacce/uacce.c
+++ b/drivers/bus/uacce/uacce.c
@@ -402,29 +402,10 @@ uacce_unplug_device(struct rte_device *rte_dev)
return 0;
}
-static int
-uacce_cleanup(void)
+static void
+uacce_free_device(struct rte_device *dev)
{
- struct rte_uacce_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &uacce_bus) {
- int ret = 0;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = uacce_unplug_device(&dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&uacce_bus, &dev->device);
- free(dev);
- }
-
- return error;
+ free(RTE_BUS_DEVICE(dev, struct rte_uacce_device));
}
static int
@@ -551,7 +532,8 @@ rte_uacce_unregister(struct rte_uacce_driver *driver)
static struct rte_bus uacce_bus = {
.scan = uacce_scan,
.probe = rte_bus_generic_probe,
- .cleanup = uacce_cleanup,
+ .free_device = uacce_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.match = uacce_bus_match,
.probe_device = uacce_probe_device,
.unplug_device = uacce_unplug_device,
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 7e94f86e28..02d719a44d 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -548,26 +548,19 @@ vdev_scan(void)
return 0;
}
+static void
+vdev_free_device(struct rte_device *dev)
+{
+ free(RTE_BUS_DEVICE(dev, struct rte_vdev_device));
+}
+
static int
-vdev_cleanup(void)
+vdev_cleanup(struct rte_bus *bus)
{
- struct rte_vdev_device *dev;
- int error = 0;
+ int error;
rte_spinlock_recursive_lock(&vdev_device_list_lock);
- RTE_BUS_FOREACH_DEV(dev, &rte_vdev_bus) {
- int ret;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = vdev_unplug_device(&dev->device);
- if (ret < 0)
- error = -1;
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&rte_vdev_bus, &dev->device);
- free(dev);
- }
+ error = rte_bus_generic_cleanup(bus);
rte_spinlock_recursive_unlock(&vdev_device_list_lock);
return error;
@@ -608,6 +601,7 @@ vdev_get_iommu_class(void)
static struct rte_bus rte_vdev_bus = {
.scan = vdev_scan,
.probe = rte_bus_generic_probe,
+ .free_device = vdev_free_device,
.cleanup = vdev_cleanup,
.find_device = vdev_find_device,
.match = vdev_bus_match,
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index bfb45e963c..a6e3a24a7c 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -144,12 +144,12 @@ rte_vmbus_probe(void)
}
static int
-rte_vmbus_cleanup(void)
+rte_vmbus_cleanup(struct rte_bus *bus)
{
struct rte_vmbus_device *dev;
int error = 0;
- RTE_BUS_FOREACH_DEV(dev, &rte_vmbus_bus) {
+ RTE_BUS_FOREACH_DEV(dev, bus) {
const struct rte_vmbus_driver *drv;
int ret;
@@ -167,7 +167,7 @@ rte_vmbus_cleanup(void)
rte_intr_instance_free(dev->intr_handle);
dev->device.driver = NULL;
- rte_bus_remove_device(&rte_vmbus_bus, &dev->device);
+ rte_bus_remove_device(bus, &dev->device);
free(dev);
}
diff --git a/lib/eal/common/eal_common_bus.c b/lib/eal/common/eal_common_bus.c
index ca13ccce5b..9ba23516ee 100644
--- a/lib/eal/common/eal_common_bus.c
+++ b/lib/eal/common/eal_common_bus.c
@@ -124,6 +124,37 @@ rte_bus_generic_probe(struct rte_bus *bus)
return (probed && probed == failed) ? -1 : 0;
}
+/*
+ * Generic cleanup function for buses.
+ * Iterates through all devices on the bus, unplugs probed devices,
+ * removes devargs, removes devices from the bus list, and frees device structures.
+ */
+RTE_EXPORT_INTERNAL_SYMBOL(rte_bus_generic_cleanup)
+int
+rte_bus_generic_cleanup(struct rte_bus *bus)
+{
+ struct rte_device *dev;
+ int error = 0;
+
+ RTE_VERIFY(bus->free_device);
+ RTE_VERIFY(bus->unplug_device);
+
+ while ((dev = TAILQ_FIRST(&bus->device_list)) != NULL) {
+ if (rte_dev_is_probed(dev)) {
+ if (bus->unplug_device && bus->unplug_device(dev) < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
+ }
+
+ rte_devargs_remove(dev->devargs);
+ rte_bus_remove_device(bus, dev);
+ bus->free_device(dev);
+ }
+
+ return error;
+}
+
/* Probe all devices of all buses */
RTE_EXPORT_SYMBOL(rte_bus_probe)
int
@@ -164,7 +195,7 @@ eal_bus_cleanup(void)
TAILQ_FOREACH(bus, &rte_bus_list, next) {
if (bus->cleanup == NULL)
continue;
- if (bus->cleanup() != 0)
+ if (bus->cleanup(bus) != 0)
ret = -1;
}
diff --git a/lib/eal/include/bus_driver.h b/lib/eal/include/bus_driver.h
index fde55ff06d..4f6521c87f 100644
--- a/lib/eal/include/bus_driver.h
+++ b/lib/eal/include/bus_driver.h
@@ -226,17 +226,31 @@ typedef int (*rte_bus_hot_unplug_handler_t)(struct rte_device *dev);
*/
typedef int (*rte_bus_sigbus_handler_t)(const void *failure_addr);
+/**
+ * Free a bus-specific device structure.
+ *
+ * @param dev
+ * Device pointer.
+ */
+typedef void (*rte_bus_free_device_t)(struct rte_device *dev);
+
/**
* Implementation specific cleanup function which is responsible for cleaning up
* devices on that bus with applicable drivers.
*
+ * The cleanup operation is the counterpart to scan, removing all devices added
+ * during scan.
+ *
* This is called while iterating over each registered bus.
*
+ * @param bus
+ * Pointer to the bus to cleanup.
+ *
* @return
* 0 for successful cleanup
* !0 for any error during cleanup
*/
-typedef int (*rte_bus_cleanup_t)(void);
+typedef int (*rte_bus_cleanup_t)(struct rte_bus *bus);
/**
* Check if a driver matches a device.
@@ -336,6 +350,7 @@ struct rte_bus {
/**< handle hot-unplug failure on the bus */
rte_bus_sigbus_handler_t sigbus_handler;
/**< handle sigbus error on the bus */
+ rte_bus_free_device_t free_device; /**< Free bus-specific device */
rte_bus_cleanup_t cleanup; /**< Cleanup devices on bus */
RTE_TAILQ_HEAD(, rte_device) device_list; /**< List of devices on the bus */
RTE_TAILQ_HEAD(, rte_driver) driver_list; /**< List of drivers on the bus */
@@ -624,6 +639,23 @@ struct rte_driver *rte_bus_find_driver(const struct rte_bus *bus, const struct r
__rte_internal
int rte_bus_generic_probe(struct rte_bus *bus);
+/**
+ * Generic cleanup function for buses.
+ *
+ * Iterates through all devices on the bus, unplugs probed devices,
+ * removes devargs, removes devices from the bus list, and frees device structures.
+ *
+ * This function can be used by buses that don't require special cleanup
+ * logic and just need the standard device cleanup sequence.
+ *
+ * @param bus
+ * Pointer to the bus to cleanup.
+ * @return
+ * 0 on success, -1 if any errors occurred during cleanup.
+ */
+__rte_internal
+int rte_bus_generic_cleanup(struct rte_bus *bus);
+
#ifdef __cplusplus
}
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v2 09/10] bus/vmbus: store name in bus specific device
2026-06-18 15:28 ` [PATCH v2 00/10] " David Marchand
` (7 preceding siblings ...)
2026-06-18 15:28 ` [PATCH v2 08/10] bus: implement cleanup in EAL David Marchand
@ 2026-06-18 15:28 ` David Marchand
2026-06-22 10:28 ` Bruce Richardson
2026-06-18 15:28 ` [PATCH v2 10/10] bus/vmbus: support unplug David Marchand
9 siblings, 1 reply; 55+ messages in thread
From: David Marchand @ 2026-06-18 15:28 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Wei Hu
The device name is allocated with strdup() during scan and freed in
several places. However, when this bus cleanup is converted to use the
EAL generic helper, freeing the device object will require a custom
helper to also free the device name (and for this, a cast will be
needed).
Instead, add an embedded name array to rte_vmbus_device structure
(char name[RTE_DEV_NAME_MAX_LEN]) which is sufficient for all VMBUS
device names (UUID format: 36 characters, or shorter legacy format).
This simplifies the device freeing to a simple free() call.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/vmbus/bus_vmbus_driver.h | 1 +
drivers/bus/vmbus/linux/vmbus_bus.c | 10 +++-------
2 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/bus/vmbus/bus_vmbus_driver.h b/drivers/bus/vmbus/bus_vmbus_driver.h
index 888d856141..706ff1fcf5 100644
--- a/drivers/bus/vmbus/bus_vmbus_driver.h
+++ b/drivers/bus/vmbus/bus_vmbus_driver.h
@@ -38,6 +38,7 @@ enum hv_uio_map {
*/
struct rte_vmbus_device {
struct rte_device device; /**< Inherit core device */
+ char name[RTE_DEV_NAME_MAX_LEN]; /**< VMBUS device name */
rte_uuid_t device_id; /**< VMBUS device id */
rte_uuid_t class_id; /**< VMBUS device type */
uint32_t relid; /**< id for primary */
diff --git a/drivers/bus/vmbus/linux/vmbus_bus.c b/drivers/bus/vmbus/linux/vmbus_bus.c
index 77d904ad6d..779ea50b92 100644
--- a/drivers/bus/vmbus/linux/vmbus_bus.c
+++ b/drivers/bus/vmbus/linux/vmbus_bus.c
@@ -280,15 +280,14 @@ vmbus_scan_one(const char *name)
char filename[PATH_MAX];
char dirname[PATH_MAX];
unsigned long tmp;
- char *dev_name;
dev = calloc(1, sizeof(*dev));
if (dev == NULL)
return -1;
- dev->device.name = dev_name = strdup(name);
- if (!dev->device.name)
+ if (rte_strscpy(dev->name, name, sizeof(dev->name)) < 0)
goto error;
+ dev->device.name = dev->name;
/* sysfs base directory
* /sys/bus/vmbus/devices/7a08391f-f5a0-4ac0-9802-d13fd964f8df
@@ -305,7 +304,6 @@ vmbus_scan_one(const char *name)
/* skip non-network devices */
if (rte_uuid_compare(dev->class_id, vmbus_nic_uuid) != 0) {
- free(dev_name);
free(dev);
return 0;
}
@@ -330,7 +328,7 @@ vmbus_scan_one(const char *name)
dev->monitor_id = UINT8_MAX;
}
- dev->device.devargs = rte_bus_find_devargs(&rte_vmbus_bus, dev_name);
+ dev->device.devargs = rte_bus_find_devargs(&rte_vmbus_bus, dev->name);
dev->device.numa_node = SOCKET_ID_ANY;
if (vmbus_use_numa(dev)) {
@@ -360,7 +358,6 @@ vmbus_scan_one(const char *name)
} else { /* already registered */
VMBUS_LOG(NOTICE,
"%s already registered", name);
- free(dev_name);
free(dev);
}
return 0;
@@ -371,7 +368,6 @@ vmbus_scan_one(const char *name)
error:
VMBUS_LOG(DEBUG, "failed");
- free(dev_name);
free(dev);
return -1;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v2 10/10] bus/vmbus: support unplug
2026-06-18 15:28 ` [PATCH v2 00/10] " David Marchand
` (8 preceding siblings ...)
2026-06-18 15:28 ` [PATCH v2 09/10] bus/vmbus: store name in bus specific device David Marchand
@ 2026-06-18 15:28 ` David Marchand
9 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-18 15:28 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Wei Hu
Add .unplug callback to handle driver removal, device unmapping, and
interrupt cleanup. This enables use of the generic bus cleanup helper.
The cleanup function was already performing these operations, so it
seems safe to expose them through the unplug operation.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
doc/guides/rel_notes/release_26_07.rst | 4 +++
drivers/bus/vmbus/vmbus_common.c | 41 ++++++++++++--------------
2 files changed, 23 insertions(+), 22 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 5d7aa8d1bf..55d3b44527 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -114,6 +114,10 @@ New Features
Added no-IOMMU mode for devices without or not enabling IOMMU/SVA.
+* **Added unplug operation support to VMBUS bus.**
+
+ Implemented device unplug operation to allow runtime removal of VMBUS devices.
+
* **Added selective Rx in ethdev API.**
Some parts of packets may be discarded in Rx
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index a6e3a24a7c..cd6e851e4c 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -144,34 +144,29 @@ rte_vmbus_probe(void)
}
static int
-rte_vmbus_cleanup(struct rte_bus *bus)
+vmbus_unplug_device(struct rte_device *rte_dev)
{
- struct rte_vmbus_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, bus) {
- const struct rte_vmbus_driver *drv;
- int ret;
-
- if (!rte_dev_is_probed(&dev->device))
- continue;
- drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
- if (drv->remove == NULL)
- continue;
+ const struct rte_vmbus_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
+ struct rte_vmbus_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
+ int ret = 0;
+ if (drv->remove != NULL) {
ret = drv->remove(dev);
if (ret < 0)
- error = -1;
+ return ret;
+ }
- rte_vmbus_unmap_device(dev);
- rte_intr_instance_free(dev->intr_handle);
+ rte_vmbus_unmap_device(dev);
+ rte_intr_instance_free(dev->intr_handle);
+ dev->intr_handle = NULL;
- dev->device.driver = NULL;
- rte_bus_remove_device(bus, &dev->device);
- free(dev);
- }
+ return 0;
+}
- return error;
+static void
+vmbus_free_device(struct rte_device *dev)
+{
+ free(RTE_BUS_DEVICE(dev, struct rte_vmbus_device));
}
static int
@@ -222,10 +217,12 @@ rte_vmbus_unregister(struct rte_vmbus_driver *driver)
struct rte_bus rte_vmbus_bus = {
.scan = rte_vmbus_scan,
.probe = rte_bus_generic_probe,
- .cleanup = rte_vmbus_cleanup,
+ .free_device = vmbus_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = vmbus_bus_match,
.probe_device = vmbus_probe_device,
+ .unplug_device = vmbus_unplug_device,
.parse = vmbus_parse,
.dev_compare = vmbus_dev_compare,
};
--
2.53.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* RE: [EXTERNAL] [PATCH v2 05/10] bus/vmbus: fix interrupt leak in cleanup
2026-06-18 15:28 ` [PATCH v2 05/10] bus/vmbus: fix interrupt leak in cleanup David Marchand
@ 2026-06-19 22:04 ` Long Li
0 siblings, 0 replies; 55+ messages in thread
From: Long Li @ 2026-06-19 22:04 UTC (permalink / raw)
To: David Marchand, dev@dpdk.org
Cc: thomas@monjalon.net, stephen@networkplumber.org,
bruce.richardson@intel.com, fengchengwen@huawei.com,
hemant.agrawal@nxp.com, stable@dpdk.org, Wei Hu
> When calling this bus cleanup, interrupt handle was not released.
>
> Fixes: 65780eada9d9 ("bus/vmbus: support cleanup")
> Cc: stable@dpdk.org
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
Reviewed-by: Long Li <longli@microsoft.com>
> ---
> drivers/bus/vmbus/vmbus_common.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/bus/vmbus/vmbus_common.c
> b/drivers/bus/vmbus/vmbus_common.c
> index 01573927ce..74c1ddff69 100644
> --- a/drivers/bus/vmbus/vmbus_common.c
> +++ b/drivers/bus/vmbus/vmbus_common.c
> @@ -150,6 +150,7 @@ rte_vmbus_cleanup(void)
> error = -1;
>
> rte_vmbus_unmap_device(dev);
> + rte_intr_instance_free(dev->intr_handle);
>
> dev->device.driver = NULL;
> rte_bus_remove_device(&rte_vmbus_bus, &dev->device);
> --
> 2.53.0
^ permalink raw reply [flat|nested] 55+ messages in thread
* RE: [EXTERNAL] [PATCH v2 06/10] bus/vmbus: allocate interrupt during probing
2026-06-18 15:28 ` [PATCH v2 06/10] bus/vmbus: allocate interrupt during probing David Marchand
@ 2026-06-19 22:05 ` Long Li
0 siblings, 0 replies; 55+ messages in thread
From: Long Li @ 2026-06-19 22:05 UTC (permalink / raw)
To: David Marchand, dev@dpdk.org
Cc: thomas@monjalon.net, stephen@networkplumber.org,
bruce.richardson@intel.com, fengchengwen@huawei.com,
hemant.agrawal@nxp.com, Wei Hu
> Allocating the interrupt handle is a waste of memory if no device is probed
> later (like for example, if a allowlist is passed).
> Instead, allocate this handle at the time probe_device is called.
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
Reviewed-by: Long Li <longli@microsoft.com>
> ---
> Changes since v1:
> - fixed/reordered interrupt handle allocation,
>
> ---
> drivers/bus/vmbus/linux/vmbus_bus.c | 6 ------
> drivers/bus/vmbus/vmbus_common.c | 18 ++++++++++++++++--
> 2 files changed, 16 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/bus/vmbus/linux/vmbus_bus.c
> b/drivers/bus/vmbus/linux/vmbus_bus.c
> index 0af10f6a69..77d904ad6d 100644
> --- a/drivers/bus/vmbus/linux/vmbus_bus.c
> +++ b/drivers/bus/vmbus/linux/vmbus_bus.c
> @@ -345,12 +345,6 @@ vmbus_scan_one(const char *name)
> }
> }
>
> - /* Allocate interrupt handle instance */
> - dev->intr_handle =
> - rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
> - if (dev->intr_handle == NULL)
> - goto error;
> -
> /* device is valid, add in list (sorted) */
> VMBUS_LOG(DEBUG, "Adding vmbus device %s", name);
>
> diff --git a/drivers/bus/vmbus/vmbus_common.c
> b/drivers/bus/vmbus/vmbus_common.c
> index 74c1ddff69..bfb45e963c 100644
> --- a/drivers/bus/vmbus/vmbus_common.c
> +++ b/drivers/bus/vmbus/vmbus_common.c
> @@ -100,10 +100,16 @@ vmbus_probe_device(struct rte_driver *drv, struct
> rte_device *dev)
> return 1;
> }
>
> + /* allocate interrupt handle instance */
> + vmbus_dev->intr_handle =
> + rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
> + if (vmbus_dev->intr_handle == NULL)
> + return -ENOMEM;
> +
> /* map resources for device */
> ret = rte_vmbus_map_device(vmbus_dev);
> if (ret != 0)
> - return ret;
> + goto free_intr;
>
> if (vmbus_dev->device.numa_node < 0 && rte_socket_count() > 1)
> VMBUS_LOG(INFO, "Device %s is not NUMA-aware", guid); @@
> -112,7 +118,15 @@ vmbus_probe_device(struct rte_driver *drv, struct
> rte_device *dev)
> VMBUS_LOG(INFO, " probe driver: %s", vmbus_drv->driver.name);
> ret = vmbus_drv->probe(vmbus_drv, vmbus_dev);
> if (ret != 0)
> - rte_vmbus_unmap_device(vmbus_dev);
> + goto unmap;
> +
> + return 0;
> +
> +unmap:
> + rte_vmbus_unmap_device(vmbus_dev);
> +free_intr:
> + rte_intr_instance_free(vmbus_dev->intr_handle);
> + vmbus_dev->intr_handle = NULL;
>
> return ret;
> }
> --
> 2.53.0
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v2 02/10] dma/idxd: remove next pointer in bus specific device
2026-06-18 15:28 ` [PATCH v2 02/10] dma/idxd: remove next pointer in bus specific device David Marchand
@ 2026-06-22 9:48 ` Bruce Richardson
0 siblings, 0 replies; 55+ messages in thread
From: Bruce Richardson @ 2026-06-22 9:48 UTC (permalink / raw)
To: David Marchand
Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal,
Kevin Laatz
On Thu, Jun 18, 2026 at 05:28:17PM +0200, David Marchand wrote:
> The dma/idxd devices are now stored in a list of generic rte_device
> objects.
>
> Fixes: b4f0974a995b ("bus: factorize device list")
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
> drivers/dma/idxd/idxd_bus.c | 1 -
> 1 file changed, 1 deletion(-)
>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v2 01/10] bus: fix reference to plug callback
2026-06-18 15:28 ` [PATCH v2 01/10] bus: fix reference to plug callback David Marchand
@ 2026-06-22 9:49 ` Bruce Richardson
0 siblings, 0 replies; 55+ messages in thread
From: Bruce Richardson @ 2026-06-22 9:49 UTC (permalink / raw)
To: David Marchand; +Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal
On Thu, Jun 18, 2026 at 05:28:16PM +0200, David Marchand wrote:
> Remove now unused typedef, update documentation
> and some log following the callback rename.
>
> Fixes: 76622feba9e6 ("bus: refactor device probe")
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
> Changes since v1:
> - remove missed rte_bus_plug_t typedef,
>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v2 07/10] bus: align unplug with device probe
2026-06-18 15:28 ` [PATCH v2 07/10] bus: align unplug with device probe David Marchand
@ 2026-06-22 10:19 ` Bruce Richardson
2026-06-22 12:44 ` David Marchand
0 siblings, 1 reply; 55+ messages in thread
From: Bruce Richardson @ 2026-06-22 10:19 UTC (permalink / raw)
To: David Marchand
Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal,
Parav Pandit, Xueming Li, Nipun Gupta, Nikhil Agarwal,
Sachin Saxena, Rosen Xu, Chenbo Xia, Tomasz Duszynski
On Thu, Jun 18, 2026 at 05:28:22PM +0200, David Marchand wrote:
> Refactor bus unplug operations to be the counterpart of probe_device.
> The (renamed) unplug operation now only handles:
> - Driver removal (calling the driver's remove callback)
> - Freeing probe-allocated resources (interrupts, mappings)
>
> Device deletion (devargs removal, bus removal, freeing device
> structure) is now handled only during bus cleanup, not in unplug.
>
> Additionally, move driver pointer clearing from individual bus unplug
> operations to EAL's local_dev_remove() where the unplug operation is
> invoked. This centralizes driver lifecycle management and eliminates
> code duplication across bus drivers.
>
> For vdev, add a check in rte_vdev_uninit() since this public API can
> be called on devices without a driver attached.
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
Running an AI correctness review reports a potential issue with ifpga bus
after this patch. Maybe worth a double check.
/Bruce
In ifpga_alloc_afu_dev (called at scan time, before any probe),
afu_dev->intr_handle is allocated unconditionally.
In the old ifpga_cleanup, the "goto free:" label ran for all devices, so
intr_handle was freed unconditionally. In the new ifpga_cleanup,
intr_handle is only freed via ifpga_unplug_device, which is only called
when rte_dev_is_probed() returns true. For any ifpga device discovered
during scan but never successfully probed (no matching driver, failed
probe, blocked devargs), intr_handle is leaked. The fix should free it
unconditionally in ifpga_cleanup, outside the rte_dev_is_probed block.
> ---
> doc/guides/prog_guide/device_hotplug.rst | 18 ++++---
> drivers/bus/auxiliary/auxiliary_common.c | 46 ++++++----------
> drivers/bus/cdx/cdx.c | 29 ++--------
> drivers/bus/fslmc/fslmc_bus.c | 7 +--
> drivers/bus/ifpga/ifpga_bus.c | 63 ++++++++++------------
> drivers/bus/pci/pci_common.c | 57 ++++----------------
> drivers/bus/platform/platform.c | 16 +++---
> drivers/bus/uacce/uacce.c | 67 ++++++++----------------
> drivers/bus/vdev/vdev.c | 53 ++++++++-----------
> lib/eal/common/eal_common_dev.c | 8 +--
> lib/eal/include/bus_driver.h | 4 +-
> 11 files changed, 129 insertions(+), 239 deletions(-)
>
> diff --git a/doc/guides/prog_guide/device_hotplug.rst b/doc/guides/prog_guide/device_hotplug.rst
> index 7eb7fbcc2b..d21ba0c244 100644
> --- a/doc/guides/prog_guide/device_hotplug.rst
> +++ b/doc/guides/prog_guide/device_hotplug.rst
> @@ -165,7 +165,7 @@ using ``rte_dev_event_callback_register()`` function.
> on the device in question.
> When ``RTE_DEV_EVENT_REMOVE`` event is delivered,
> it indicates that the kernel has removed the device;
> - the application should call ``rte_dev_remove()`` to clean up EAL resources.
> + the application should call ``rte_dev_remove()`` to unplug the device driver.
>
>
> Event Notification Usage
> @@ -256,13 +256,17 @@ When ``rte_dev_remove()`` is called, the following sequence occurs:
> See `Multi-process Synchronization`_ for details.
>
> #. **Device Unplug**:
> - The bus's ``unplug()`` method is called (``dev->bus->unplug()``),
> - which triggers the driver's remove function.
> - This typically stops device operations, releases device resources,
> - unmaps memory regions, and unregisters from subsystems.
> + The bus's ``unplug_device()`` method is called (``dev->bus->unplug_device()``),
> + which triggers the driver's remove function
> + and releases resources allocated during probe
> + (such as interrupt handles and device memory mappings).
>
> -#. **Devargs Cleanup**:
> - The devargs associated with the device are removed from the global list.
> +.. note::
> +
> + The device structure, its devargs, and its entry in the bus device list
> + are NOT freed during ``rte_dev_remove()``.
> + They remain in memory until ``rte_eal_cleanup()`` is called,
> + at which point the bus's ``cleanup()`` method handles complete device deletion.
>
>
> Multi-process Synchronization
> diff --git a/drivers/bus/auxiliary/auxiliary_common.c b/drivers/bus/auxiliary/auxiliary_common.c
> index 048aacf254..10f466e57a 100644
> --- a/drivers/bus/auxiliary/auxiliary_common.c
> +++ b/drivers/bus/auxiliary/auxiliary_common.c
> @@ -122,13 +122,11 @@ auxiliary_probe_device(struct rte_driver *drv, struct rte_device *dev)
> return ret;
> }
>
> -/*
> - * Call the remove() function of the driver.
> - */
> static int
> -rte_auxiliary_driver_remove_dev(struct rte_auxiliary_device *dev)
> +auxiliary_unplug_device(struct rte_device *rte_dev)
> {
> - const struct rte_auxiliary_driver *drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
> + const struct rte_auxiliary_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
> + struct rte_auxiliary_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
> int ret = 0;
>
> AUXILIARY_LOG(DEBUG, "Driver %s remove auxiliary device %s on NUMA node %i",
> @@ -140,8 +138,8 @@ rte_auxiliary_driver_remove_dev(struct rte_auxiliary_device *dev)
> return ret;
> }
>
> - /* clear driver structure */
> - dev->device.driver = NULL;
> + rte_intr_instance_free(dev->intr_handle);
> + dev->intr_handle = NULL;
>
> return 0;
> }
> @@ -181,22 +179,6 @@ rte_auxiliary_unregister(struct rte_auxiliary_driver *driver)
> rte_bus_remove_driver(&auxiliary_bus, &driver->driver);
> }
>
> -static int
> -auxiliary_unplug(struct rte_device *dev)
> -{
> - struct rte_auxiliary_device *adev = RTE_BUS_DEVICE(dev, *adev);
> - int ret;
> -
> - ret = rte_auxiliary_driver_remove_dev(adev);
> - if (ret == 0) {
> - rte_bus_remove_device(&auxiliary_bus, &adev->device);
> - rte_devargs_remove(dev->devargs);
> - rte_intr_instance_free(adev->intr_handle);
> - free(adev);
> - }
> - return ret;
> -}
> -
> static int
> auxiliary_cleanup(void)
> {
> @@ -206,13 +188,17 @@ auxiliary_cleanup(void)
> RTE_BUS_FOREACH_DEV(dev, &auxiliary_bus) {
> int ret;
>
> - if (!rte_dev_is_probed(&dev->device))
> - continue;
> - ret = auxiliary_unplug(&dev->device);
> - if (ret < 0) {
> - rte_errno = errno;
> - error = -1;
> + if (rte_dev_is_probed(&dev->device)) {
> + ret = auxiliary_unplug_device(&dev->device);
> + if (ret < 0) {
> + rte_errno = errno;
> + error = -1;
> + }
> }
> +
> + rte_devargs_remove(dev->device.devargs);
> + rte_bus_remove_device(&auxiliary_bus, &dev->device);
> + free(dev);
> }
>
> return error;
> @@ -265,7 +251,7 @@ struct rte_bus auxiliary_bus = {
> .find_device = rte_bus_generic_find_device,
> .match = auxiliary_bus_match,
> .probe_device = auxiliary_probe_device,
> - .unplug = auxiliary_unplug,
> + .unplug_device = auxiliary_unplug_device,
> .parse = auxiliary_parse,
> .dma_map = auxiliary_dma_map,
> .dma_unmap = auxiliary_dma_unmap,
> diff --git a/drivers/bus/cdx/cdx.c b/drivers/bus/cdx/cdx.c
> index 2443161e1a..c0b46a41ad 100644
> --- a/drivers/bus/cdx/cdx.c
> +++ b/drivers/bus/cdx/cdx.c
> @@ -374,14 +374,11 @@ rte_cdx_unregister(struct rte_cdx_driver *driver)
> rte_bus_remove_driver(&rte_cdx_bus, &driver->driver);
> }
>
> -/*
> - * If vendor/device ID match, call the remove() function of the
> - * driver.
> - */
> static int
> -cdx_detach_dev(struct rte_cdx_device *dev)
> +cdx_unplug_device(struct rte_device *rte_dev)
> {
> - const struct rte_cdx_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
> + const struct rte_cdx_driver *dr = RTE_BUS_DRIVER(rte_dev->driver, *dr);
> + struct rte_cdx_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
> int ret = 0;
>
> CDX_BUS_DEBUG("detach device %s using driver: %s",
> @@ -393,9 +390,6 @@ cdx_detach_dev(struct rte_cdx_device *dev)
> return ret;
> }
>
> - /* clear driver structure */
> - dev->device.driver = NULL;
> -
> rte_cdx_unmap_device(dev);
>
> rte_intr_instance_free(dev->intr_handle);
> @@ -404,21 +398,6 @@ cdx_detach_dev(struct rte_cdx_device *dev)
> return 0;
> }
>
> -static int
> -cdx_unplug(struct rte_device *dev)
> -{
> - struct rte_cdx_device *cdx_dev = RTE_BUS_DEVICE(dev, *cdx_dev);
> - int ret;
> -
> - ret = cdx_detach_dev(cdx_dev);
> - if (ret == 0) {
> - rte_bus_remove_device(&rte_cdx_bus, &cdx_dev->device);
> - rte_devargs_remove(dev->devargs);
> - free(cdx_dev);
> - }
> - return ret;
> -}
> -
> static int
> cdx_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
> {
> @@ -452,7 +431,7 @@ static struct rte_bus rte_cdx_bus = {
> .find_device = rte_bus_generic_find_device,
> .match = cdx_bus_match,
> .probe_device = cdx_probe_device,
> - .unplug = cdx_unplug,
> + .unplug_device = cdx_unplug_device,
> .parse = cdx_parse,
> .dma_map = cdx_dma_map,
> .dma_unmap = cdx_dma_unmap,
> diff --git a/drivers/bus/fslmc/fslmc_bus.c b/drivers/bus/fslmc/fslmc_bus.c
> index c7549a361a..dca4c5b182 100644
> --- a/drivers/bus/fslmc/fslmc_bus.c
> +++ b/drivers/bus/fslmc/fslmc_bus.c
> @@ -520,6 +520,7 @@ fslmc_bus_probe_device(struct rte_driver *driver, struct rte_device *rte_dev)
> return 0;
> }
>
> + /* FIXME: probe_device should allocate intr_handle */
> ret = drv->probe(drv, dev);
> if (ret != 0) {
> DPAA2_BUS_ERR("Unable to probe");
> @@ -531,7 +532,7 @@ fslmc_bus_probe_device(struct rte_driver *driver, struct rte_device *rte_dev)
> }
>
> static int
> -fslmc_bus_unplug(struct rte_device *rte_dev)
> +fslmc_bus_unplug_device(struct rte_device *rte_dev)
> {
> struct rte_dpaa2_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
> const struct rte_dpaa2_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
> @@ -540,7 +541,7 @@ fslmc_bus_unplug(struct rte_device *rte_dev)
> int ret = drv->remove(dev);
> if (ret != 0)
> return ret;
> - dev->device.driver = NULL;
> + /* FIXME: unplug_device should free intr_handle */
> DPAA2_BUS_INFO("%s Un-Plugged", dev->device.name);
> return 0;
> }
> @@ -558,7 +559,7 @@ struct rte_bus rte_fslmc_bus = {
> .get_iommu_class = rte_dpaa2_get_iommu_class,
> .match = fslmc_bus_match,
> .probe_device = fslmc_bus_probe_device,
> - .unplug = fslmc_bus_unplug,
> + .unplug_device = fslmc_bus_unplug_device,
> .dev_iterate = rte_bus_generic_dev_iterate,
> };
>
> diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c
> index 2c22329f65..394b777916 100644
> --- a/drivers/bus/ifpga/ifpga_bus.c
> +++ b/drivers/bus/ifpga/ifpga_bus.c
> @@ -276,6 +276,25 @@ ifpga_probe_device(struct rte_driver *drv, struct rte_device *dev)
> return afu_drv->probe(afu_dev);
> }
>
> +static int
> +ifpga_unplug_device(struct rte_device *dev)
> +{
> + const struct rte_afu_driver *afu_drv = RTE_BUS_DRIVER(dev->driver, *afu_drv);
> + struct rte_afu_device *afu_dev = RTE_BUS_DEVICE(dev, *afu_dev);
> + int ret = 0;
> +
> + if (afu_drv->remove) {
> + ret = afu_drv->remove(afu_dev);
> + if (ret)
> + return ret;
> + }
> +
> + rte_intr_instance_free(afu_dev->intr_handle);
> + afu_dev->intr_handle = NULL;
> +
> + return 0;
> +}
> +
> /*
> * Cleanup the content of the Intel FPGA bus, and call the remove() function
> * for all registered devices.
> @@ -287,52 +306,24 @@ ifpga_cleanup(void)
> int error = 0;
>
> RTE_BUS_FOREACH_DEV(afu_dev, &rte_ifpga_bus) {
> - const struct rte_afu_driver *drv;
> int ret = 0;
>
> - if (!rte_dev_is_probed(&afu_dev->device))
> - goto free;
> - drv = RTE_BUS_DRIVER(afu_dev->device.driver, *drv);
> - if (drv->remove == NULL)
> - goto free;
> -
> - ret = drv->remove(afu_dev);
> - if (ret < 0) {
> - rte_errno = errno;
> - error = -1;
> + if (rte_dev_is_probed(&afu_dev->device)) {
> + ret = ifpga_unplug_device(&afu_dev->device);
> + if (ret < 0) {
> + rte_errno = errno;
> + error = -1;
> + }
> }
> - afu_dev->device.driver = NULL;
>
> -free:
> - rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
> rte_devargs_remove(afu_dev->device.devargs);
> - rte_intr_instance_free(afu_dev->intr_handle);
> + rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
> free(afu_dev);
> }
>
> return error;
> }
>
> -static int
> -ifpga_unplug(struct rte_device *dev)
> -{
> - struct rte_afu_device *afu_dev = RTE_BUS_DEVICE(dev, *afu_dev);
> - const struct rte_afu_driver *afu_drv = RTE_BUS_DRIVER(dev->driver, *afu_drv);
> - int ret;
> -
> - ret = afu_drv->remove(afu_dev);
> - if (ret)
> - return ret;
> -
> - rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
> -
> - rte_devargs_remove(dev->devargs);
> - rte_intr_instance_free(afu_dev->intr_handle);
> - free(afu_dev);
> - return 0;
> -
> -}
> -
> static int
> ifpga_parse(const char *name, void *addr)
> {
> @@ -384,7 +375,7 @@ static struct rte_bus rte_ifpga_bus = {
> .find_device = rte_bus_generic_find_device,
> .match = ifpga_bus_match,
> .probe_device = ifpga_probe_device,
> - .unplug = ifpga_unplug,
> + .unplug_device = ifpga_unplug_device,
> .parse = ifpga_parse,
> };
>
> diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
> index 791e9a7b49..bf4822f7ec 100644
> --- a/drivers/bus/pci/pci_common.c
> +++ b/drivers/bus/pci/pci_common.c
> @@ -282,13 +282,10 @@ pci_probe_device(struct rte_driver *drv, struct rte_device *dev)
> return ret;
> }
>
> -/*
> - * If vendor/device ID match, call the remove() function of the
> - * driver.
> - */
> static int
> -rte_pci_detach_dev(struct rte_pci_device *dev)
> +pci_unplug_device(struct rte_device *rte_dev)
> {
> + struct rte_pci_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
> struct rte_pci_addr *loc;
> const struct rte_pci_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
> int ret = 0;
> @@ -308,9 +305,6 @@ rte_pci_detach_dev(struct rte_pci_device *dev)
> return ret;
> }
>
> - /* clear driver structure */
> - dev->device.driver = NULL;
> -
> if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
> /* unmap resources for devices that use igb_uio */
> rte_pci_unmap_device(dev);
> @@ -330,33 +324,17 @@ pci_cleanup(void)
> int error = 0;
>
> RTE_BUS_FOREACH_DEV(dev, &rte_pci_bus) {
> - const struct rte_pci_driver *drv;
> int ret = 0;
>
> - if (!rte_dev_is_probed(&dev->device))
> - goto free;
> - drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
> - if (drv->remove == NULL)
> - goto free;
> -
> - ret = drv->remove(dev);
> - if (ret < 0) {
> - rte_errno = errno;
> - error = -1;
> + if (rte_dev_is_probed(&dev->device)) {
> + ret = pci_unplug_device(&dev->device);
> + if (ret < 0) {
> + rte_errno = errno;
> + error = -1;
> + }
> }
>
> - if (drv->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
> - rte_pci_unmap_device(dev);
> -
> - dev->device.driver = NULL;
> -
> -free:
> - /* free interrupt handles */
> - rte_intr_instance_free(dev->intr_handle);
> - dev->intr_handle = NULL;
> - rte_intr_instance_free(dev->vfio_req_intr_handle);
> - dev->vfio_req_intr_handle = NULL;
> -
> + rte_devargs_remove(dev->device.devargs);
> rte_bus_remove_device(&rte_pci_bus, &dev->device);
> pci_free(RTE_PCI_DEVICE_INTERNAL(dev));
> }
> @@ -521,21 +499,6 @@ pci_sigbus_handler(const void *failure_addr)
> return ret;
> }
>
> -static int
> -pci_unplug(struct rte_device *dev)
> -{
> - struct rte_pci_device *pdev = RTE_BUS_DEVICE(dev, *pdev);
> - int ret;
> -
> - ret = rte_pci_detach_dev(pdev);
> - if (ret == 0) {
> - rte_bus_remove_device(&rte_pci_bus, &pdev->device);
> - rte_devargs_remove(dev->devargs);
> - pci_free(RTE_PCI_DEVICE_INTERNAL(pdev));
> - }
> - return ret;
> -}
> -
> static int
> pci_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
> {
> @@ -784,7 +747,7 @@ struct rte_bus rte_pci_bus = {
> .find_device = rte_bus_generic_find_device,
> .match = pci_bus_match,
> .probe_device = pci_probe_device,
> - .unplug = pci_unplug,
> + .unplug_device = pci_unplug_device,
> .parse = pci_parse,
> .dev_compare = pci_dev_compare,
> .devargs_parse = rte_pci_devargs_parse,
> diff --git a/drivers/bus/platform/platform.c b/drivers/bus/platform/platform.c
> index 170a2e03d0..5b3c78a505 100644
> --- a/drivers/bus/platform/platform.c
> +++ b/drivers/bus/platform/platform.c
> @@ -416,19 +416,15 @@ device_release_driver(struct rte_platform_device *pdev)
> if (ret)
> PLATFORM_LOG_LINE(WARNING, "failed to remove %s", pdev->name);
> }
> -
> - pdev->device.driver = NULL;
> }
>
> static int
> -platform_bus_unplug(struct rte_device *dev)
> +platform_bus_unplug_device(struct rte_device *dev)
> {
> struct rte_platform_device *pdev = RTE_BUS_DEVICE(dev, *pdev);
>
> device_release_driver(pdev);
> device_cleanup(pdev);
> - rte_devargs_remove(pdev->device.devargs);
> - free(pdev);
>
> return 0;
> }
> @@ -501,10 +497,12 @@ platform_bus_cleanup(void)
> struct rte_platform_device *pdev;
>
> RTE_BUS_FOREACH_DEV(pdev, &platform_bus) {
> + if (rte_dev_is_probed(&pdev->device))
> + platform_bus_unplug_device(&pdev->device);
> +
> + rte_devargs_remove(pdev->device.devargs);
> rte_bus_remove_device(&platform_bus, &pdev->device);
> - if (!rte_dev_is_probed(&pdev->device))
> - continue;
> - platform_bus_unplug(&pdev->device);
> + free(pdev);
> }
>
> return 0;
> @@ -516,7 +514,7 @@ static struct rte_bus platform_bus = {
> .find_device = rte_bus_generic_find_device,
> .match = platform_bus_match,
> .probe_device = platform_bus_probe_device,
> - .unplug = platform_bus_unplug,
> + .unplug_device = platform_bus_unplug_device,
> .parse = platform_bus_parse,
> .dma_map = platform_bus_dma_map,
> .dma_unmap = platform_bus_dma_unmap,
> diff --git a/drivers/bus/uacce/uacce.c b/drivers/bus/uacce/uacce.c
> index 8a3c55b248..bfe1f26557 100644
> --- a/drivers/bus/uacce/uacce.c
> +++ b/drivers/bus/uacce/uacce.c
> @@ -385,40 +385,10 @@ uacce_probe_device(struct rte_driver *drv, struct rte_device *dev)
> }
>
> static int
> -uacce_cleanup(void)
> +uacce_unplug_device(struct rte_device *rte_dev)
> {
> - struct rte_uacce_device *dev;
> - int error = 0;
> -
> - RTE_BUS_FOREACH_DEV(dev, &uacce_bus) {
> - const struct rte_uacce_driver *dr;
> - int ret = 0;
> -
> - if (!rte_dev_is_probed(&dev->device))
> - goto free;
> - dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
> - if (dr->remove == NULL)
> - goto free;
> -
> - ret = dr->remove(dev);
> - if (ret < 0) {
> - rte_errno = errno;
> - error = -1;
> - }
> - dev->device.driver = NULL;
> -
> -free:
> - rte_bus_remove_device(&uacce_bus, &dev->device);
> - free(dev);
> - }
> -
> - return error;
> -}
> -
> -static int
> -uacce_detach_dev(struct rte_uacce_device *dev)
> -{
> - const struct rte_uacce_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
> + const struct rte_uacce_driver *dr = RTE_BUS_DRIVER(rte_dev->driver, *dr);
> + struct rte_uacce_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
> int ret = 0;
>
> UACCE_BUS_DEBUG("detach device %s using driver: %s", dev->device.name, dr->driver.name);
> @@ -429,25 +399,32 @@ uacce_detach_dev(struct rte_uacce_device *dev)
> return ret;
> }
>
> - dev->device.driver = NULL;
> -
> return 0;
> }
>
> static int
> -uacce_unplug(struct rte_device *dev)
> +uacce_cleanup(void)
> {
> - struct rte_uacce_device *uacce_dev = RTE_BUS_DEVICE(dev, *uacce_dev);
> - int ret;
> + struct rte_uacce_device *dev;
> + int error = 0;
>
> - ret = uacce_detach_dev(uacce_dev);
> - if (ret == 0) {
> - rte_bus_remove_device(&uacce_bus, &uacce_dev->device);
> - rte_devargs_remove(dev->devargs);
> - free(uacce_dev);
> + RTE_BUS_FOREACH_DEV(dev, &uacce_bus) {
> + int ret = 0;
> +
> + if (rte_dev_is_probed(&dev->device)) {
> + ret = uacce_unplug_device(&dev->device);
> + if (ret < 0) {
> + rte_errno = errno;
> + error = -1;
> + }
> + }
> +
> + rte_devargs_remove(dev->device.devargs);
> + rte_bus_remove_device(&uacce_bus, &dev->device);
> + free(dev);
> }
>
> - return ret;
> + return error;
> }
>
> static int
> @@ -577,7 +554,7 @@ static struct rte_bus uacce_bus = {
> .cleanup = uacce_cleanup,
> .match = uacce_bus_match,
> .probe_device = uacce_probe_device,
> - .unplug = uacce_unplug,
> + .unplug_device = uacce_unplug_device,
> .find_device = rte_bus_generic_find_device,
> .parse = uacce_parse,
> .dev_iterate = rte_bus_generic_dev_iterate,
> diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
> index 09221ccdea..7e94f86e28 100644
> --- a/drivers/bus/vdev/vdev.c
> +++ b/drivers/bus/vdev/vdev.c
> @@ -343,19 +343,15 @@ rte_vdev_init(const char *name, const char *args)
> }
>
> static int
> -vdev_remove_driver(struct rte_vdev_device *dev)
> +vdev_unplug_device(struct rte_device *rte_dev)
> {
> - const char *name = rte_vdev_device_name(dev);
> - const struct rte_vdev_driver *driver;
> + const struct rte_vdev_driver *driver = RTE_BUS_DRIVER(rte_dev->driver, *driver);
> + struct rte_vdev_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
>
> - if (!dev->device.driver) {
> - VDEV_LOG(DEBUG, "no driver attach to device %s", name);
> - return 1;
> - }
> + if (driver->remove)
> + return driver->remove(dev);
>
> - driver = RTE_BUS_DRIVER(dev->device.driver, *driver);
> -
> - return driver->remove(dev);
> + return 0;
> }
>
> RTE_EXPORT_SYMBOL(rte_vdev_uninit)
> @@ -376,7 +372,12 @@ rte_vdev_uninit(const char *name)
> goto unlock;
> }
>
> - ret = vdev_remove_driver(dev);
> + if (rte_dev_is_probed(&dev->device)) {
> + ret = vdev_unplug_device(&dev->device);
> + } else {
> + VDEV_LOG(DEBUG, "no driver attach to device %s", name);
> + ret = 1;
> + }
> if (ret)
> goto unlock;
>
> @@ -553,27 +554,21 @@ vdev_cleanup(void)
> struct rte_vdev_device *dev;
> int error = 0;
>
> + rte_spinlock_recursive_lock(&vdev_device_list_lock);
> RTE_BUS_FOREACH_DEV(dev, &rte_vdev_bus) {
> - const struct rte_vdev_driver *drv;
> int ret;
>
> - if (!rte_dev_is_probed(&dev->device))
> - goto free;
> -
> - drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
> -
> - if (drv->remove == NULL)
> - goto free;
> -
> - ret = drv->remove(dev);
> - if (ret < 0)
> - error = -1;
> + if (rte_dev_is_probed(&dev->device)) {
> + ret = vdev_unplug_device(&dev->device);
> + if (ret < 0)
> + error = -1;
> + }
>
> - dev->device.driver = NULL;
> -free:
> + rte_devargs_remove(dev->device.devargs);
> rte_bus_remove_device(&rte_vdev_bus, &dev->device);
> free(dev);
> }
> + rte_spinlock_recursive_unlock(&vdev_device_list_lock);
>
> return error;
> }
> @@ -591,12 +586,6 @@ vdev_find_device(const struct rte_bus *bus, const struct rte_device *start,
> return dev;
> }
>
> -static int
> -vdev_unplug(struct rte_device *dev)
> -{
> - return rte_vdev_uninit(dev->name);
> -}
> -
> static enum rte_iova_mode
> vdev_get_iommu_class(void)
> {
> @@ -623,7 +612,7 @@ static struct rte_bus rte_vdev_bus = {
> .find_device = vdev_find_device,
> .match = vdev_bus_match,
> .probe_device = vdev_probe_device,
> - .unplug = vdev_unplug,
> + .unplug_device = vdev_unplug_device,
> .parse = vdev_parse,
> .dma_map = vdev_dma_map,
> .dma_unmap = vdev_dma_unmap,
> diff --git a/lib/eal/common/eal_common_dev.c b/lib/eal/common/eal_common_dev.c
> index 2a2103ec57..762ed09e21 100644
> --- a/lib/eal/common/eal_common_dev.c
> +++ b/lib/eal/common/eal_common_dev.c
> @@ -385,19 +385,21 @@ local_dev_remove(struct rte_device *dev)
> {
> int ret;
>
> - if (dev->bus->unplug == NULL) {
> - EAL_LOG(ERR, "Function unplug not supported by bus (%s)",
> + if (dev->bus->unplug_device == NULL) {
> + EAL_LOG(ERR, "Function unplug_device not supported by bus (%s)",
> dev->bus->name);
> return -ENOTSUP;
> }
>
> - ret = dev->bus->unplug(dev);
> + ret = dev->bus->unplug_device(dev);
> if (ret) {
> EAL_LOG(ERR, "Driver cannot detach the device (%s)",
> dev->name);
> return (ret < 0) ? ret : -ENOENT;
> }
>
> + dev->driver = NULL;
> +
> return 0;
> }
>
> diff --git a/lib/eal/include/bus_driver.h b/lib/eal/include/bus_driver.h
> index 9711e6712b..fde55ff06d 100644
> --- a/lib/eal/include/bus_driver.h
> +++ b/lib/eal/include/bus_driver.h
> @@ -101,7 +101,7 @@ typedef int (*rte_bus_probe_device_t)(struct rte_driver *drv, struct rte_device
> * 0 on success.
> * !0 on error.
> */
> -typedef int (*rte_bus_unplug_t)(struct rte_device *dev);
> +typedef int (*rte_bus_unplug_device_t)(struct rte_device *dev);
>
> /**
> * Bus specific parsing function.
> @@ -323,7 +323,7 @@ struct rte_bus {
> rte_bus_find_device_t find_device; /**< Find a device on the bus */
> rte_bus_match_t match; /**< Check if driver matches device */
> rte_bus_probe_device_t probe_device; /**< Probe single device with driver */
> - rte_bus_unplug_t unplug; /**< Remove single device from driver */
> + rte_bus_unplug_device_t unplug_device; /**< Remove single device from driver */
> rte_bus_parse_t parse; /**< Parse a device name */
> rte_bus_dev_compare_t dev_compare; /**< Compare two device names */
> rte_bus_devargs_parse_t devargs_parse; /**< Parse bus devargs */
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v2 08/10] bus: implement cleanup in EAL
2026-06-18 15:28 ` [PATCH v2 08/10] bus: implement cleanup in EAL David Marchand
@ 2026-06-22 10:26 ` Bruce Richardson
0 siblings, 0 replies; 55+ messages in thread
From: Bruce Richardson @ 2026-06-22 10:26 UTC (permalink / raw)
To: David Marchand
Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal,
Parav Pandit, Xueming Li, Sachin Saxena, Rosen Xu, Chenbo Xia,
Nipun Gupta, Tomasz Duszynski, Wei Hu
On Thu, Jun 18, 2026 at 05:28:23PM +0200, David Marchand wrote:
> Introduce a generic cleanup helper rte_bus_generic_cleanup() that
> eliminates code duplication across bus cleanup implementations:
> unplug probed devices, remove devargs, remove from bus list,
> and free device structures.
>
> Add .free_device operation to struct rte_bus to allow buses to specify
> how to free their device structures.
> Update all buses for the new .cleanup and RTE_REGISTER_BUS prototypes.
>
> Convert to rte_bus_generic_cleanup() the buses that have both a .cleanup
> and .unplug_device: this requires implementing .free_device for them.
>
> Untouched buses are:
> - dma/idxd which has no unplug support,
> - bus/cdx which has unplug support, but no cleanup was implemented so
> far,
> - NXP buses:
> - bus/dpaa and bus/fslmc have many issues on interrupt
> allocation/setup/freeing or VFIO setup/release,
> - bus/fslmc cleanup callback is actually implemented in its internal
> VFIO layer and requires too much refactoring,
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v2 09/10] bus/vmbus: store name in bus specific device
2026-06-18 15:28 ` [PATCH v2 09/10] bus/vmbus: store name in bus specific device David Marchand
@ 2026-06-22 10:28 ` Bruce Richardson
0 siblings, 0 replies; 55+ messages in thread
From: Bruce Richardson @ 2026-06-22 10:28 UTC (permalink / raw)
To: David Marchand
Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal,
Wei Hu
On Thu, Jun 18, 2026 at 05:28:24PM +0200, David Marchand wrote:
> The device name is allocated with strdup() during scan and freed in
> several places. However, when this bus cleanup is converted to use the
> EAL generic helper, freeing the device object will require a custom
> helper to also free the device name (and for this, a cast will be
> needed).
>
> Instead, add an embedded name array to rte_vmbus_device structure
> (char name[RTE_DEV_NAME_MAX_LEN]) which is sufficient for all VMBUS
> device names (UUID format: 36 characters, or shorter legacy format).
>
> This simplifies the device freeing to a simple free() call.
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
Seems reasonable to me.
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v2 07/10] bus: align unplug with device probe
2026-06-22 10:19 ` Bruce Richardson
@ 2026-06-22 12:44 ` David Marchand
0 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-22 12:44 UTC (permalink / raw)
To: Bruce Richardson
Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal,
Parav Pandit, Xueming Li, Nipun Gupta, Nikhil Agarwal,
Sachin Saxena, Rosen Xu, Chenbo Xia, Tomasz Duszynski
On Mon, 22 Jun 2026 at 12:19, Bruce Richardson
<bruce.richardson@intel.com> wrote:
> Running an AI correctness review reports a potential issue with ifpga bus
> after this patch. Maybe worth a double check.
>
> /Bruce
>
> In ifpga_alloc_afu_dev (called at scan time, before any probe),
> afu_dev->intr_handle is allocated unconditionally.
>
> In the old ifpga_cleanup, the "goto free:" label ran for all devices, so
> intr_handle was freed unconditionally. In the new ifpga_cleanup,
> intr_handle is only freed via ifpga_unplug_device, which is only called
> when rte_dev_is_probed() returns true. For any ifpga device discovered
> during scan but never successfully probed (no matching driver, failed
> probe, blocked devargs), intr_handle is leaked. The fix should free it
> unconditionally in ifpga_cleanup, outside the rte_dev_is_probed block.
My AI friend did not see it and it gets resolved when using the generic helper.
But yes good catch.
--
David Marchand
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 00/11] Bus cleanup infrastructure and fixes
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
` (15 preceding siblings ...)
2026-06-18 15:28 ` [PATCH v2 00/10] " David Marchand
@ 2026-06-23 10:54 ` David Marchand
2026-06-23 10:54 ` [PATCH v3 01/11] bus: fix reference to plug callback David Marchand
` (10 more replies)
16 siblings, 11 replies; 55+ messages in thread
From: David Marchand @ 2026-06-23 10:54 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal
This is a followup of the previous bus refactoring.
See https://inbox.dpdk.org/dev/CAJFAV8zvFpLwz8SY8DUUezyJyM43eRZ17Yj30ex808eHC4ZE=g@mail.gmail.com/.
This series refactors the bus cleanup infrastructure to reduce code
duplication and fix resource leaks in several bus drivers.
It should address the leak Thomas pointed at.
The first part of the series (patches 1-6) addresses several bugs and
inconsistencies:
- Documentation and log message inconsistencies from earlier bus
refactoring
- Device list management issues in dma/idxd and bus/vdev
- Resource leaks in PCI and VMBUS bus cleanup (mappings and interrupts)
- Deferred interrupt allocation to probe time (VMBUS)
The core infrastructure changes (patches 7-8) introduce the generic
cleanup framework:
- Refactors unplug operations to be the counterpart of probe_device
- Implements rte_bus_generic_cleanup() to centralize cleanup logic
- Adds .free_device operation to struct rte_bus
The final patches (9-10) convert the VMBUS bus to use the generic
cleanup helper.
After this series, most buses use the generic cleanup helper, eliminating
duplicated code and ensuring consistent cleanup behavior across the
codebase.
NXP bus drivers require more (leak) fixes and refactoring and
are left untouched.
--
David Marchand
Changes since v2:
- moved ifpga interruption allocation,
Changes since v1:
- dropped all changes on DPAA and FSLMC bus,
- added one more cleanup on the first patch,
- changed coding style in rte_vdev_init,
- implemented explicit .free_device instead of hack for calling free(),
- reordered interrupt handle allocation in VMBUS bus,
David Marchand (11):
bus: fix reference to plug callback
dma/idxd: remove next pointer in bus specific device
bus/vdev: remove driver setting in probe
bus/pci: fix mapping leak in bus cleanup
bus/vmbus: fix interrupt leak in cleanup
bus/vmbus: allocate interrupt during probing
bus/ifpga: allocate interrupt during probing
bus: align unplug with device probe
bus: implement cleanup in EAL
bus/vmbus: store name in bus specific device
bus/vmbus: support unplug
doc/guides/prog_guide/device_hotplug.rst | 20 +++---
doc/guides/rel_notes/release_26_07.rst | 4 ++
drivers/bus/auxiliary/auxiliary_common.c | 54 +++------------
drivers/bus/cdx/cdx.c | 29 ++------
drivers/bus/dpaa/dpaa_bus.c | 4 +-
drivers/bus/fslmc/fslmc_bus.c | 9 +--
drivers/bus/ifpga/ifpga_bus.c | 88 ++++++++----------------
drivers/bus/pci/pci_common.c | 68 +++---------------
drivers/bus/platform/platform.c | 26 ++-----
drivers/bus/uacce/uacce.c | 59 +++-------------
drivers/bus/vdev/vdev.c | 76 ++++++++------------
drivers/bus/vmbus/bus_vmbus_driver.h | 1 +
drivers/bus/vmbus/linux/vmbus_bus.c | 16 +----
drivers/bus/vmbus/vmbus_common.c | 58 +++++++++-------
drivers/dma/idxd/idxd_bus.c | 1 -
lib/eal/common/eal_common_bus.c | 33 ++++++++-
lib/eal/common/eal_common_dev.c | 10 +--
lib/eal/include/bus_driver.h | 51 +++++++++-----
18 files changed, 234 insertions(+), 373 deletions(-)
--
2.54.0
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 01/11] bus: fix reference to plug callback
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
@ 2026-06-23 10:54 ` David Marchand
2026-06-23 10:54 ` [PATCH v3 02/11] dma/idxd: remove next pointer in bus specific device David Marchand
` (9 subsequent siblings)
10 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-23 10:54 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal
Remove now unused typedef, update documentation
and some log following the callback rename.
Fixes: 76622feba9e6 ("bus: refactor device probe")
Signed-off-by: David Marchand <david.marchand@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
Changes since v1:
- remove missed rte_bus_plug_t typedef,
---
doc/guides/prog_guide/device_hotplug.rst | 2 +-
lib/eal/common/eal_common_dev.c | 2 +-
lib/eal/include/bus_driver.h | 13 -------------
3 files changed, 2 insertions(+), 15 deletions(-)
diff --git a/doc/guides/prog_guide/device_hotplug.rst b/doc/guides/prog_guide/device_hotplug.rst
index 9896a097f3..7eb7fbcc2b 100644
--- a/doc/guides/prog_guide/device_hotplug.rst
+++ b/doc/guides/prog_guide/device_hotplug.rst
@@ -234,7 +234,7 @@ When ``rte_dev_probe()`` is called, the following sequence occurs:
and the attach operation fails if the device is not found.
#. **Device Probe**:
- The bus's ``plug()`` method is called, which triggers the device driver's probe function.
+ The bus's ``probe_device()`` method is called, which triggers the device driver's probe function.
The probe function typically allocates device-specific resources,
maps device memory regions, initializes device hardware,
and registers the device with the appropriate subsystem (e.g., ethdev for network devices).
diff --git a/lib/eal/common/eal_common_dev.c b/lib/eal/common/eal_common_dev.c
index 48b631532a..2a2103ec57 100644
--- a/lib/eal/common/eal_common_dev.c
+++ b/lib/eal/common/eal_common_dev.c
@@ -193,7 +193,7 @@ local_dev_probe(const char *devargs, struct rte_device **new_dev)
goto err_devarg;
if (da->bus->probe_device == NULL) {
- EAL_LOG(ERR, "Function plug not supported by bus (%s)",
+ EAL_LOG(ERR, "Function probe_device not supported by bus (%s)",
da->bus->name);
ret = -ENOTSUP;
goto err_devarg;
diff --git a/lib/eal/include/bus_driver.h b/lib/eal/include/bus_driver.h
index 0a7e23d98d..9711e6712b 100644
--- a/lib/eal/include/bus_driver.h
+++ b/lib/eal/include/bus_driver.h
@@ -75,19 +75,6 @@ typedef struct rte_device *
(*rte_bus_find_device_t)(const struct rte_bus *bus, const struct rte_device *start,
rte_dev_cmp_t cmp, const void *data);
-/**
- * Implementation specific probe function which is responsible for linking
- * devices on that bus with applicable drivers.
- *
- * @param dev
- * Device pointer that was returned by a previous call to find_device.
- *
- * @return
- * 0 on success.
- * !0 on error.
- */
-typedef int (*rte_bus_plug_t)(struct rte_device *dev);
-
/**
* Implementation specific probe function which is responsible for linking
* devices on that bus with applicable drivers.
--
2.54.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v3 02/11] dma/idxd: remove next pointer in bus specific device
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
2026-06-23 10:54 ` [PATCH v3 01/11] bus: fix reference to plug callback David Marchand
@ 2026-06-23 10:54 ` David Marchand
2026-06-23 10:54 ` [PATCH v3 03/11] bus/vdev: remove driver setting in probe David Marchand
` (8 subsequent siblings)
10 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-23 10:54 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Kevin Laatz
The dma/idxd devices are now stored in a list of generic rte_device
objects.
Fixes: b4f0974a995b ("bus: factorize device list")
Signed-off-by: David Marchand <david.marchand@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
drivers/dma/idxd/idxd_bus.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/dma/idxd/idxd_bus.c b/drivers/dma/idxd/idxd_bus.c
index 4810d52f2a..2ec526ec09 100644
--- a/drivers/dma/idxd/idxd_bus.c
+++ b/drivers/dma/idxd/idxd_bus.c
@@ -34,7 +34,6 @@ struct dsa_wq_addr {
/** a DSA device instance */
struct rte_dsa_device {
struct rte_device device; /**< Inherit core device */
- TAILQ_ENTRY(rte_dsa_device) next; /**< next dev in list */
char wq_name[32]; /**< the workqueue name/number e.g. wq0.1 */
struct dsa_wq_addr addr; /**< Identifies the specific WQ */
--
2.54.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v3 03/11] bus/vdev: remove driver setting in probe
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
2026-06-23 10:54 ` [PATCH v3 01/11] bus: fix reference to plug callback David Marchand
2026-06-23 10:54 ` [PATCH v3 02/11] dma/idxd: remove next pointer in bus specific device David Marchand
@ 2026-06-23 10:54 ` David Marchand
2026-06-23 10:54 ` [PATCH v3 04/11] bus/pci: fix mapping leak in bus cleanup David Marchand
` (7 subsequent siblings)
10 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-23 10:54 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal
Setting the device driver field is not the responsibility of the
probe_device callback anymore, but that of EAL (see local_dev_probe).
Yet, because of the VDEV API, rte_vdev_init() must be updated to mark
the device as probed.
Fixes: f282771a04ef ("bus: factorize driver reference")
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
Changes since v1:
- implement the same way as EAL,
---
drivers/bus/vdev/vdev.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 3bddf8938c..09221ccdea 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -188,7 +188,6 @@ vdev_probe_device(struct rte_driver *drv, struct rte_device *dev)
struct rte_vdev_driver *vdev_drv = RTE_BUS_DRIVER(drv, *vdev_drv);
const char *name;
enum rte_iova_mode iova_mode;
- int ret;
name = rte_vdev_device_name(vdev_dev);
VDEV_LOG(DEBUG, "Search driver to probe device %s", name);
@@ -200,10 +199,7 @@ vdev_probe_device(struct rte_driver *drv, struct rte_device *dev)
return -1;
}
- ret = vdev_drv->probe(vdev_dev);
- if (ret == 0)
- vdev_dev->device.driver = &vdev_drv->driver;
- return ret;
+ return vdev_drv->probe(vdev_dev);
}
/* The caller shall be responsible for thread-safe */
@@ -328,7 +324,10 @@ rte_vdev_init(const char *name, const char *args)
} else if (rte_dev_is_probed(&dev->device)) {
ret = -EEXIST;
} else {
+ dev->device.driver = drv;
ret = rte_vdev_bus.probe_device(drv, &dev->device);
+ if (ret != 0)
+ dev->device.driver = NULL;
}
if (ret < 0) {
/* If fails, remove it from vdev list */
--
2.54.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v3 04/11] bus/pci: fix mapping leak in bus cleanup
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
` (2 preceding siblings ...)
2026-06-23 10:54 ` [PATCH v3 03/11] bus/vdev: remove driver setting in probe David Marchand
@ 2026-06-23 10:54 ` David Marchand
2026-06-23 10:54 ` [PATCH v3 05/11] bus/vmbus: fix interrupt leak in cleanup David Marchand
` (6 subsequent siblings)
10 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-23 10:54 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, stable, Chenbo Xia, Nipun Gupta,
Morten Brørup, Kevin Laatz
When calling this bus cleanup, PCI resources were not unmapped.
Fixes: 1cab1a40ea9b ("bus: cleanup devices on shutdown")
Cc: stable@dpdk.org
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/pci/pci_common.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index fd18b8772b..791e9a7b49 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -344,6 +344,10 @@ pci_cleanup(void)
rte_errno = errno;
error = -1;
}
+
+ if (drv->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+ rte_pci_unmap_device(dev);
+
dev->device.driver = NULL;
free:
--
2.54.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v3 05/11] bus/vmbus: fix interrupt leak in cleanup
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
` (3 preceding siblings ...)
2026-06-23 10:54 ` [PATCH v3 04/11] bus/pci: fix mapping leak in bus cleanup David Marchand
@ 2026-06-23 10:54 ` David Marchand
2026-06-23 10:54 ` [PATCH v3 06/11] bus/vmbus: allocate interrupt during probing David Marchand
` (5 subsequent siblings)
10 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-23 10:54 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, stable, Wei Hu
When calling this bus cleanup, interrupt handle was not released.
Fixes: 65780eada9d9 ("bus/vmbus: support cleanup")
Cc: stable@dpdk.org
Signed-off-by: David Marchand <david.marchand@redhat.com>
Reviewed-by: Long Li <longli@microsoft.com>
---
drivers/bus/vmbus/vmbus_common.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index 01573927ce..74c1ddff69 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -150,6 +150,7 @@ rte_vmbus_cleanup(void)
error = -1;
rte_vmbus_unmap_device(dev);
+ rte_intr_instance_free(dev->intr_handle);
dev->device.driver = NULL;
rte_bus_remove_device(&rte_vmbus_bus, &dev->device);
--
2.54.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v3 06/11] bus/vmbus: allocate interrupt during probing
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
` (4 preceding siblings ...)
2026-06-23 10:54 ` [PATCH v3 05/11] bus/vmbus: fix interrupt leak in cleanup David Marchand
@ 2026-06-23 10:54 ` David Marchand
2026-06-23 10:54 ` [PATCH v3 07/11] bus/ifpga: " David Marchand
` (4 subsequent siblings)
10 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-23 10:54 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Wei Hu
Allocating the interrupt handle is a waste of memory if no device is
probed later (like for example, if a allowlist is passed).
Instead, allocate this handle at the time probe_device is called.
Signed-off-by: David Marchand <david.marchand@redhat.com>
Reviewed-by: Long Li <longli@microsoft.com>
---
Changes since v1:
- fixed/reordered interrupt handle allocation,
---
drivers/bus/vmbus/linux/vmbus_bus.c | 6 ------
drivers/bus/vmbus/vmbus_common.c | 18 ++++++++++++++++--
2 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/drivers/bus/vmbus/linux/vmbus_bus.c b/drivers/bus/vmbus/linux/vmbus_bus.c
index 0af10f6a69..77d904ad6d 100644
--- a/drivers/bus/vmbus/linux/vmbus_bus.c
+++ b/drivers/bus/vmbus/linux/vmbus_bus.c
@@ -345,12 +345,6 @@ vmbus_scan_one(const char *name)
}
}
- /* Allocate interrupt handle instance */
- dev->intr_handle =
- rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
- if (dev->intr_handle == NULL)
- goto error;
-
/* device is valid, add in list (sorted) */
VMBUS_LOG(DEBUG, "Adding vmbus device %s", name);
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index 74c1ddff69..bfb45e963c 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -100,10 +100,16 @@ vmbus_probe_device(struct rte_driver *drv, struct rte_device *dev)
return 1;
}
+ /* allocate interrupt handle instance */
+ vmbus_dev->intr_handle =
+ rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
+ if (vmbus_dev->intr_handle == NULL)
+ return -ENOMEM;
+
/* map resources for device */
ret = rte_vmbus_map_device(vmbus_dev);
if (ret != 0)
- return ret;
+ goto free_intr;
if (vmbus_dev->device.numa_node < 0 && rte_socket_count() > 1)
VMBUS_LOG(INFO, "Device %s is not NUMA-aware", guid);
@@ -112,7 +118,15 @@ vmbus_probe_device(struct rte_driver *drv, struct rte_device *dev)
VMBUS_LOG(INFO, " probe driver: %s", vmbus_drv->driver.name);
ret = vmbus_drv->probe(vmbus_drv, vmbus_dev);
if (ret != 0)
- rte_vmbus_unmap_device(vmbus_dev);
+ goto unmap;
+
+ return 0;
+
+unmap:
+ rte_vmbus_unmap_device(vmbus_dev);
+free_intr:
+ rte_intr_instance_free(vmbus_dev->intr_handle);
+ vmbus_dev->intr_handle = NULL;
return ret;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v3 07/11] bus/ifpga: allocate interrupt during probing
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
` (5 preceding siblings ...)
2026-06-23 10:54 ` [PATCH v3 06/11] bus/vmbus: allocate interrupt during probing David Marchand
@ 2026-06-23 10:54 ` David Marchand
2026-06-23 11:25 ` Bruce Richardson
2026-06-23 10:54 ` [PATCH v3 08/11] bus: align unplug with device probe David Marchand
` (3 subsequent siblings)
10 siblings, 1 reply; 55+ messages in thread
From: David Marchand @ 2026-06-23 10:54 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Rosen Xu
Allocating the interrupt handle is a waste of memory if no device is
probed later (like for example, if a allowlist is passed).
Instead, allocate this handle at the time probe_device is called.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/ifpga/ifpga_bus.c | 29 ++++++++++++++++-------------
1 file changed, 16 insertions(+), 13 deletions(-)
diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c
index 2c22329f65..af77d69ef6 100644
--- a/drivers/bus/ifpga/ifpga_bus.c
+++ b/drivers/bus/ifpga/ifpga_bus.c
@@ -144,14 +144,6 @@ ifpga_scan_one(struct rte_rawdev *rawdev,
afu_dev->id.uuid.uuid_high = 0;
afu_dev->id.port = afu_pr_conf.afu_id.port;
- /* Allocate interrupt instance */
- afu_dev->intr_handle =
- rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
- if (afu_dev->intr_handle == NULL) {
- IFPGA_BUS_ERR("Failed to allocate intr handle");
- goto end;
- }
-
if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get)
rawdev->dev_ops->dev_info_get(rawdev, afu_dev, sizeof(*afu_dev));
@@ -177,10 +169,7 @@ ifpga_scan_one(struct rte_rawdev *rawdev,
end:
rte_kvargs_free(kvlist);
free(path);
- if (afu_dev) {
- rte_intr_instance_free(afu_dev->intr_handle);
- free(afu_dev);
- }
+ free(afu_dev);
return NULL;
}
@@ -272,8 +261,22 @@ ifpga_probe_device(struct rte_driver *drv, struct rte_device *dev)
{
struct rte_afu_device *afu_dev = RTE_BUS_DEVICE(dev, *afu_dev);
struct rte_afu_driver *afu_drv = RTE_BUS_DRIVER(drv, *afu_drv);
+ int ret;
+
+ afu_dev->intr_handle =
+ rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
+ if (afu_dev->intr_handle == NULL) {
+ IFPGA_BUS_ERR("Failed to allocate intr handle");
+ return -ENOMEM;
+ }
+
+ ret = afu_drv->probe(afu_dev);
+ if (ret != 0) {
+ rte_intr_instance_free(afu_dev->intr_handle);
+ afu_dev->intr_handle = NULL;
+ }
- return afu_drv->probe(afu_dev);
+ return ret;
}
/*
--
2.54.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v3 08/11] bus: align unplug with device probe
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
` (6 preceding siblings ...)
2026-06-23 10:54 ` [PATCH v3 07/11] bus/ifpga: " David Marchand
@ 2026-06-23 10:54 ` David Marchand
2026-06-23 10:54 ` [PATCH v3 09/11] bus: implement cleanup in EAL David Marchand
` (2 subsequent siblings)
10 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-23 10:54 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Parav Pandit, Xueming Li, Nipun Gupta,
Nikhil Agarwal, Sachin Saxena, Rosen Xu, Chenbo Xia,
Tomasz Duszynski
Refactor bus unplug operations to be the counterpart of probe_device.
The (renamed) unplug operation now only handles:
- Driver removal (calling the driver's remove callback)
- Freeing probe-allocated resources (interrupts, mappings)
Device deletion (devargs removal, bus removal, freeing device
structure) is now handled only during bus cleanup, not in unplug.
Additionally, move driver pointer clearing from individual bus unplug
operations to EAL's local_dev_remove() where the unplug operation is
invoked. This centralizes driver lifecycle management and eliminates
code duplication across bus drivers.
For vdev, add a check in rte_vdev_uninit() since this public API can
be called on devices without a driver attached.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
doc/guides/prog_guide/device_hotplug.rst | 18 ++++---
drivers/bus/auxiliary/auxiliary_common.c | 46 ++++++----------
drivers/bus/cdx/cdx.c | 29 ++--------
drivers/bus/fslmc/fslmc_bus.c | 7 +--
drivers/bus/ifpga/ifpga_bus.c | 63 ++++++++++------------
drivers/bus/pci/pci_common.c | 57 ++++----------------
drivers/bus/platform/platform.c | 16 +++---
drivers/bus/uacce/uacce.c | 67 ++++++++----------------
drivers/bus/vdev/vdev.c | 53 ++++++++-----------
lib/eal/common/eal_common_dev.c | 8 +--
lib/eal/include/bus_driver.h | 4 +-
11 files changed, 129 insertions(+), 239 deletions(-)
diff --git a/doc/guides/prog_guide/device_hotplug.rst b/doc/guides/prog_guide/device_hotplug.rst
index 7eb7fbcc2b..d21ba0c244 100644
--- a/doc/guides/prog_guide/device_hotplug.rst
+++ b/doc/guides/prog_guide/device_hotplug.rst
@@ -165,7 +165,7 @@ using ``rte_dev_event_callback_register()`` function.
on the device in question.
When ``RTE_DEV_EVENT_REMOVE`` event is delivered,
it indicates that the kernel has removed the device;
- the application should call ``rte_dev_remove()`` to clean up EAL resources.
+ the application should call ``rte_dev_remove()`` to unplug the device driver.
Event Notification Usage
@@ -256,13 +256,17 @@ When ``rte_dev_remove()`` is called, the following sequence occurs:
See `Multi-process Synchronization`_ for details.
#. **Device Unplug**:
- The bus's ``unplug()`` method is called (``dev->bus->unplug()``),
- which triggers the driver's remove function.
- This typically stops device operations, releases device resources,
- unmaps memory regions, and unregisters from subsystems.
+ The bus's ``unplug_device()`` method is called (``dev->bus->unplug_device()``),
+ which triggers the driver's remove function
+ and releases resources allocated during probe
+ (such as interrupt handles and device memory mappings).
-#. **Devargs Cleanup**:
- The devargs associated with the device are removed from the global list.
+.. note::
+
+ The device structure, its devargs, and its entry in the bus device list
+ are NOT freed during ``rte_dev_remove()``.
+ They remain in memory until ``rte_eal_cleanup()`` is called,
+ at which point the bus's ``cleanup()`` method handles complete device deletion.
Multi-process Synchronization
diff --git a/drivers/bus/auxiliary/auxiliary_common.c b/drivers/bus/auxiliary/auxiliary_common.c
index 048aacf254..10f466e57a 100644
--- a/drivers/bus/auxiliary/auxiliary_common.c
+++ b/drivers/bus/auxiliary/auxiliary_common.c
@@ -122,13 +122,11 @@ auxiliary_probe_device(struct rte_driver *drv, struct rte_device *dev)
return ret;
}
-/*
- * Call the remove() function of the driver.
- */
static int
-rte_auxiliary_driver_remove_dev(struct rte_auxiliary_device *dev)
+auxiliary_unplug_device(struct rte_device *rte_dev)
{
- const struct rte_auxiliary_driver *drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
+ const struct rte_auxiliary_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
+ struct rte_auxiliary_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
int ret = 0;
AUXILIARY_LOG(DEBUG, "Driver %s remove auxiliary device %s on NUMA node %i",
@@ -140,8 +138,8 @@ rte_auxiliary_driver_remove_dev(struct rte_auxiliary_device *dev)
return ret;
}
- /* clear driver structure */
- dev->device.driver = NULL;
+ rte_intr_instance_free(dev->intr_handle);
+ dev->intr_handle = NULL;
return 0;
}
@@ -181,22 +179,6 @@ rte_auxiliary_unregister(struct rte_auxiliary_driver *driver)
rte_bus_remove_driver(&auxiliary_bus, &driver->driver);
}
-static int
-auxiliary_unplug(struct rte_device *dev)
-{
- struct rte_auxiliary_device *adev = RTE_BUS_DEVICE(dev, *adev);
- int ret;
-
- ret = rte_auxiliary_driver_remove_dev(adev);
- if (ret == 0) {
- rte_bus_remove_device(&auxiliary_bus, &adev->device);
- rte_devargs_remove(dev->devargs);
- rte_intr_instance_free(adev->intr_handle);
- free(adev);
- }
- return ret;
-}
-
static int
auxiliary_cleanup(void)
{
@@ -206,13 +188,17 @@ auxiliary_cleanup(void)
RTE_BUS_FOREACH_DEV(dev, &auxiliary_bus) {
int ret;
- if (!rte_dev_is_probed(&dev->device))
- continue;
- ret = auxiliary_unplug(&dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = auxiliary_unplug_device(&dev->device);
+ if (ret < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
}
+
+ rte_devargs_remove(dev->device.devargs);
+ rte_bus_remove_device(&auxiliary_bus, &dev->device);
+ free(dev);
}
return error;
@@ -265,7 +251,7 @@ struct rte_bus auxiliary_bus = {
.find_device = rte_bus_generic_find_device,
.match = auxiliary_bus_match,
.probe_device = auxiliary_probe_device,
- .unplug = auxiliary_unplug,
+ .unplug_device = auxiliary_unplug_device,
.parse = auxiliary_parse,
.dma_map = auxiliary_dma_map,
.dma_unmap = auxiliary_dma_unmap,
diff --git a/drivers/bus/cdx/cdx.c b/drivers/bus/cdx/cdx.c
index 2443161e1a..c0b46a41ad 100644
--- a/drivers/bus/cdx/cdx.c
+++ b/drivers/bus/cdx/cdx.c
@@ -374,14 +374,11 @@ rte_cdx_unregister(struct rte_cdx_driver *driver)
rte_bus_remove_driver(&rte_cdx_bus, &driver->driver);
}
-/*
- * If vendor/device ID match, call the remove() function of the
- * driver.
- */
static int
-cdx_detach_dev(struct rte_cdx_device *dev)
+cdx_unplug_device(struct rte_device *rte_dev)
{
- const struct rte_cdx_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
+ const struct rte_cdx_driver *dr = RTE_BUS_DRIVER(rte_dev->driver, *dr);
+ struct rte_cdx_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
int ret = 0;
CDX_BUS_DEBUG("detach device %s using driver: %s",
@@ -393,9 +390,6 @@ cdx_detach_dev(struct rte_cdx_device *dev)
return ret;
}
- /* clear driver structure */
- dev->device.driver = NULL;
-
rte_cdx_unmap_device(dev);
rte_intr_instance_free(dev->intr_handle);
@@ -404,21 +398,6 @@ cdx_detach_dev(struct rte_cdx_device *dev)
return 0;
}
-static int
-cdx_unplug(struct rte_device *dev)
-{
- struct rte_cdx_device *cdx_dev = RTE_BUS_DEVICE(dev, *cdx_dev);
- int ret;
-
- ret = cdx_detach_dev(cdx_dev);
- if (ret == 0) {
- rte_bus_remove_device(&rte_cdx_bus, &cdx_dev->device);
- rte_devargs_remove(dev->devargs);
- free(cdx_dev);
- }
- return ret;
-}
-
static int
cdx_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
{
@@ -452,7 +431,7 @@ static struct rte_bus rte_cdx_bus = {
.find_device = rte_bus_generic_find_device,
.match = cdx_bus_match,
.probe_device = cdx_probe_device,
- .unplug = cdx_unplug,
+ .unplug_device = cdx_unplug_device,
.parse = cdx_parse,
.dma_map = cdx_dma_map,
.dma_unmap = cdx_dma_unmap,
diff --git a/drivers/bus/fslmc/fslmc_bus.c b/drivers/bus/fslmc/fslmc_bus.c
index c7549a361a..dca4c5b182 100644
--- a/drivers/bus/fslmc/fslmc_bus.c
+++ b/drivers/bus/fslmc/fslmc_bus.c
@@ -520,6 +520,7 @@ fslmc_bus_probe_device(struct rte_driver *driver, struct rte_device *rte_dev)
return 0;
}
+ /* FIXME: probe_device should allocate intr_handle */
ret = drv->probe(drv, dev);
if (ret != 0) {
DPAA2_BUS_ERR("Unable to probe");
@@ -531,7 +532,7 @@ fslmc_bus_probe_device(struct rte_driver *driver, struct rte_device *rte_dev)
}
static int
-fslmc_bus_unplug(struct rte_device *rte_dev)
+fslmc_bus_unplug_device(struct rte_device *rte_dev)
{
struct rte_dpaa2_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
const struct rte_dpaa2_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
@@ -540,7 +541,7 @@ fslmc_bus_unplug(struct rte_device *rte_dev)
int ret = drv->remove(dev);
if (ret != 0)
return ret;
- dev->device.driver = NULL;
+ /* FIXME: unplug_device should free intr_handle */
DPAA2_BUS_INFO("%s Un-Plugged", dev->device.name);
return 0;
}
@@ -558,7 +559,7 @@ struct rte_bus rte_fslmc_bus = {
.get_iommu_class = rte_dpaa2_get_iommu_class,
.match = fslmc_bus_match,
.probe_device = fslmc_bus_probe_device,
- .unplug = fslmc_bus_unplug,
+ .unplug_device = fslmc_bus_unplug_device,
.dev_iterate = rte_bus_generic_dev_iterate,
};
diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c
index af77d69ef6..7e2e2efce0 100644
--- a/drivers/bus/ifpga/ifpga_bus.c
+++ b/drivers/bus/ifpga/ifpga_bus.c
@@ -279,6 +279,25 @@ ifpga_probe_device(struct rte_driver *drv, struct rte_device *dev)
return ret;
}
+static int
+ifpga_unplug_device(struct rte_device *dev)
+{
+ const struct rte_afu_driver *afu_drv = RTE_BUS_DRIVER(dev->driver, *afu_drv);
+ struct rte_afu_device *afu_dev = RTE_BUS_DEVICE(dev, *afu_dev);
+ int ret = 0;
+
+ if (afu_drv->remove) {
+ ret = afu_drv->remove(afu_dev);
+ if (ret)
+ return ret;
+ }
+
+ rte_intr_instance_free(afu_dev->intr_handle);
+ afu_dev->intr_handle = NULL;
+
+ return 0;
+}
+
/*
* Cleanup the content of the Intel FPGA bus, and call the remove() function
* for all registered devices.
@@ -290,52 +309,24 @@ ifpga_cleanup(void)
int error = 0;
RTE_BUS_FOREACH_DEV(afu_dev, &rte_ifpga_bus) {
- const struct rte_afu_driver *drv;
int ret = 0;
- if (!rte_dev_is_probed(&afu_dev->device))
- goto free;
- drv = RTE_BUS_DRIVER(afu_dev->device.driver, *drv);
- if (drv->remove == NULL)
- goto free;
-
- ret = drv->remove(afu_dev);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
+ if (rte_dev_is_probed(&afu_dev->device)) {
+ ret = ifpga_unplug_device(&afu_dev->device);
+ if (ret < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
}
- afu_dev->device.driver = NULL;
-free:
- rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
rte_devargs_remove(afu_dev->device.devargs);
- rte_intr_instance_free(afu_dev->intr_handle);
+ rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
free(afu_dev);
}
return error;
}
-static int
-ifpga_unplug(struct rte_device *dev)
-{
- struct rte_afu_device *afu_dev = RTE_BUS_DEVICE(dev, *afu_dev);
- const struct rte_afu_driver *afu_drv = RTE_BUS_DRIVER(dev->driver, *afu_drv);
- int ret;
-
- ret = afu_drv->remove(afu_dev);
- if (ret)
- return ret;
-
- rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
-
- rte_devargs_remove(dev->devargs);
- rte_intr_instance_free(afu_dev->intr_handle);
- free(afu_dev);
- return 0;
-
-}
-
static int
ifpga_parse(const char *name, void *addr)
{
@@ -387,7 +378,7 @@ static struct rte_bus rte_ifpga_bus = {
.find_device = rte_bus_generic_find_device,
.match = ifpga_bus_match,
.probe_device = ifpga_probe_device,
- .unplug = ifpga_unplug,
+ .unplug_device = ifpga_unplug_device,
.parse = ifpga_parse,
};
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 791e9a7b49..bf4822f7ec 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -282,13 +282,10 @@ pci_probe_device(struct rte_driver *drv, struct rte_device *dev)
return ret;
}
-/*
- * If vendor/device ID match, call the remove() function of the
- * driver.
- */
static int
-rte_pci_detach_dev(struct rte_pci_device *dev)
+pci_unplug_device(struct rte_device *rte_dev)
{
+ struct rte_pci_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
struct rte_pci_addr *loc;
const struct rte_pci_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
int ret = 0;
@@ -308,9 +305,6 @@ rte_pci_detach_dev(struct rte_pci_device *dev)
return ret;
}
- /* clear driver structure */
- dev->device.driver = NULL;
-
if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
/* unmap resources for devices that use igb_uio */
rte_pci_unmap_device(dev);
@@ -330,33 +324,17 @@ pci_cleanup(void)
int error = 0;
RTE_BUS_FOREACH_DEV(dev, &rte_pci_bus) {
- const struct rte_pci_driver *drv;
int ret = 0;
- if (!rte_dev_is_probed(&dev->device))
- goto free;
- drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
- if (drv->remove == NULL)
- goto free;
-
- ret = drv->remove(dev);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = pci_unplug_device(&dev->device);
+ if (ret < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
}
- if (drv->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
- rte_pci_unmap_device(dev);
-
- dev->device.driver = NULL;
-
-free:
- /* free interrupt handles */
- rte_intr_instance_free(dev->intr_handle);
- dev->intr_handle = NULL;
- rte_intr_instance_free(dev->vfio_req_intr_handle);
- dev->vfio_req_intr_handle = NULL;
-
+ rte_devargs_remove(dev->device.devargs);
rte_bus_remove_device(&rte_pci_bus, &dev->device);
pci_free(RTE_PCI_DEVICE_INTERNAL(dev));
}
@@ -521,21 +499,6 @@ pci_sigbus_handler(const void *failure_addr)
return ret;
}
-static int
-pci_unplug(struct rte_device *dev)
-{
- struct rte_pci_device *pdev = RTE_BUS_DEVICE(dev, *pdev);
- int ret;
-
- ret = rte_pci_detach_dev(pdev);
- if (ret == 0) {
- rte_bus_remove_device(&rte_pci_bus, &pdev->device);
- rte_devargs_remove(dev->devargs);
- pci_free(RTE_PCI_DEVICE_INTERNAL(pdev));
- }
- return ret;
-}
-
static int
pci_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
{
@@ -784,7 +747,7 @@ struct rte_bus rte_pci_bus = {
.find_device = rte_bus_generic_find_device,
.match = pci_bus_match,
.probe_device = pci_probe_device,
- .unplug = pci_unplug,
+ .unplug_device = pci_unplug_device,
.parse = pci_parse,
.dev_compare = pci_dev_compare,
.devargs_parse = rte_pci_devargs_parse,
diff --git a/drivers/bus/platform/platform.c b/drivers/bus/platform/platform.c
index 170a2e03d0..5b3c78a505 100644
--- a/drivers/bus/platform/platform.c
+++ b/drivers/bus/platform/platform.c
@@ -416,19 +416,15 @@ device_release_driver(struct rte_platform_device *pdev)
if (ret)
PLATFORM_LOG_LINE(WARNING, "failed to remove %s", pdev->name);
}
-
- pdev->device.driver = NULL;
}
static int
-platform_bus_unplug(struct rte_device *dev)
+platform_bus_unplug_device(struct rte_device *dev)
{
struct rte_platform_device *pdev = RTE_BUS_DEVICE(dev, *pdev);
device_release_driver(pdev);
device_cleanup(pdev);
- rte_devargs_remove(pdev->device.devargs);
- free(pdev);
return 0;
}
@@ -501,10 +497,12 @@ platform_bus_cleanup(void)
struct rte_platform_device *pdev;
RTE_BUS_FOREACH_DEV(pdev, &platform_bus) {
+ if (rte_dev_is_probed(&pdev->device))
+ platform_bus_unplug_device(&pdev->device);
+
+ rte_devargs_remove(pdev->device.devargs);
rte_bus_remove_device(&platform_bus, &pdev->device);
- if (!rte_dev_is_probed(&pdev->device))
- continue;
- platform_bus_unplug(&pdev->device);
+ free(pdev);
}
return 0;
@@ -516,7 +514,7 @@ static struct rte_bus platform_bus = {
.find_device = rte_bus_generic_find_device,
.match = platform_bus_match,
.probe_device = platform_bus_probe_device,
- .unplug = platform_bus_unplug,
+ .unplug_device = platform_bus_unplug_device,
.parse = platform_bus_parse,
.dma_map = platform_bus_dma_map,
.dma_unmap = platform_bus_dma_unmap,
diff --git a/drivers/bus/uacce/uacce.c b/drivers/bus/uacce/uacce.c
index 8a3c55b248..bfe1f26557 100644
--- a/drivers/bus/uacce/uacce.c
+++ b/drivers/bus/uacce/uacce.c
@@ -385,40 +385,10 @@ uacce_probe_device(struct rte_driver *drv, struct rte_device *dev)
}
static int
-uacce_cleanup(void)
+uacce_unplug_device(struct rte_device *rte_dev)
{
- struct rte_uacce_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &uacce_bus) {
- const struct rte_uacce_driver *dr;
- int ret = 0;
-
- if (!rte_dev_is_probed(&dev->device))
- goto free;
- dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
- if (dr->remove == NULL)
- goto free;
-
- ret = dr->remove(dev);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- dev->device.driver = NULL;
-
-free:
- rte_bus_remove_device(&uacce_bus, &dev->device);
- free(dev);
- }
-
- return error;
-}
-
-static int
-uacce_detach_dev(struct rte_uacce_device *dev)
-{
- const struct rte_uacce_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
+ const struct rte_uacce_driver *dr = RTE_BUS_DRIVER(rte_dev->driver, *dr);
+ struct rte_uacce_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
int ret = 0;
UACCE_BUS_DEBUG("detach device %s using driver: %s", dev->device.name, dr->driver.name);
@@ -429,25 +399,32 @@ uacce_detach_dev(struct rte_uacce_device *dev)
return ret;
}
- dev->device.driver = NULL;
-
return 0;
}
static int
-uacce_unplug(struct rte_device *dev)
+uacce_cleanup(void)
{
- struct rte_uacce_device *uacce_dev = RTE_BUS_DEVICE(dev, *uacce_dev);
- int ret;
+ struct rte_uacce_device *dev;
+ int error = 0;
- ret = uacce_detach_dev(uacce_dev);
- if (ret == 0) {
- rte_bus_remove_device(&uacce_bus, &uacce_dev->device);
- rte_devargs_remove(dev->devargs);
- free(uacce_dev);
+ RTE_BUS_FOREACH_DEV(dev, &uacce_bus) {
+ int ret = 0;
+
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = uacce_unplug_device(&dev->device);
+ if (ret < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
+ }
+
+ rte_devargs_remove(dev->device.devargs);
+ rte_bus_remove_device(&uacce_bus, &dev->device);
+ free(dev);
}
- return ret;
+ return error;
}
static int
@@ -577,7 +554,7 @@ static struct rte_bus uacce_bus = {
.cleanup = uacce_cleanup,
.match = uacce_bus_match,
.probe_device = uacce_probe_device,
- .unplug = uacce_unplug,
+ .unplug_device = uacce_unplug_device,
.find_device = rte_bus_generic_find_device,
.parse = uacce_parse,
.dev_iterate = rte_bus_generic_dev_iterate,
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 09221ccdea..7e94f86e28 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -343,19 +343,15 @@ rte_vdev_init(const char *name, const char *args)
}
static int
-vdev_remove_driver(struct rte_vdev_device *dev)
+vdev_unplug_device(struct rte_device *rte_dev)
{
- const char *name = rte_vdev_device_name(dev);
- const struct rte_vdev_driver *driver;
+ const struct rte_vdev_driver *driver = RTE_BUS_DRIVER(rte_dev->driver, *driver);
+ struct rte_vdev_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
- if (!dev->device.driver) {
- VDEV_LOG(DEBUG, "no driver attach to device %s", name);
- return 1;
- }
+ if (driver->remove)
+ return driver->remove(dev);
- driver = RTE_BUS_DRIVER(dev->device.driver, *driver);
-
- return driver->remove(dev);
+ return 0;
}
RTE_EXPORT_SYMBOL(rte_vdev_uninit)
@@ -376,7 +372,12 @@ rte_vdev_uninit(const char *name)
goto unlock;
}
- ret = vdev_remove_driver(dev);
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = vdev_unplug_device(&dev->device);
+ } else {
+ VDEV_LOG(DEBUG, "no driver attach to device %s", name);
+ ret = 1;
+ }
if (ret)
goto unlock;
@@ -553,27 +554,21 @@ vdev_cleanup(void)
struct rte_vdev_device *dev;
int error = 0;
+ rte_spinlock_recursive_lock(&vdev_device_list_lock);
RTE_BUS_FOREACH_DEV(dev, &rte_vdev_bus) {
- const struct rte_vdev_driver *drv;
int ret;
- if (!rte_dev_is_probed(&dev->device))
- goto free;
-
- drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
-
- if (drv->remove == NULL)
- goto free;
-
- ret = drv->remove(dev);
- if (ret < 0)
- error = -1;
+ if (rte_dev_is_probed(&dev->device)) {
+ ret = vdev_unplug_device(&dev->device);
+ if (ret < 0)
+ error = -1;
+ }
- dev->device.driver = NULL;
-free:
+ rte_devargs_remove(dev->device.devargs);
rte_bus_remove_device(&rte_vdev_bus, &dev->device);
free(dev);
}
+ rte_spinlock_recursive_unlock(&vdev_device_list_lock);
return error;
}
@@ -591,12 +586,6 @@ vdev_find_device(const struct rte_bus *bus, const struct rte_device *start,
return dev;
}
-static int
-vdev_unplug(struct rte_device *dev)
-{
- return rte_vdev_uninit(dev->name);
-}
-
static enum rte_iova_mode
vdev_get_iommu_class(void)
{
@@ -623,7 +612,7 @@ static struct rte_bus rte_vdev_bus = {
.find_device = vdev_find_device,
.match = vdev_bus_match,
.probe_device = vdev_probe_device,
- .unplug = vdev_unplug,
+ .unplug_device = vdev_unplug_device,
.parse = vdev_parse,
.dma_map = vdev_dma_map,
.dma_unmap = vdev_dma_unmap,
diff --git a/lib/eal/common/eal_common_dev.c b/lib/eal/common/eal_common_dev.c
index 2a2103ec57..762ed09e21 100644
--- a/lib/eal/common/eal_common_dev.c
+++ b/lib/eal/common/eal_common_dev.c
@@ -385,19 +385,21 @@ local_dev_remove(struct rte_device *dev)
{
int ret;
- if (dev->bus->unplug == NULL) {
- EAL_LOG(ERR, "Function unplug not supported by bus (%s)",
+ if (dev->bus->unplug_device == NULL) {
+ EAL_LOG(ERR, "Function unplug_device not supported by bus (%s)",
dev->bus->name);
return -ENOTSUP;
}
- ret = dev->bus->unplug(dev);
+ ret = dev->bus->unplug_device(dev);
if (ret) {
EAL_LOG(ERR, "Driver cannot detach the device (%s)",
dev->name);
return (ret < 0) ? ret : -ENOENT;
}
+ dev->driver = NULL;
+
return 0;
}
diff --git a/lib/eal/include/bus_driver.h b/lib/eal/include/bus_driver.h
index 9711e6712b..fde55ff06d 100644
--- a/lib/eal/include/bus_driver.h
+++ b/lib/eal/include/bus_driver.h
@@ -101,7 +101,7 @@ typedef int (*rte_bus_probe_device_t)(struct rte_driver *drv, struct rte_device
* 0 on success.
* !0 on error.
*/
-typedef int (*rte_bus_unplug_t)(struct rte_device *dev);
+typedef int (*rte_bus_unplug_device_t)(struct rte_device *dev);
/**
* Bus specific parsing function.
@@ -323,7 +323,7 @@ struct rte_bus {
rte_bus_find_device_t find_device; /**< Find a device on the bus */
rte_bus_match_t match; /**< Check if driver matches device */
rte_bus_probe_device_t probe_device; /**< Probe single device with driver */
- rte_bus_unplug_t unplug; /**< Remove single device from driver */
+ rte_bus_unplug_device_t unplug_device; /**< Remove single device from driver */
rte_bus_parse_t parse; /**< Parse a device name */
rte_bus_dev_compare_t dev_compare; /**< Compare two device names */
rte_bus_devargs_parse_t devargs_parse; /**< Parse bus devargs */
--
2.54.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v3 09/11] bus: implement cleanup in EAL
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
` (7 preceding siblings ...)
2026-06-23 10:54 ` [PATCH v3 08/11] bus: align unplug with device probe David Marchand
@ 2026-06-23 10:54 ` David Marchand
2026-06-23 10:54 ` [PATCH v3 10/11] bus/vmbus: store name in bus specific device David Marchand
2026-06-23 10:54 ` [PATCH v3 11/11] bus/vmbus: support unplug David Marchand
10 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-23 10:54 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Parav Pandit, Xueming Li, Sachin Saxena, Rosen Xu,
Chenbo Xia, Nipun Gupta, Tomasz Duszynski, Wei Hu
Introduce a generic cleanup helper rte_bus_generic_cleanup() that
eliminates code duplication across bus cleanup implementations:
unplug probed devices, remove devargs, remove from bus list,
and free device structures.
Add .free_device operation to struct rte_bus to allow buses to specify
how to free their device structures.
Update all buses for the new .cleanup and RTE_REGISTER_BUS prototypes.
Convert to rte_bus_generic_cleanup() the buses that have both a .cleanup
and .unplug_device: this requires implementing .free_device for them.
Untouched buses are:
- dma/idxd which has no unplug support,
- bus/cdx which has unplug support, but no cleanup was implemented so
far,
- NXP buses:
- bus/dpaa and bus/fslmc have many issues on interrupt
allocation/setup/freeing or VFIO setup/release,
- bus/fslmc cleanup callback is actually implemented in its internal
VFIO layer and requires too much refactoring,
Signed-off-by: David Marchand <david.marchand@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
Changes since v1:
- dropped hack on using free() and the check in RTE_REGISTER_BUS,
---
drivers/bus/auxiliary/auxiliary_common.c | 28 ++++---------------
drivers/bus/dpaa/dpaa_bus.c | 4 +--
drivers/bus/fslmc/fslmc_bus.c | 2 +-
drivers/bus/ifpga/ifpga_bus.c | 32 ++++------------------
drivers/bus/pci/pci_common.c | 29 +++++---------------
drivers/bus/platform/platform.c | 20 ++++----------
drivers/bus/uacce/uacce.c | 28 ++++---------------
drivers/bus/vdev/vdev.c | 26 +++++++-----------
drivers/bus/vmbus/vmbus_common.c | 6 ++---
lib/eal/common/eal_common_bus.c | 33 ++++++++++++++++++++++-
lib/eal/include/bus_driver.h | 34 +++++++++++++++++++++++-
11 files changed, 107 insertions(+), 135 deletions(-)
diff --git a/drivers/bus/auxiliary/auxiliary_common.c b/drivers/bus/auxiliary/auxiliary_common.c
index 10f466e57a..80b90a4961 100644
--- a/drivers/bus/auxiliary/auxiliary_common.c
+++ b/drivers/bus/auxiliary/auxiliary_common.c
@@ -179,29 +179,10 @@ rte_auxiliary_unregister(struct rte_auxiliary_driver *driver)
rte_bus_remove_driver(&auxiliary_bus, &driver->driver);
}
-static int
-auxiliary_cleanup(void)
+static void
+auxiliary_free_device(struct rte_device *dev)
{
- struct rte_auxiliary_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &auxiliary_bus) {
- int ret;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = auxiliary_unplug_device(&dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&auxiliary_bus, &dev->device);
- free(dev);
- }
-
- return error;
+ free(RTE_BUS_DEVICE(dev, struct rte_auxiliary_device));
}
static int
@@ -247,7 +228,8 @@ auxiliary_get_iommu_class(void)
struct rte_bus auxiliary_bus = {
.scan = auxiliary_scan,
.probe = rte_bus_generic_probe,
- .cleanup = auxiliary_cleanup,
+ .free_device = auxiliary_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = auxiliary_bus_match,
.probe_device = auxiliary_probe_device,
diff --git a/drivers/bus/dpaa/dpaa_bus.c b/drivers/bus/dpaa/dpaa_bus.c
index ee467b94d5..54779f82f7 100644
--- a/drivers/bus/dpaa/dpaa_bus.c
+++ b/drivers/bus/dpaa/dpaa_bus.c
@@ -807,12 +807,12 @@ dpaa_bus_probe_device(struct rte_driver *drv, struct rte_device *dev)
}
static int
-dpaa_bus_cleanup(void)
+dpaa_bus_cleanup(struct rte_bus *bus)
{
struct rte_dpaa_device *dev;
BUS_INIT_FUNC_TRACE();
- RTE_BUS_FOREACH_DEV(dev, &rte_dpaa_bus) {
+ RTE_BUS_FOREACH_DEV(dev, bus) {
const struct rte_dpaa_driver *drv;
int ret = 0;
diff --git a/drivers/bus/fslmc/fslmc_bus.c b/drivers/bus/fslmc/fslmc_bus.c
index dca4c5b182..1a0eca30b4 100644
--- a/drivers/bus/fslmc/fslmc_bus.c
+++ b/drivers/bus/fslmc/fslmc_bus.c
@@ -436,7 +436,7 @@ fslmc_bus_match(const struct rte_driver *drv, const struct rte_device *dev)
}
static int
-rte_fslmc_close(void)
+rte_fslmc_close(struct rte_bus *bus __rte_unused)
{
int ret = 0;
diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c
index 7e2e2efce0..79d1c3778f 100644
--- a/drivers/bus/ifpga/ifpga_bus.c
+++ b/drivers/bus/ifpga/ifpga_bus.c
@@ -298,33 +298,10 @@ ifpga_unplug_device(struct rte_device *dev)
return 0;
}
-/*
- * Cleanup the content of the Intel FPGA bus, and call the remove() function
- * for all registered devices.
- */
-static int
-ifpga_cleanup(void)
+static void
+ifpga_free_device(struct rte_device *dev)
{
- struct rte_afu_device *afu_dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(afu_dev, &rte_ifpga_bus) {
- int ret = 0;
-
- if (rte_dev_is_probed(&afu_dev->device)) {
- ret = ifpga_unplug_device(&afu_dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(afu_dev->device.devargs);
- rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
- free(afu_dev);
- }
-
- return error;
+ free(RTE_BUS_DEVICE(dev, struct rte_afu_device));
}
static int
@@ -374,7 +351,8 @@ ifpga_parse(const char *name, void *addr)
static struct rte_bus rte_ifpga_bus = {
.scan = ifpga_scan,
.probe = rte_bus_generic_probe,
- .cleanup = ifpga_cleanup,
+ .free_device = ifpga_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = ifpga_bus_match,
.probe_device = ifpga_probe_device,
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index bf4822f7ec..0f635e1537 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -317,29 +317,11 @@ pci_unplug_device(struct rte_device *rte_dev)
return 0;
}
-static int
-pci_cleanup(void)
+static void
+pci_free_device(struct rte_device *dev)
{
- struct rte_pci_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &rte_pci_bus) {
- int ret = 0;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = pci_unplug_device(&dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&rte_pci_bus, &dev->device);
- pci_free(RTE_PCI_DEVICE_INTERNAL(dev));
- }
-
- return error;
+ struct rte_pci_device *pdev = RTE_BUS_DEVICE(dev, *pdev);
+ pci_free(RTE_PCI_DEVICE_INTERNAL(pdev));
}
/* dump one device */
@@ -743,7 +725,8 @@ struct rte_bus rte_pci_bus = {
.allow_multi_probe = true,
.scan = rte_pci_scan,
.probe = rte_bus_generic_probe,
- .cleanup = pci_cleanup,
+ .free_device = pci_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = pci_bus_match,
.probe_device = pci_probe_device,
diff --git a/drivers/bus/platform/platform.c b/drivers/bus/platform/platform.c
index 5b3c78a505..90d865a8df 100644
--- a/drivers/bus/platform/platform.c
+++ b/drivers/bus/platform/platform.c
@@ -491,26 +491,17 @@ platform_bus_get_iommu_class(void)
return RTE_IOVA_DC;
}
-static int
-platform_bus_cleanup(void)
+static void
+platform_free_device(struct rte_device *dev)
{
- struct rte_platform_device *pdev;
-
- RTE_BUS_FOREACH_DEV(pdev, &platform_bus) {
- if (rte_dev_is_probed(&pdev->device))
- platform_bus_unplug_device(&pdev->device);
-
- rte_devargs_remove(pdev->device.devargs);
- rte_bus_remove_device(&platform_bus, &pdev->device);
- free(pdev);
- }
-
- return 0;
+ free(RTE_BUS_DEVICE(dev, struct rte_platform_device));
}
static struct rte_bus platform_bus = {
.scan = platform_bus_scan,
.probe = rte_bus_generic_probe,
+ .free_device = platform_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = platform_bus_match,
.probe_device = platform_bus_probe_device,
@@ -520,7 +511,6 @@ static struct rte_bus platform_bus = {
.dma_unmap = platform_bus_dma_unmap,
.get_iommu_class = platform_bus_get_iommu_class,
.dev_iterate = rte_bus_generic_dev_iterate,
- .cleanup = platform_bus_cleanup,
};
RTE_REGISTER_BUS(platform, platform_bus);
diff --git a/drivers/bus/uacce/uacce.c b/drivers/bus/uacce/uacce.c
index bfe1f26557..99a6fb314d 100644
--- a/drivers/bus/uacce/uacce.c
+++ b/drivers/bus/uacce/uacce.c
@@ -402,29 +402,10 @@ uacce_unplug_device(struct rte_device *rte_dev)
return 0;
}
-static int
-uacce_cleanup(void)
+static void
+uacce_free_device(struct rte_device *dev)
{
- struct rte_uacce_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &uacce_bus) {
- int ret = 0;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = uacce_unplug_device(&dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&uacce_bus, &dev->device);
- free(dev);
- }
-
- return error;
+ free(RTE_BUS_DEVICE(dev, struct rte_uacce_device));
}
static int
@@ -551,7 +532,8 @@ rte_uacce_unregister(struct rte_uacce_driver *driver)
static struct rte_bus uacce_bus = {
.scan = uacce_scan,
.probe = rte_bus_generic_probe,
- .cleanup = uacce_cleanup,
+ .free_device = uacce_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.match = uacce_bus_match,
.probe_device = uacce_probe_device,
.unplug_device = uacce_unplug_device,
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 7e94f86e28..02d719a44d 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -548,26 +548,19 @@ vdev_scan(void)
return 0;
}
+static void
+vdev_free_device(struct rte_device *dev)
+{
+ free(RTE_BUS_DEVICE(dev, struct rte_vdev_device));
+}
+
static int
-vdev_cleanup(void)
+vdev_cleanup(struct rte_bus *bus)
{
- struct rte_vdev_device *dev;
- int error = 0;
+ int error;
rte_spinlock_recursive_lock(&vdev_device_list_lock);
- RTE_BUS_FOREACH_DEV(dev, &rte_vdev_bus) {
- int ret;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = vdev_unplug_device(&dev->device);
- if (ret < 0)
- error = -1;
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&rte_vdev_bus, &dev->device);
- free(dev);
- }
+ error = rte_bus_generic_cleanup(bus);
rte_spinlock_recursive_unlock(&vdev_device_list_lock);
return error;
@@ -608,6 +601,7 @@ vdev_get_iommu_class(void)
static struct rte_bus rte_vdev_bus = {
.scan = vdev_scan,
.probe = rte_bus_generic_probe,
+ .free_device = vdev_free_device,
.cleanup = vdev_cleanup,
.find_device = vdev_find_device,
.match = vdev_bus_match,
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index bfb45e963c..a6e3a24a7c 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -144,12 +144,12 @@ rte_vmbus_probe(void)
}
static int
-rte_vmbus_cleanup(void)
+rte_vmbus_cleanup(struct rte_bus *bus)
{
struct rte_vmbus_device *dev;
int error = 0;
- RTE_BUS_FOREACH_DEV(dev, &rte_vmbus_bus) {
+ RTE_BUS_FOREACH_DEV(dev, bus) {
const struct rte_vmbus_driver *drv;
int ret;
@@ -167,7 +167,7 @@ rte_vmbus_cleanup(void)
rte_intr_instance_free(dev->intr_handle);
dev->device.driver = NULL;
- rte_bus_remove_device(&rte_vmbus_bus, &dev->device);
+ rte_bus_remove_device(bus, &dev->device);
free(dev);
}
diff --git a/lib/eal/common/eal_common_bus.c b/lib/eal/common/eal_common_bus.c
index ca13ccce5b..9ba23516ee 100644
--- a/lib/eal/common/eal_common_bus.c
+++ b/lib/eal/common/eal_common_bus.c
@@ -124,6 +124,37 @@ rte_bus_generic_probe(struct rte_bus *bus)
return (probed && probed == failed) ? -1 : 0;
}
+/*
+ * Generic cleanup function for buses.
+ * Iterates through all devices on the bus, unplugs probed devices,
+ * removes devargs, removes devices from the bus list, and frees device structures.
+ */
+RTE_EXPORT_INTERNAL_SYMBOL(rte_bus_generic_cleanup)
+int
+rte_bus_generic_cleanup(struct rte_bus *bus)
+{
+ struct rte_device *dev;
+ int error = 0;
+
+ RTE_VERIFY(bus->free_device);
+ RTE_VERIFY(bus->unplug_device);
+
+ while ((dev = TAILQ_FIRST(&bus->device_list)) != NULL) {
+ if (rte_dev_is_probed(dev)) {
+ if (bus->unplug_device && bus->unplug_device(dev) < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
+ }
+
+ rte_devargs_remove(dev->devargs);
+ rte_bus_remove_device(bus, dev);
+ bus->free_device(dev);
+ }
+
+ return error;
+}
+
/* Probe all devices of all buses */
RTE_EXPORT_SYMBOL(rte_bus_probe)
int
@@ -164,7 +195,7 @@ eal_bus_cleanup(void)
TAILQ_FOREACH(bus, &rte_bus_list, next) {
if (bus->cleanup == NULL)
continue;
- if (bus->cleanup() != 0)
+ if (bus->cleanup(bus) != 0)
ret = -1;
}
diff --git a/lib/eal/include/bus_driver.h b/lib/eal/include/bus_driver.h
index fde55ff06d..4f6521c87f 100644
--- a/lib/eal/include/bus_driver.h
+++ b/lib/eal/include/bus_driver.h
@@ -226,17 +226,31 @@ typedef int (*rte_bus_hot_unplug_handler_t)(struct rte_device *dev);
*/
typedef int (*rte_bus_sigbus_handler_t)(const void *failure_addr);
+/**
+ * Free a bus-specific device structure.
+ *
+ * @param dev
+ * Device pointer.
+ */
+typedef void (*rte_bus_free_device_t)(struct rte_device *dev);
+
/**
* Implementation specific cleanup function which is responsible for cleaning up
* devices on that bus with applicable drivers.
*
+ * The cleanup operation is the counterpart to scan, removing all devices added
+ * during scan.
+ *
* This is called while iterating over each registered bus.
*
+ * @param bus
+ * Pointer to the bus to cleanup.
+ *
* @return
* 0 for successful cleanup
* !0 for any error during cleanup
*/
-typedef int (*rte_bus_cleanup_t)(void);
+typedef int (*rte_bus_cleanup_t)(struct rte_bus *bus);
/**
* Check if a driver matches a device.
@@ -336,6 +350,7 @@ struct rte_bus {
/**< handle hot-unplug failure on the bus */
rte_bus_sigbus_handler_t sigbus_handler;
/**< handle sigbus error on the bus */
+ rte_bus_free_device_t free_device; /**< Free bus-specific device */
rte_bus_cleanup_t cleanup; /**< Cleanup devices on bus */
RTE_TAILQ_HEAD(, rte_device) device_list; /**< List of devices on the bus */
RTE_TAILQ_HEAD(, rte_driver) driver_list; /**< List of drivers on the bus */
@@ -624,6 +639,23 @@ struct rte_driver *rte_bus_find_driver(const struct rte_bus *bus, const struct r
__rte_internal
int rte_bus_generic_probe(struct rte_bus *bus);
+/**
+ * Generic cleanup function for buses.
+ *
+ * Iterates through all devices on the bus, unplugs probed devices,
+ * removes devargs, removes devices from the bus list, and frees device structures.
+ *
+ * This function can be used by buses that don't require special cleanup
+ * logic and just need the standard device cleanup sequence.
+ *
+ * @param bus
+ * Pointer to the bus to cleanup.
+ * @return
+ * 0 on success, -1 if any errors occurred during cleanup.
+ */
+__rte_internal
+int rte_bus_generic_cleanup(struct rte_bus *bus);
+
#ifdef __cplusplus
}
#endif
--
2.54.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v3 10/11] bus/vmbus: store name in bus specific device
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
` (8 preceding siblings ...)
2026-06-23 10:54 ` [PATCH v3 09/11] bus: implement cleanup in EAL David Marchand
@ 2026-06-23 10:54 ` David Marchand
2026-06-23 10:54 ` [PATCH v3 11/11] bus/vmbus: support unplug David Marchand
10 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-23 10:54 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Wei Hu
The device name is allocated with strdup() during scan and freed in
several places. However, when this bus cleanup is converted to use the
EAL generic helper, freeing the device object will require a custom
helper to also free the device name (and for this, a cast will be
needed).
Instead, add an embedded name array to rte_vmbus_device structure
(char name[RTE_DEV_NAME_MAX_LEN]) which is sufficient for all VMBUS
device names (UUID format: 36 characters, or shorter legacy format).
This simplifies the device freeing to a simple free() call.
Signed-off-by: David Marchand <david.marchand@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
drivers/bus/vmbus/bus_vmbus_driver.h | 1 +
drivers/bus/vmbus/linux/vmbus_bus.c | 10 +++-------
2 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/bus/vmbus/bus_vmbus_driver.h b/drivers/bus/vmbus/bus_vmbus_driver.h
index 888d856141..706ff1fcf5 100644
--- a/drivers/bus/vmbus/bus_vmbus_driver.h
+++ b/drivers/bus/vmbus/bus_vmbus_driver.h
@@ -38,6 +38,7 @@ enum hv_uio_map {
*/
struct rte_vmbus_device {
struct rte_device device; /**< Inherit core device */
+ char name[RTE_DEV_NAME_MAX_LEN]; /**< VMBUS device name */
rte_uuid_t device_id; /**< VMBUS device id */
rte_uuid_t class_id; /**< VMBUS device type */
uint32_t relid; /**< id for primary */
diff --git a/drivers/bus/vmbus/linux/vmbus_bus.c b/drivers/bus/vmbus/linux/vmbus_bus.c
index 77d904ad6d..779ea50b92 100644
--- a/drivers/bus/vmbus/linux/vmbus_bus.c
+++ b/drivers/bus/vmbus/linux/vmbus_bus.c
@@ -280,15 +280,14 @@ vmbus_scan_one(const char *name)
char filename[PATH_MAX];
char dirname[PATH_MAX];
unsigned long tmp;
- char *dev_name;
dev = calloc(1, sizeof(*dev));
if (dev == NULL)
return -1;
- dev->device.name = dev_name = strdup(name);
- if (!dev->device.name)
+ if (rte_strscpy(dev->name, name, sizeof(dev->name)) < 0)
goto error;
+ dev->device.name = dev->name;
/* sysfs base directory
* /sys/bus/vmbus/devices/7a08391f-f5a0-4ac0-9802-d13fd964f8df
@@ -305,7 +304,6 @@ vmbus_scan_one(const char *name)
/* skip non-network devices */
if (rte_uuid_compare(dev->class_id, vmbus_nic_uuid) != 0) {
- free(dev_name);
free(dev);
return 0;
}
@@ -330,7 +328,7 @@ vmbus_scan_one(const char *name)
dev->monitor_id = UINT8_MAX;
}
- dev->device.devargs = rte_bus_find_devargs(&rte_vmbus_bus, dev_name);
+ dev->device.devargs = rte_bus_find_devargs(&rte_vmbus_bus, dev->name);
dev->device.numa_node = SOCKET_ID_ANY;
if (vmbus_use_numa(dev)) {
@@ -360,7 +358,6 @@ vmbus_scan_one(const char *name)
} else { /* already registered */
VMBUS_LOG(NOTICE,
"%s already registered", name);
- free(dev_name);
free(dev);
}
return 0;
@@ -371,7 +368,6 @@ vmbus_scan_one(const char *name)
error:
VMBUS_LOG(DEBUG, "failed");
- free(dev_name);
free(dev);
return -1;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v3 11/11] bus/vmbus: support unplug
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
` (9 preceding siblings ...)
2026-06-23 10:54 ` [PATCH v3 10/11] bus/vmbus: store name in bus specific device David Marchand
@ 2026-06-23 10:54 ` David Marchand
10 siblings, 0 replies; 55+ messages in thread
From: David Marchand @ 2026-06-23 10:54 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Wei Hu
Add .unplug callback to handle driver removal, device unmapping, and
interrupt cleanup. This enables use of the generic bus cleanup helper.
The cleanup function was already performing these operations, so it
seems safe to expose them through the unplug operation.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
doc/guides/rel_notes/release_26_07.rst | 4 +++
drivers/bus/vmbus/vmbus_common.c | 41 ++++++++++++--------------
2 files changed, 23 insertions(+), 22 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 5d7aa8d1bf..55d3b44527 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -114,6 +114,10 @@ New Features
Added no-IOMMU mode for devices without or not enabling IOMMU/SVA.
+* **Added unplug operation support to VMBUS bus.**
+
+ Implemented device unplug operation to allow runtime removal of VMBUS devices.
+
* **Added selective Rx in ethdev API.**
Some parts of packets may be discarded in Rx
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index a6e3a24a7c..cd6e851e4c 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -144,34 +144,29 @@ rte_vmbus_probe(void)
}
static int
-rte_vmbus_cleanup(struct rte_bus *bus)
+vmbus_unplug_device(struct rte_device *rte_dev)
{
- struct rte_vmbus_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, bus) {
- const struct rte_vmbus_driver *drv;
- int ret;
-
- if (!rte_dev_is_probed(&dev->device))
- continue;
- drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
- if (drv->remove == NULL)
- continue;
+ const struct rte_vmbus_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
+ struct rte_vmbus_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
+ int ret = 0;
+ if (drv->remove != NULL) {
ret = drv->remove(dev);
if (ret < 0)
- error = -1;
+ return ret;
+ }
- rte_vmbus_unmap_device(dev);
- rte_intr_instance_free(dev->intr_handle);
+ rte_vmbus_unmap_device(dev);
+ rte_intr_instance_free(dev->intr_handle);
+ dev->intr_handle = NULL;
- dev->device.driver = NULL;
- rte_bus_remove_device(bus, &dev->device);
- free(dev);
- }
+ return 0;
+}
- return error;
+static void
+vmbus_free_device(struct rte_device *dev)
+{
+ free(RTE_BUS_DEVICE(dev, struct rte_vmbus_device));
}
static int
@@ -222,10 +217,12 @@ rte_vmbus_unregister(struct rte_vmbus_driver *driver)
struct rte_bus rte_vmbus_bus = {
.scan = rte_vmbus_scan,
.probe = rte_bus_generic_probe,
- .cleanup = rte_vmbus_cleanup,
+ .free_device = vmbus_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = vmbus_bus_match,
.probe_device = vmbus_probe_device,
+ .unplug_device = vmbus_unplug_device,
.parse = vmbus_parse,
.dev_compare = vmbus_dev_compare,
};
--
2.54.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [PATCH v3 07/11] bus/ifpga: allocate interrupt during probing
2026-06-23 10:54 ` [PATCH v3 07/11] bus/ifpga: " David Marchand
@ 2026-06-23 11:25 ` Bruce Richardson
0 siblings, 0 replies; 55+ messages in thread
From: Bruce Richardson @ 2026-06-23 11:25 UTC (permalink / raw)
To: David Marchand
Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal,
Rosen Xu
On Tue, Jun 23, 2026 at 12:54:34PM +0200, David Marchand wrote:
> Allocating the interrupt handle is a waste of memory if no device is
> probed later (like for example, if a allowlist is passed).
> Instead, allocate this handle at the time probe_device is called.
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
^ permalink raw reply [flat|nested] 55+ messages in thread
end of thread, other threads:[~2026-06-23 11:25 UTC | newest]
Thread overview: 55+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-11 9:45 [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
2026-06-11 9:45 ` [PATCH 01/13] bus: fix reference to plug callback David Marchand
2026-06-11 9:45 ` [PATCH 02/13] dma/idxd: remove next pointer in bus specific device David Marchand
2026-06-11 9:45 ` [PATCH 03/13] bus/vdev: remove driver setting in probe David Marchand
2026-06-11 9:45 ` [PATCH 04/13] drivers/bus: cleanup device freeing in NXP bus David Marchand
2026-06-11 9:45 ` [PATCH 05/13] drivers/bus: allocate interrupt during probing " David Marchand
2026-06-11 9:45 ` [PATCH 06/13] bus/pci: fix mapping leak in bus cleanup David Marchand
2026-06-11 9:45 ` [PATCH 07/13] bus/vmbus: fix interrupt leak in cleanup David Marchand
2026-06-11 9:45 ` [PATCH 08/13] bus/vmbus: allocate interrupt during probing David Marchand
2026-06-15 19:13 ` [EXTERNAL] " Long Li
2026-06-11 9:45 ` [PATCH 09/13] bus: align unplug with device probe David Marchand
2026-06-11 9:45 ` [PATCH 10/13] bus: implement cleanup in EAL David Marchand
2026-06-11 9:45 ` [PATCH 11/13] bus/dpaa: support unplug David Marchand
2026-06-11 9:45 ` [PATCH 12/13] bus/vmbus: store name in bus specific device David Marchand
2026-06-11 9:45 ` [PATCH 13/13] bus/vmbus: support unplug David Marchand
2026-06-11 10:09 ` [PATCH 00/13] Bus cleanup infrastructure and fixes David Marchand
2026-06-15 19:14 ` [EXTERNAL] " Long Li
2026-06-15 23:55 ` Long Li
2026-06-16 6:55 ` David Marchand
2026-06-16 7:47 ` David Marchand
2026-06-17 9:16 ` Hemant Agrawal
2026-06-18 8:39 ` David Marchand
2026-06-18 15:28 ` David Marchand
2026-06-18 15:28 ` [PATCH v2 00/10] " David Marchand
2026-06-18 15:28 ` [PATCH v2 01/10] bus: fix reference to plug callback David Marchand
2026-06-22 9:49 ` Bruce Richardson
2026-06-18 15:28 ` [PATCH v2 02/10] dma/idxd: remove next pointer in bus specific device David Marchand
2026-06-22 9:48 ` Bruce Richardson
2026-06-18 15:28 ` [PATCH v2 03/10] bus/vdev: remove driver setting in probe David Marchand
2026-06-18 15:28 ` [PATCH v2 04/10] bus/pci: fix mapping leak in bus cleanup David Marchand
2026-06-18 15:28 ` [PATCH v2 05/10] bus/vmbus: fix interrupt leak in cleanup David Marchand
2026-06-19 22:04 ` [EXTERNAL] " Long Li
2026-06-18 15:28 ` [PATCH v2 06/10] bus/vmbus: allocate interrupt during probing David Marchand
2026-06-19 22:05 ` [EXTERNAL] " Long Li
2026-06-18 15:28 ` [PATCH v2 07/10] bus: align unplug with device probe David Marchand
2026-06-22 10:19 ` Bruce Richardson
2026-06-22 12:44 ` David Marchand
2026-06-18 15:28 ` [PATCH v2 08/10] bus: implement cleanup in EAL David Marchand
2026-06-22 10:26 ` Bruce Richardson
2026-06-18 15:28 ` [PATCH v2 09/10] bus/vmbus: store name in bus specific device David Marchand
2026-06-22 10:28 ` Bruce Richardson
2026-06-18 15:28 ` [PATCH v2 10/10] bus/vmbus: support unplug David Marchand
2026-06-23 10:54 ` [PATCH v3 00/11] Bus cleanup infrastructure and fixes David Marchand
2026-06-23 10:54 ` [PATCH v3 01/11] bus: fix reference to plug callback David Marchand
2026-06-23 10:54 ` [PATCH v3 02/11] dma/idxd: remove next pointer in bus specific device David Marchand
2026-06-23 10:54 ` [PATCH v3 03/11] bus/vdev: remove driver setting in probe David Marchand
2026-06-23 10:54 ` [PATCH v3 04/11] bus/pci: fix mapping leak in bus cleanup David Marchand
2026-06-23 10:54 ` [PATCH v3 05/11] bus/vmbus: fix interrupt leak in cleanup David Marchand
2026-06-23 10:54 ` [PATCH v3 06/11] bus/vmbus: allocate interrupt during probing David Marchand
2026-06-23 10:54 ` [PATCH v3 07/11] bus/ifpga: " David Marchand
2026-06-23 11:25 ` Bruce Richardson
2026-06-23 10:54 ` [PATCH v3 08/11] bus: align unplug with device probe David Marchand
2026-06-23 10:54 ` [PATCH v3 09/11] bus: implement cleanup in EAL David Marchand
2026-06-23 10:54 ` [PATCH v3 10/11] bus/vmbus: store name in bus specific device David Marchand
2026-06-23 10:54 ` [PATCH v3 11/11] bus/vmbus: support unplug David Marchand
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox