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 <[email protected]>
---
 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

Reply via email to