[libvirt] [PATCH 4/5] qemu: Handle multipath devices properly

Michal Privoznik mprivozn at redhat.com
Mon Mar 26 05:16:45 UTC 2018


https://bugzilla.redhat.com/show_bug.cgi?id=1557769

Problem with multipath devices is that there can be several other
devices 'hidden' behind them. For instance, /dev/dm-1 can
consist of /dev/sda, /dev/sdb and /dev/sdc. Therefore, when
setting up devices CGroup and namespaces we have to take this
into account.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 libvirt.spec.in        |  2 ++
 src/qemu/qemu_cgroup.c | 43 ++++++++++++++++++++++++++++++++++---
 src/qemu/qemu_domain.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 100 insertions(+), 3 deletions(-)

diff --git a/libvirt.spec.in b/libvirt.spec.in
index b55a947ec9..ebfac10866 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -796,6 +796,8 @@ Requires: gzip
 Requires: bzip2
 Requires: lzop
 Requires: xz
+# For mpath devices
+Requires: device-mapper
     %if 0%{?fedora} || 0%{?rhel} > 7
 Requires: systemd-container
     %endif
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index b604edb31c..a2198c9789 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -60,7 +60,12 @@ qemuSetupImagePathCgroup(virDomainObjPtr vm,
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
     int perms = VIR_CGROUP_DEVICE_READ;
-    int ret;
+    unsigned long long *mpathdevs = NULL;
+    size_t nmpathdevs = 0;
+    size_t i;
+    char *devPath = NULL;
+    int rv;
+    int ret = -1;
 
     if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES))
         return 0;
@@ -71,12 +76,44 @@ qemuSetupImagePathCgroup(virDomainObjPtr vm,
     VIR_DEBUG("Allow path %s, perms: %s",
               path, virCgroupGetDevicePermsString(perms));
 
-    ret = virCgroupAllowDevicePath(priv->cgroup, path, perms, true);
+    rv = virCgroupAllowDevicePath(priv->cgroup, path, perms, true);
 
     virDomainAuditCgroupPath(vm, priv->cgroup, "allow", path,
                              virCgroupGetDevicePermsString(perms),
-                             ret);
+                             rv);
+    if (rv < 0)
+        goto cleanup;
 
+    if (virFileGetMPathTargets(path, &mpathdevs, &nmpathdevs) < 0 &&
+        errno != ENOSYS && errno != EBADF) {
+        virReportSystemError(errno,
+                             _("Unable to get mpath targets for %s"),
+                             path);
+        goto cleanup;
+    }
+
+    for (i = 0; i < nmpathdevs; i++) {
+        if (virFileMajMinToName(mpathdevs[i], &devPath) < 0) {
+            virReportSystemError(errno,
+                                 _("Unable to translate %llx to device path"),
+                                 mpathdevs[i]);
+            goto cleanup;
+        }
+
+        rv = virCgroupAllowDevicePath(priv->cgroup, devPath, perms, true);
+
+        virDomainAuditCgroupPath(vm, priv->cgroup, "allow", devPath,
+                                 virCgroupGetDevicePermsString(perms),
+                                 rv);
+        if (rv < 0)
+            goto cleanup;
+        VIR_FREE(devPath);
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(devPath);
+    VIR_FREE(mpathdevs);
     return ret;
 }
 
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 4aaf617dae..cd39eb5942 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -10105,6 +10105,10 @@ qemuDomainSetupDisk(virQEMUDriverConfigPtr cfg ATTRIBUTE_UNUSED,
 {
     virStorageSourcePtr next;
     char *dst = NULL;
+    unsigned long long *mpathdevs = NULL;
+    size_t nmpathdevs = 0;
+    char *mpathPath = NULL;
+    size_t i;
     int ret = -1;
 
     for (next = disk->src; virStorageSourceIsBacking(next); next = next->backingStore) {
@@ -10115,10 +10119,34 @@ qemuDomainSetupDisk(virQEMUDriverConfigPtr cfg ATTRIBUTE_UNUSED,
 
         if (qemuDomainCreateDevice(next->path, data, false) < 0)
             goto cleanup;
+
+        if (virFileGetMPathTargets(next->path, &mpathdevs, &nmpathdevs) < 0 &&
+            errno != ENOSYS && errno != EBADF) {
+            virReportSystemError(errno,
+                                 _("Unable to get mpath targets for %s"),
+                                 next->path);
+            goto cleanup;
+        }
+
+        for (i = 0; i < nmpathdevs; i++) {
+            if (virFileMajMinToName(mpathdevs[i], &mpathPath) < 0) {
+                virReportSystemError(errno,
+                                     _("Unable to translate %llx to device path"),
+                                     mpathdevs[i]);
+                goto cleanup;
+            }
+
+            if (qemuDomainCreateDevice(mpathPath, data, false) < 0)
+                goto cleanup;
+
+            VIR_FREE(mpathPath);
+        }
     }
 
     ret = 0;
  cleanup:
+    VIR_FREE(mpathPath);
+    VIR_FREE(mpathdevs);
     VIR_FREE(dst);
     return ret;
 }
@@ -11128,6 +11156,10 @@ qemuDomainNamespaceSetupDisk(virDomainObjPtr vm,
     virStorageSourcePtr next;
     char **paths = NULL;
     size_t npaths = 0;
+    unsigned long long *mpathdevs = NULL;
+    char **mpathdevPaths = NULL;
+    size_t nmpathdevs = 0;
+    size_t i;
     int ret = -1;
 
     if (!qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT))
@@ -11142,6 +11174,29 @@ qemuDomainNamespaceSetupDisk(virDomainObjPtr vm,
 
         if (VIR_APPEND_ELEMENT_COPY(paths, npaths, next->path) < 0)
             goto cleanup;
+
+        if (virFileGetMPathTargets(next->path, &mpathdevs, &nmpathdevs) < 0 &&
+            errno != ENOSYS && errno != EBADF) {
+            virReportSystemError(errno,
+                                 _("Unable to get mpath targets for %s"),
+                                 next->path);
+            goto cleanup;
+        }
+
+        if (VIR_ALLOC_N(mpathdevPaths, nmpathdevs) < 0)
+            goto cleanup;
+
+        for (i = 0; i < nmpathdevs; i++) {
+            if (virFileMajMinToName(mpathdevs[i], &mpathdevPaths[i]) < 0) {
+                virReportSystemError(errno,
+                                     _("Unable to translate %llx to device path"),
+                                     mpathdevs[i]);
+                goto cleanup;
+            }
+
+            if (VIR_APPEND_ELEMENT_COPY(paths, npaths, mpathdevPaths[i]) < 0)
+                goto cleanup;
+        }
     }
 
     if (qemuDomainNamespaceMknodPaths(vm, (const char **)paths, npaths) < 0)
@@ -11149,6 +11204,9 @@ qemuDomainNamespaceSetupDisk(virDomainObjPtr vm,
 
     ret = 0;
  cleanup:
+    for (i = 0; i < nmpathdevs; i++)
+        VIR_FREE(mpathdevPaths[i]);
+    VIR_FREE(mpathdevPaths);
     VIR_FREE(paths);
     return ret;
 }
-- 
2.16.1




More information about the libvir-list mailing list