Open iommufd FD from libvirt backend without exposing
these FDs to XML users, i.e. one per domain for
/dev/iommu, and pass the FD to qemu command line.
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
---
src/qemu/qemu_command.c | 8 ++++--
src/qemu/qemu_domain.c | 1 +
src/qemu/qemu_domain.h | 2 ++
src/qemu/qemu_process.c | 56 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 65 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 9b08f66175..99c310cf31 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -5229,12 +5229,14 @@ qemuBuildAcpiNodesetProps(virCommand *cmd,
static int
qemuBuildHostdevCommandLine(virCommand *cmd,
const virDomainDef *def,
- virQEMUCaps *qemuCaps)
+ virQEMUCaps *qemuCaps,
+ virDomainObj *vm)
{
size_t i;
g_autoptr(virJSONValue) props = NULL;
int iommufd = 0;
const char * iommufdId = "iommufd0";
+ qemuDomainObjPrivate *priv = vm->privateData;
for (i = 0; i < def->nhostdevs; i++) {
virDomainHostdevDef *hostdev = def->hostdevs[i];
@@ -5265,8 +5267,10 @@ qemuBuildHostdevCommandLine(virCommand *cmd,
if (subsys->u.pci.driver.iommufd == VIR_TRISTATE_BOOL_YES && iommufd == 0) {
iommufd = 1;
+ virCommandPassFD(cmd, priv->iommufd, VIR_COMMAND_PASS_FD_CLOSE_PARENT);
if (qemuMonitorCreateObjectProps(&props, "iommufd",
iommufdId,
+ "S:fd", g_strdup_printf("%d", priv->iommufd),
NULL) < 0)
return -1;
@@ -10967,7 +10971,7 @@ qemuBuildCommandLine(virDomainObj *vm,
if (qemuBuildRedirdevCommandLine(cmd, def, qemuCaps) < 0)
return NULL;
- if (qemuBuildHostdevCommandLine(cmd, def, qemuCaps) < 0)
+ if (qemuBuildHostdevCommandLine(cmd, def, qemuCaps, vm) < 0)
return NULL;
if (migrateURI)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 7601bdbb2b..d569dd5ad9 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -2042,6 +2042,7 @@ qemuDomainObjPrivateAlloc(void *opaque)
priv->blockjobs = virHashNew(virObjectUnref);
priv->fds = virHashNew(g_object_unref);
+ priv->iommufd = -1;
priv->pidMonitored = -1;
/* agent commands block by default, user can choose different behavior */
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 4736f1ede5..e55ba1c968 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -264,6 +264,8 @@ struct _qemuDomainObjPrivate {
/* named file descriptor groups associated with the VM */
GHashTable *fds;
+ int iommufd;
+
char *memoryBackingDir;
};
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index bf245ee8af..83b8a586a1 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -10272,6 +10272,38 @@ qemuProcessHandleNbdkitExit(qemuNbdkitProcess *nbdkit,
virObjectUnlock(vm);
}
+/**
+ * qemuProcessOpenIommuFd:
+ * @vm: domain object
+ * @iommuFd: returned file descriptor
+ *
+ * Opens /dev/iommu file descriptor for the VM.
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int
+qemuProcessOpenIommuFd(virDomainObj *vm, int *iommuFd)
+{
+ int fd = -1;
+
+ VIR_DEBUG("Opening IOMMU FD for domain %s", vm->def->name);
+
+ if ((fd = open("/dev/iommu", O_RDWR | O_CLOEXEC)) < 0) {
+ if (errno == ENOENT) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("IOMMU FD support requires /dev/iommu device"));
+ } else {
+ virReportSystemError(errno, "%s",
+ _("cannot open /dev/iommu"));
+ }
+ return -1;
+ }
+
+ *iommuFd = fd;
+ VIR_DEBUG("Opened IOMMU FD %d for domain %s", fd, vm->def->name);
+ return 0;
+}
+
/**
* qemuProcessOpenVfioDeviceFd:
* @hostdev: host device definition
@@ -10329,6 +10361,8 @@ qemuProcessOpenVfioDeviceFd(virDomainHostdevDef *hostdev,
int
qemuProcessOpenVfioFds(virDomainObj *vm)
{
+ qemuDomainObjPrivate *priv = vm->privateData;
+ bool needsIommuFd = false;
size_t i;
/* Check if we have any hostdevs that need VFIO FDs */
@@ -10342,6 +10376,8 @@ qemuProcessOpenVfioFds(virDomainObj *vm)
if (hostdev->source.subsys.u.pci.driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO &&
hostdev->source.subsys.u.pci.driver.iommufd == VIR_TRISTATE_BOOL_YES) {
+ needsIommuFd = true;
+
if (!hostdev->privateData) {
if (!(hostdev->privateData = qemuDomainHostdevPrivateNew()))
goto error;
@@ -10363,6 +10399,18 @@ qemuProcessOpenVfioFds(virDomainObj *vm)
}
}
+ /* Open IOMMU FD if needed */
+ if (needsIommuFd) {
+ int iommuFd = -1;
+
+ if (qemuProcessOpenIommuFd(vm, &iommuFd) < 0)
+ goto error;
+
+ priv->iommufd = iommuFd;
+
+ VIR_DEBUG("Stored IOMMU FD %d", priv->iommufd);
+ }
+
return 0;
error:
@@ -10379,6 +10427,7 @@ qemuProcessOpenVfioFds(virDomainObj *vm)
void
qemuProcessCloseVfioFds(virDomainObj *vm)
{
+ qemuDomainObjPrivate *priv = vm->privateData;
size_t i;
/* Close all VFIO device FDs */
@@ -10396,4 +10445,11 @@ qemuProcessCloseVfioFds(virDomainObj *vm)
VIR_FORCE_CLOSE(hostdevPriv->vfioDeviceFd);
}
}
+
+ /* Close IOMMU FD */
+ if (priv->iommufd >= 0) {
+ VIR_DEBUG("Closing IOMMU FD %d", priv->iommufd);
+ VIR_FORCE_CLOSE(priv->iommufd);
+ priv->iommufd = -1;
+ }
}
--
2.43.0
On a Friday in 2025, Nathan Chen via Devel wrote:
>Open iommufd FD from libvirt backend without exposing
>these FDs to XML users, i.e. one per domain for
>/dev/iommu, and pass the FD to qemu command line.
>
>Signed-off-by: Nathan Chen <nathanc@nvidia.com>
>---
> src/qemu/qemu_command.c | 8 ++++--
> src/qemu/qemu_domain.c | 1 +
> src/qemu/qemu_domain.h | 2 ++
> src/qemu/qemu_process.c | 56 +++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 65 insertions(+), 2 deletions(-)
>
>diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
>index 9b08f66175..99c310cf31 100644
>--- a/src/qemu/qemu_command.c
>+++ b/src/qemu/qemu_command.c
>@@ -5229,12 +5229,14 @@ qemuBuildAcpiNodesetProps(virCommand *cmd,
> static int
> qemuBuildHostdevCommandLine(virCommand *cmd,
> const virDomainDef *def,
>- virQEMUCaps *qemuCaps)
>+ virQEMUCaps *qemuCaps,
>+ virDomainObj *vm)
> {
> size_t i;
> g_autoptr(virJSONValue) props = NULL;
> int iommufd = 0;
> const char * iommufdId = "iommufd0";
>+ qemuDomainObjPrivate *priv = vm->privateData;
>
> for (i = 0; i < def->nhostdevs; i++) {
> virDomainHostdevDef *hostdev = def->hostdevs[i];
>@@ -5265,8 +5267,10 @@ qemuBuildHostdevCommandLine(virCommand *cmd,
>
> if (subsys->u.pci.driver.iommufd == VIR_TRISTATE_BOOL_YES && iommufd == 0) {
> iommufd = 1;
>+ virCommandPassFD(cmd, priv->iommufd, VIR_COMMAND_PASS_FD_CLOSE_PARENT);
> if (qemuMonitorCreateObjectProps(&props, "iommufd",
> iommufdId,
>+ "S:fd", g_strdup_printf("%d", priv->iommufd),
Same comment about g_strdup_printf as with the other fd: formatting.
Also, this change would be in a different function now.
> NULL) < 0)
> return -1;
>
>@@ -10967,7 +10971,7 @@ qemuBuildCommandLine(virDomainObj *vm,
> if (qemuBuildRedirdevCommandLine(cmd, def, qemuCaps) < 0)
> return NULL;
>
>- if (qemuBuildHostdevCommandLine(cmd, def, qemuCaps) < 0)
>+ if (qemuBuildHostdevCommandLine(cmd, def, qemuCaps, vm) < 0)
> return NULL;
>
> if (migrateURI)
>diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
>index 7601bdbb2b..d569dd5ad9 100644
>--- a/src/qemu/qemu_domain.c
>+++ b/src/qemu/qemu_domain.c
>@@ -2042,6 +2042,7 @@ qemuDomainObjPrivateAlloc(void *opaque)
> priv->blockjobs = virHashNew(virObjectUnref);
> priv->fds = virHashNew(g_object_unref);
>
>+ priv->iommufd = -1;
> priv->pidMonitored = -1;
>
> /* agent commands block by default, user can choose different behavior */
>diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
>index 4736f1ede5..e55ba1c968 100644
>--- a/src/qemu/qemu_domain.h
>+++ b/src/qemu/qemu_domain.h
>@@ -264,6 +264,8 @@ struct _qemuDomainObjPrivate {
> /* named file descriptor groups associated with the VM */
> GHashTable *fds;
>
>+ int iommufd;
>+
> char *memoryBackingDir;
> };
>
>diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
>index bf245ee8af..83b8a586a1 100644
>--- a/src/qemu/qemu_process.c
>+++ b/src/qemu/qemu_process.c
>@@ -10272,6 +10272,38 @@ qemuProcessHandleNbdkitExit(qemuNbdkitProcess *nbdkit,
> virObjectUnlock(vm);
> }
>
>+/**
>+ * qemuProcessOpenIommuFd:
>+ * @vm: domain object
>+ * @iommuFd: returned file descriptor
>+ *
>+ * Opens /dev/iommu file descriptor for the VM.
>+ *
>+ * Returns: 0 on success, -1 on failure
>+ */
>+static int
>+qemuProcessOpenIommuFd(virDomainObj *vm, int *iommuFd)
>+{
>+ int fd = -1;
>+
>+ VIR_DEBUG("Opening IOMMU FD for domain %s", vm->def->name);
>+
>+ if ((fd = open("/dev/iommu", O_RDWR | O_CLOEXEC)) < 0) {
>+ if (errno == ENOENT) {
>+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
>+ _("IOMMU FD support requires /dev/iommu device"));
>+ } else {
>+ virReportSystemError(errno, "%s",
>+ _("cannot open /dev/iommu"));
>+ }
>+ return -1;
>+ }
>+
>+ *iommuFd = fd;
>+ VIR_DEBUG("Opened IOMMU FD %d for domain %s", fd, vm->def->name);
>+ return 0;
>+}
>+
> /**
> * qemuProcessOpenVfioDeviceFd:
> * @hostdev: host device definition
>@@ -10329,6 +10361,8 @@ qemuProcessOpenVfioDeviceFd(virDomainHostdevDef *hostdev,
> int
> qemuProcessOpenVfioFds(virDomainObj *vm)
> {
>+ qemuDomainObjPrivate *priv = vm->privateData;
>+ bool needsIommuFd = false;
> size_t i;
>
> /* Check if we have any hostdevs that need VFIO FDs */
>@@ -10342,6 +10376,8 @@ qemuProcessOpenVfioFds(virDomainObj *vm)
> if (hostdev->source.subsys.u.pci.driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO &&
> hostdev->source.subsys.u.pci.driver.iommufd == VIR_TRISTATE_BOOL_YES) {
>
>+ needsIommuFd = true;
>+
> if (!hostdev->privateData) {
> if (!(hostdev->privateData = qemuDomainHostdevPrivateNew()))
> goto error;
>@@ -10363,6 +10399,18 @@ qemuProcessOpenVfioFds(virDomainObj *vm)
> }
> }
>
>+ /* Open IOMMU FD if needed */
>+ if (needsIommuFd) {
>+ int iommuFd = -1;
>+
No need for the intermediary variable,
>+ if (qemuProcessOpenIommuFd(vm, &iommuFd) < 0)
>+ goto error;
>+
>+ priv->iommufd = iommuFd;
>+
>+ VIR_DEBUG("Stored IOMMU FD %d", priv->iommufd);
>+ }
>+
> return 0;
>
> error:
Everything below can be dropped
Jano
>@@ -10379,6 +10427,7 @@ qemuProcessOpenVfioFds(virDomainObj *vm)
> void
> qemuProcessCloseVfioFds(virDomainObj *vm)
> {
>+ qemuDomainObjPrivate *priv = vm->privateData;
> size_t i;
>
> /* Close all VFIO device FDs */
>@@ -10396,4 +10445,11 @@ qemuProcessCloseVfioFds(virDomainObj *vm)
> VIR_FORCE_CLOSE(hostdevPriv->vfioDeviceFd);
> }
> }
>+
>+ /* Close IOMMU FD */
>+ if (priv->iommufd >= 0) {
>+ VIR_DEBUG("Closing IOMMU FD %d", priv->iommufd);
>+ VIR_FORCE_CLOSE(priv->iommufd);
>+ priv->iommufd = -1;
>+ }
> }
>--
>2.43.0
>
© 2016 - 2025 Red Hat, Inc.