Add vfio-container type and allow user to create vfio-container
object via '-object' command line argument or 'object-add' qmp command.
Add 'fd' parameter to this type to allow user provide file descriptor of
a vfio-container.
E.g.
-object vfio-container,id=ct,fd=5
Signed-off-by: Andrey Ryabinin <arbn@yandex-team.com>
---
hw/vfio/common.c | 183 ++++++++++++++++++++++------------
hw/vfio/trace-events | 2 +-
include/hw/vfio/vfio-common.h | 4 +
qapi/qom.json | 14 +++
4 files changed, 137 insertions(+), 66 deletions(-)
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 6b5d8c0bf69..392057d3025 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -31,9 +31,11 @@
#include "exec/memory.h"
#include "exec/ram_addr.h"
#include "hw/hw.h"
+#include "monitor/monitor.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/range.h"
+#include "qom/object_interfaces.h"
#include "sysemu/kvm.h"
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
@@ -2013,7 +2015,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
Error **errp)
{
VFIOContainer *container;
- int ret, fd;
+ int ret;
VFIOAddressSpace *space;
space = vfio_get_address_space(as);
@@ -2069,31 +2071,15 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
}
}
- fd = qemu_open_old("/dev/vfio/vfio", O_RDWR);
- if (fd < 0) {
- error_setg_errno(errp, errno, "failed to open /dev/vfio/vfio");
- ret = -errno;
- goto put_space_exit;
- }
+ container = VFIO_CONTAINER(object_new(TYPE_VFIO_CONTAINER));
+ container->space = space;
- ret = ioctl(fd, VFIO_GET_API_VERSION);
- if (ret != VFIO_API_VERSION) {
- error_setg(errp, "supported vfio version: %d, "
- "reported version: %d", VFIO_API_VERSION, ret);
- ret = -EINVAL;
- goto close_fd_exit;
+ user_creatable_complete(USER_CREATABLE(container), errp);
+ if (*errp) {
+ ret = -1;
+ goto free_container_exit;
}
- container = g_malloc0(sizeof(*container));
- container->space = space;
- container->fd = fd;
- container->error = NULL;
- container->dirty_pages_supported = false;
- container->dma_max_mappings = 0;
- QLIST_INIT(&container->giommu_list);
- QLIST_INIT(&container->hostwin_list);
- QLIST_INIT(&container->vrdl_list);
-
ret = vfio_init_container(container, group->fd, errp);
if (ret) {
goto free_container_exit;
@@ -2150,7 +2136,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
* in this file.
*/
if (!v2) {
- ret = ioctl(fd, VFIO_IOMMU_ENABLE);
+ ret = ioctl(container->fd, VFIO_IOMMU_ENABLE);
if (ret) {
error_setg_errno(errp, errno, "failed to enable container");
ret = -errno;
@@ -2171,7 +2157,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
}
info.argsz = sizeof(info);
- ret = ioctl(fd, VFIO_IOMMU_SPAPR_TCE_GET_INFO, &info);
+ ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_GET_INFO, &info);
if (ret) {
error_setg_errno(errp, errno,
"VFIO_IOMMU_SPAPR_TCE_GET_INFO failed");
@@ -2209,7 +2195,6 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
vfio_kvm_device_add_group(group);
- QLIST_INIT(&container->group_list);
QLIST_INSERT_HEAD(&space->containers, container, next);
group->container = container;
@@ -2223,29 +2208,18 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
ret = -1;
error_propagate_prepend(errp, container->error,
"memory listener initialization failed: ");
- goto listener_release_exit;
+ goto free_container_exit;
}
container->initialized = true;
return 0;
-listener_release_exit:
- QLIST_REMOVE(group, container_next);
- QLIST_REMOVE(container, next);
- vfio_kvm_device_del_group(group);
- vfio_listener_release(container);
enable_discards_exit:
vfio_ram_block_discard_disable(container, false);
free_container_exit:
- g_free(container);
-
-close_fd_exit:
- close(fd);
-
-put_space_exit:
- vfio_put_address_space(space);
+ object_unref(OBJECT(container));
return ret;
}
@@ -2271,32 +2245,7 @@ static void vfio_disconnect_container(VFIOGroup *group)
group->groupid);
}
- if (QLIST_EMPTY(&container->group_list)) {
- VFIOAddressSpace *space = container->space;
- VFIOGuestIOMMU *giommu, *tmp;
- VFIOHostDMAWindow *hostwin, *next;
-
- QLIST_REMOVE(container, next);
-
- QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) {
- memory_region_unregister_iommu_notifier(
- MEMORY_REGION(giommu->iommu_mr), &giommu->n);
- QLIST_REMOVE(giommu, giommu_next);
- g_free(giommu);
- }
-
- QLIST_FOREACH_SAFE(hostwin, &container->hostwin_list, hostwin_next,
- next) {
- QLIST_REMOVE(hostwin, hostwin_next);
- g_free(hostwin);
- }
-
- trace_vfio_disconnect_container(container->fd);
- close(container->fd);
- g_free(container);
-
- vfio_put_address_space(space);
- }
+ object_unref(OBJECT(container));
}
VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp)
@@ -2628,3 +2577,107 @@ int vfio_eeh_as_op(AddressSpace *as, uint32_t op)
}
return vfio_eeh_container_op(container, op);
}
+
+static void vfio_container_set_fd(Object *obj, const char *value,
+ Error **errp)
+{
+ VFIOContainer *ct = VFIO_CONTAINER(obj);
+
+ ct->fd = monitor_fd_param(monitor_cur(), value, errp);
+}
+
+static void vfio_container_complete(UserCreatable *uc, Error **errp)
+{
+ VFIOContainer *container = VFIO_CONTAINER(uc);
+ int ret;
+
+ if (container->fd < 0) {
+ int fd;
+
+ fd = qemu_open_old("/dev/vfio/vfio", O_RDWR);
+ if (fd < 0) {
+ error_setg_errno(errp, errno, "failed to open /dev/vfio/vfio");
+ return;
+ }
+ container->fd = fd;
+ }
+
+ ret = ioctl(container->fd, VFIO_GET_API_VERSION);
+ if (ret != VFIO_API_VERSION) {
+ error_setg(errp, "supported vfio version: %d, "
+ "reported version: %d", VFIO_API_VERSION, ret);
+ return;
+ }
+}
+
+static void vfio_container_class_init(ObjectClass *class, void *data)
+{
+ UserCreatableClass *ucc = USER_CREATABLE_CLASS(class);
+ ucc->complete = vfio_container_complete;
+
+ object_class_property_add_str(class, "fd", NULL, vfio_container_set_fd);
+}
+
+static void vfio_container_instance_init(Object *obj)
+{
+ VFIOContainer *ct = VFIO_CONTAINER(obj);
+
+ ct->dirty_pages_supported = false;
+ ct->dma_max_mappings = 0;
+ ct->fd = -1;
+ QLIST_INIT(&ct->giommu_list);
+ QLIST_INIT(&ct->hostwin_list);
+ QLIST_INIT(&ct->group_list);
+ QLIST_INIT(&ct->vrdl_list);
+}
+
+static void
+vfio_container_instance_finalize(Object *obj)
+{
+ VFIOContainer *container = VFIO_CONTAINER(obj);
+ VFIOAddressSpace *space = container->space;
+ VFIOGuestIOMMU *giommu, *tmp;
+ VFIOHostDMAWindow *hostwin, *next;
+
+ QLIST_REMOVE(container, next);
+
+ QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) {
+ memory_region_unregister_iommu_notifier(
+ MEMORY_REGION(giommu->iommu_mr), &giommu->n);
+ QLIST_REMOVE(giommu, giommu_next);
+ g_free(giommu);
+ }
+ QLIST_FOREACH_SAFE(hostwin, &container->hostwin_list, hostwin_next,
+ next) {
+ QLIST_REMOVE(hostwin, hostwin_next);
+ g_free(hostwin);
+ }
+
+
+ trace_vfio_container_instance_finalize(container->fd);
+ if (container->fd > 0) {
+ close(container->fd);
+ }
+ if (space) {
+ vfio_put_address_space(space);
+ }
+}
+
+static const TypeInfo vfio_container_info = {
+ .name = TYPE_VFIO_CONTAINER,
+ .parent = TYPE_OBJECT,
+ .class_init = vfio_container_class_init,
+ .instance_size = sizeof(VFIOContainer),
+ .instance_init = vfio_container_instance_init,
+ .instance_finalize = vfio_container_instance_finalize,
+ .interfaces = (InterfaceInfo[]) {
+ {TYPE_USER_CREATABLE},
+ {}
+ },
+};
+
+static void register_vfio_types(void)
+{
+ type_register_static(&vfio_container_info);
+}
+type_init(register_vfio_types)
diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events
index 73dffe9e00d..8b79cf33a33 100644
--- a/hw/vfio/trace-events
+++ b/hw/vfio/trace-events
@@ -104,7 +104,7 @@ vfio_known_safe_misalignment(const char *name, uint64_t iova, uint64_t offset_wi
vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t size, uint64_t page_size) "Region \"%s\" 0x%"PRIx64" size=0x%"PRIx64" is not aligned to 0x%"PRIx64" and cannot be mapped for DMA"
vfio_listener_region_del_skip(uint64_t start, uint64_t end) "SKIPPING region_del 0x%"PRIx64" - 0x%"PRIx64
vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64
-vfio_disconnect_container(int fd) "close container->fd=%d"
+vfio_container_instance_finalize(int fd) "close container->fd=%d"
vfio_put_group(int fd) "close group->fd=%d"
vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u"
vfio_put_base_device(int fd) "close vdev->fd=%d"
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index e573f5a9f19..0ab99060e44 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -77,6 +77,7 @@ typedef struct VFIOAddressSpace {
struct VFIOGroup;
typedef struct VFIOContainer {
+ Object parent;
VFIOAddressSpace *space;
int fd; /* /dev/vfio/vfio, empowered by the attached groups */
MemoryListener listener;
@@ -190,6 +191,9 @@ typedef struct VFIODisplay {
} dmabuf;
} VFIODisplay;
+#define TYPE_VFIO_CONTAINER "vfio-container"
+OBJECT_DECLARE_SIMPLE_TYPE(VFIOContainer, VFIO_CONTAINER)
+
void vfio_put_base_device(VFIODevice *vbasedev);
void vfio_disable_irqindex(VFIODevice *vbasedev, int index);
void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index);
diff --git a/qapi/qom.json b/qapi/qom.json
index 80dd419b392..d1a88e10b52 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -734,6 +734,18 @@
{ 'struct': 'RemoteObjectProperties',
'data': { 'fd': 'str', 'devid': 'str' } }
+##
+# @VFIOContainerProperties:
+#
+# Properties for vfio-container objects.
+#
+# @fd: file descriptor of vfio container
+#
+# Since: 7.2
+##
+{ 'struct': 'VFIOContainerProperties',
+ 'data': { 'fd': 'str' } }
+
##
# @VfioUserServerProperties:
#
@@ -888,6 +900,7 @@
'tls-creds-psk',
'tls-creds-x509',
'tls-cipher-suites',
+ 'vfio-container',
{ 'name': 'x-remote-object', 'features': [ 'unstable' ] },
{ 'name': 'x-vfio-user-server', 'features': [ 'unstable' ] }
] }
@@ -953,6 +966,7 @@
'tls-creds-psk': 'TlsCredsPskProperties',
'tls-creds-x509': 'TlsCredsX509Properties',
'tls-cipher-suites': 'TlsCredsProperties',
+ 'vfio-container': 'VFIOContainerProperties',
'x-remote-object': 'RemoteObjectProperties',
'x-vfio-user-server': 'VfioUserServerProperties'
} }
--
2.37.3
© 2016 - 2026 Red Hat, Inc.