Allow access to /dev/iommu and /dev/vfio/devices/vfio* when launching a qemu
VM with iommufd feature enabled.

Signed-off-by: Nathan Chen <nath...@nvidia.com>
---
 src/qemu/qemu_cgroup.c    | 47 +++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_cgroup.h    |  1 +
 src/qemu/qemu_namespace.c | 36 ++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)

diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index 48af467bf9..df4e73ad15 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -462,6 +462,47 @@ qemuTeardownInputCgroup(virDomainObj *vm,
 }
 
 
+int
+qemuSetupIommufdCgroup(virDomainObj *vm)
+{
+    qemuDomainObjPrivate *priv = vm->privateData;
+    g_autoptr(DIR) dir = NULL;
+    struct dirent *dent;
+    g_autofree char *path = NULL;
+
+    if (vm->def->iommu && vm->def->niommus > 0 &&
+        /* Check if iommufd is enabled */
+        vm->def->iommu[0]->iommufd) {
+        if (!virCgroupHasController(priv->cgroup, 
VIR_CGROUP_CONTROLLER_DEVICES))
+            return 0;
+        if (virDirOpen(&dir, "/dev/vfio/devices") < 0) {
+            if (errno == ENOENT)
+                return 0;
+            return -1;
+        }
+        while (virDirRead(dir, &dent, "/dev/vfio/devices") > 0) {
+            if (STRPREFIX(dent->d_name, "vfio")) {
+                path = g_strdup_printf("/dev/vfio/devices/%s", dent->d_name);
+            }
+            if (path &&
+                qemuCgroupAllowDevicePath(vm, path,
+                                          VIR_CGROUP_DEVICE_RW, false) < 0) {
+                return -1;
+            }
+            path = NULL;
+        }
+        if (virFileExists("/dev/iommu"))
+            path = g_strdup("/dev/iommu");
+        if (path &&
+            qemuCgroupAllowDevicePath(vm, path,
+                                      VIR_CGROUP_DEVICE_RW, false) < 0) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+
 /**
  * qemuSetupHostdevCgroup:
  * vm: domain object
@@ -830,6 +871,12 @@ qemuSetupDevicesCgroup(virDomainObj *vm)
             return -1;
     }
 
+    if (vm->def->iommu && vm->def->niommus > 0 &&
+        vm->def->iommu[0]->iommufd) {
+        if (qemuSetupIommufdCgroup(vm) < 0)
+            return -1;
+    }
+
     for (i = 0; i < vm->def->nmems; i++) {
         if (qemuSetupMemoryDevicesCgroup(vm, vm->def->mems[i]) < 0)
             return -1;
diff --git a/src/qemu/qemu_cgroup.h b/src/qemu/qemu_cgroup.h
index 3668034cde..bea677ba3c 100644
--- a/src/qemu/qemu_cgroup.h
+++ b/src/qemu/qemu_cgroup.h
@@ -42,6 +42,7 @@ int qemuSetupHostdevCgroup(virDomainObj *vm,
 int qemuTeardownHostdevCgroup(virDomainObj *vm,
                               virDomainHostdevDef *dev)
    G_GNUC_WARN_UNUSED_RESULT;
+int qemuSetupIommufdCgroup(virDomainObj *vm);
 int qemuSetupMemoryDevicesCgroup(virDomainObj *vm,
                                  virDomainMemoryDef *mem);
 int qemuTeardownMemoryDevicesCgroup(virDomainObj *vm,
diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c
index 59421ec9d1..150c6ceae3 100644
--- a/src/qemu/qemu_namespace.c
+++ b/src/qemu/qemu_namespace.c
@@ -676,6 +676,39 @@ qemuDomainSetupLaunchSecurity(virDomainObj *vm,
 }
 
 
+static int
+qemuDomainSetupIommufd(virDomainObj *vm,
+                       GSList **paths)
+{
+    g_autoptr(DIR) dir = NULL;
+    struct dirent *dent;
+    g_autofree char *path = NULL;
+
+    /* Check if iommufd is enabled */
+    if (vm->def->iommu && vm->def->niommus > 0 &&
+        vm->def->iommu[0]->iommufd) {
+        if (virDirOpen(&dir, "/dev/vfio/devices") < 0) {
+            if (errno == ENOENT)
+                return 0;
+            return -1;
+        }
+        while (virDirRead(dir, &dent, "/dev/vfio/devices") > 0) {
+            if (STRPREFIX(dent->d_name, "vfio")) {
+                path = g_strdup_printf("/dev/vfio/devices/%s", dent->d_name);
+                *paths = g_slist_prepend(*paths, g_steal_pointer(&path));
+            }
+        }
+        path = NULL;
+        if (virFileExists("/dev/iommu"))
+            path = g_strdup("/dev/iommu");
+        if (path)
+            *paths = g_slist_prepend(*paths, g_steal_pointer(&path));
+    }
+
+    return 0;
+}
+
+
 static int
 qemuNamespaceMknodPaths(virDomainObj *vm,
                         GSList *paths,
@@ -699,6 +732,9 @@ qemuDomainBuildNamespace(virQEMUDriverConfig *cfg,
     if (qemuDomainSetupAllDisks(vm, &paths) < 0)
         return -1;
 
+    if (qemuDomainSetupIommufd(vm, &paths) < 0)
+        return -1;
+
     if (qemuDomainSetupAllHostdevs(vm, &paths) < 0)
         return -1;
 
-- 
2.43.0

Reply via email to