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(a)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