From: Pavel Hrdina <phrdina@redhat.com>
When fdgroup is used for iommufd we will start QEMU with -object iommufd
even if the VM has no host device. When virDomainFDAssociate() is used
the FD libvirt is holding is closed with connection.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
src/qemu/qemu_command.c | 4 +++-
src/qemu/qemu_hotplug.c | 4 ++--
src/qemu/qemu_process.c | 47 ++++++++++++++++++++++++++++++++++++++---
3 files changed, 49 insertions(+), 6 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 7286fd8b83..7801d99738 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -5367,8 +5367,10 @@ qemuBuildIOMMUFDCommandLine(virCommand *cmd,
qemuDomainObjPrivate *priv = vm->privateData;
g_autoptr(virJSONValue) props = NULL;
- if (!virDomainDefHasPCIHostdevWithIOMMUFD(def))
+ if (!virDomainDefHasPCIHostdevWithIOMMUFD(def) &&
+ !def->iommufd_fdgroup) {
return 0;
+ }
qemuFDPassDirectTransferCommand(priv->iommufd, cmd);
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index adae94f0a2..c86ebc59d0 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1615,7 +1615,7 @@ qemuDomainAttachHostPCIDevice(virQEMUDriver *driver,
if (qemuProcessOpenVfioDeviceFd(vm, hostdev) < 0)
goto error;
- if (!priv->iommufdState) {
+ if (!priv->iommufdState && !vm->def->iommufd_fdgroup) {
if (qemuProcessOpenIommuFd(vm) < 0)
goto error;
@@ -5041,7 +5041,7 @@ qemuDomainRemoveHostDevice(virQEMUDriver *driver,
}
}
- if (priv->iommufdState &&
+ if (priv->iommufdState && !vm->def->iommufd_fdgroup &&
!virDomainDefHasPCIHostdevWithIOMMUFD(vm->def)) {
qemuDomainObjEnterMonitor(vm);
ignore_value(qemuMonitorDelObject(priv->mon, "iommufd0", false));
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index fed6079ad2..c78fb4273c 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -7743,6 +7743,44 @@ qemuProcessOpenIommuFd(virDomainObj *vm)
return 0;
}
+/**
+ * qemuProcessPrepareIommuFd:
+ * @vm: domain object
+ *
+ * Find passed FD via virDomainFDAssociate() API for the VM.
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int
+qemuProcessPrepareIommuFd(virDomainObj *vm)
+{
+ qemuDomainObjPrivate *priv = vm->privateData;
+ virDomainFDTuple *fdt = virHashLookup(priv->fds, vm->def->iommufd_fdgroup);
+ VIR_AUTOCLOSE iommufd = -1;
+
+ if (!fdt) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("file descriptor group '%1$s' was not associated with the domain"),
+ vm->def->iommufd_fdgroup);
+ return -1;
+ }
+
+ if (fdt->nfds != 1) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("Only one file descriptor needs to be associated with iommufd"));
+ return -1;
+ }
+
+ iommufd = dup(fdt->fds[0]);
+
+ if (qemuSecuritySetImageFDLabel(priv->driver->securityManager, vm->def, iommufd) < 0)
+ return -1;
+
+ priv->iommufd = qemuFDPassDirectNew("iommufd", &iommufd);
+
+ return 0;
+}
+
/**
* qemuProcessOpenVfioDeviceFd:
* @hostdev: host device definition
@@ -7798,9 +7836,12 @@ qemuProcessPrepareHostHostdev(virDomainObj *vm)
}
/* Open IOMMU FD */
- if (virDomainDefHasPCIHostdevWithIOMMUFD(vm->def) &&
- qemuProcessOpenIommuFd(vm) < 0) {
- return -1;
+ if (vm->def->iommufd_fdgroup) {
+ if (qemuProcessPrepareIommuFd(vm) < 0)
+ return -1;
+ } else if (virDomainDefHasPCIHostdevWithIOMMUFD(vm->def)) {
+ if (qemuProcessOpenIommuFd(vm) < 0)
+ return -1;
}
return 0;
--
2.53.0
On Thu, Mar 19, 2026 at 17:36:56 +0100, Pavel Hrdina via Devel wrote:
> From: Pavel Hrdina <phrdina@redhat.com>
>
> When fdgroup is used for iommufd we will start QEMU with -object iommufd
> even if the VM has no host device. When virDomainFDAssociate() is used
> the FD libvirt is holding is closed with connection.
>
> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
> src/qemu/qemu_command.c | 4 +++-
> src/qemu/qemu_hotplug.c | 4 ++--
> src/qemu/qemu_process.c | 47 ++++++++++++++++++++++++++++++++++++++---
> 3 files changed, 49 insertions(+), 6 deletions(-)
>
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 7286fd8b83..7801d99738 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -5367,8 +5367,10 @@ qemuBuildIOMMUFDCommandLine(virCommand *cmd,
> qemuDomainObjPrivate *priv = vm->privateData;
> g_autoptr(virJSONValue) props = NULL;
>
> - if (!virDomainDefHasPCIHostdevWithIOMMUFD(def))
> + if (!virDomainDefHasPCIHostdevWithIOMMUFD(def) &&
> + !def->iommufd_fdgroup) {
> return 0;
> + }
>
> qemuFDPassDirectTransferCommand(priv->iommufd, cmd);
>
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index adae94f0a2..c86ebc59d0 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -1615,7 +1615,7 @@ qemuDomainAttachHostPCIDevice(virQEMUDriver *driver,
> if (qemuProcessOpenVfioDeviceFd(vm, hostdev) < 0)
> goto error;
>
> - if (!priv->iommufdState) {
> + if (!priv->iommufdState && !vm->def->iommufd_fdgroup) {
> if (qemuProcessOpenIommuFd(vm) < 0)
> goto error;
>
> @@ -5041,7 +5041,7 @@ qemuDomainRemoveHostDevice(virQEMUDriver *driver,
> }
> }
>
> - if (priv->iommufdState &&
> + if (priv->iommufdState && !vm->def->iommufd_fdgroup &&
> !virDomainDefHasPCIHostdevWithIOMMUFD(vm->def)) {
> qemuDomainObjEnterMonitor(vm);
> ignore_value(qemuMonitorDelObject(priv->mon, "iommufd0", false));
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index fed6079ad2..c78fb4273c 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -7743,6 +7743,44 @@ qemuProcessOpenIommuFd(virDomainObj *vm)
> return 0;
> }
>
> +/**
> + * qemuProcessPrepareIommuFd:
> + * @vm: domain object
> + *
> + * Find passed FD via virDomainFDAssociate() API for the VM.
> + *
> + * Returns: 0 on success, -1 on failure
> + */
> +static int
> +qemuProcessPrepareIommuFd(virDomainObj *vm)
Since this function prepares the iommufd only when passed via FDpass, it
really should have it in the name.
> +{
> + qemuDomainObjPrivate *priv = vm->privateData;
> + virDomainFDTuple *fdt = virHashLookup(priv->fds, vm->def->iommufd_fdgroup);
> + VIR_AUTOCLOSE iommufd = -1;
> +
> + if (!fdt) {
> + virReportError(VIR_ERR_INVALID_ARG,
> + _("file descriptor group '%1$s' was not associated with the domain"),
> + vm->def->iommufd_fdgroup);
> + return -1;
> + }
> +
> + if (fdt->nfds != 1) {
> + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> + _("Only one file descriptor needs to be associated with iommufd"));
> + return -1;
> + }
> +
> + iommufd = dup(fdt->fds[0]);
> +
> + if (qemuSecuritySetImageFDLabel(priv->driver->securityManager, vm->def, iommufd) < 0)
> + return -1;
I wanted to complain that this doesn't look right. (setting 'image'
label on the FD), but noticed that the other branch of when qemu opens
it does the same and additionally the selinux driver also internally
sets the image label.
> +
> + priv->iommufd = qemuFDPassDirectNew("iommufd", &iommufd);
> +
> + return 0;a
With the function renamed:
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
© 2016 - 2026 Red Hat, Inc.