File a30078cb-qemu-create-mp-target.patch of Package libvirt.14190
commit a30078cb832646177defd256e77c632905f1e6d0
Author: Michal Prívozník <mprivozn@redhat.com>
Date: Wed Nov 13 15:34:50 2019 +0100
qemu: Create multipath targets for PRs
If a disk has persistent reservations enabled, qemu-pr-helper
might open not only /dev/mapper/control but also individual
targets of the multipath device. We are already querying for them
in CGroups, but now we have to create them in the namespace too.
This was brought up in [1].
1: https://bugzilla.redhat.com/show_bug.cgi?id=1711045#c61
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Tested-by: Lin Ma <LMa@suse.com>
Reviewed-by: Jim Fehlig <jfehlig@suse.com>
Index: libvirt-5.1.0/src/qemu/qemu_domain.c
===================================================================
--- libvirt-5.1.0.orig/src/qemu/qemu_domain.c
+++ libvirt-5.1.0/src/qemu/qemu_domain.c
@@ -55,6 +55,7 @@
#include "secret_util.h"
#include "logging/log_manager.h"
#include "locking/domain_lock.h"
+#include "virdevmapper.h"
#ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h>
@@ -11920,6 +11921,9 @@ qemuDomainSetupDisk(virQEMUDriverConfigP
int ret = -1;
for (next = disk->src; virStorageSourceIsBacking(next); next = next->backingStore) {
+ VIR_AUTOSTRINGLIST targetPaths = NULL;
+ size_t i;
+
if (!next->path || !virStorageSourceIsLocalStorage(next)) {
/* Not creating device. Just continue. */
continue;
@@ -11927,6 +11931,19 @@ qemuDomainSetupDisk(virQEMUDriverConfigP
if (qemuDomainCreateDevice(next->path, data, false) < 0)
goto cleanup;
+
+ if (virDevMapperGetTargets(next->path, &targetPaths) < 0 &&
+ errno != ENOSYS && errno != EBADF) {
+ virReportSystemError(errno,
+ _("Unable to get devmapper targets for %s"),
+ next->path);
+ return -1;
+ }
+
+ for (i = 0; targetPaths && targetPaths[i]; i++) {
+ if (qemuDomainCreateDevice(targetPaths[i], data, false) < 0)
+ return -1;
+ }
}
/* qemu-pr-helper might require access to /dev/mapper/control. */
@@ -12966,36 +12983,43 @@ qemuDomainNamespaceSetupDisk(virDomainOb
virStorageSourcePtr src)
{
virStorageSourcePtr next;
- const char **paths = NULL;
+ VIR_AUTOSTRINGLIST paths = NULL;
size_t npaths = 0;
- char *dmPath = NULL;
- int ret = -1;
for (next = src; virStorageSourceIsBacking(next); next = next->backingStore) {
+ VIR_AUTOSTRINGLIST targetPaths = NULL;
+
if (virStorageSourceIsEmpty(next) ||
!virStorageSourceIsLocalStorage(next)) {
/* Not creating device. Just continue. */
continue;
}
- if (VIR_APPEND_ELEMENT_COPY(paths, npaths, next->path) < 0)
- goto cleanup;
+ if (virStringListAdd(&paths, next->path) < 0)
+ return -1;
+
+ if (virDevMapperGetTargets(next->path, &targetPaths) < 0 &&
+ errno != ENOSYS && errno != EBADF) {
+ virReportSystemError(errno,
+ _("Unable to get devmapper targets for %s"),
+ next->path);
+ return -1;
+ }
+
+ if (virStringListMerge(&paths, &targetPaths) < 0)
+ return -1;
}
/* qemu-pr-helper might require access to /dev/mapper/control. */
if (src->pr &&
- (VIR_STRDUP(dmPath, DEVICE_MAPPER_CONTROL_PATH) < 0 ||
- VIR_APPEND_ELEMENT_COPY(paths, npaths, dmPath) < 0))
- goto cleanup;
+ virStringListAdd(&paths, DEVICE_MAPPER_CONTROL_PATH) < 0)
+ return -1;
- if (qemuDomainNamespaceMknodPaths(vm, paths, npaths) < 0)
- goto cleanup;
+ npaths = virStringListLength((const char **) paths);
+ if (qemuDomainNamespaceMknodPaths(vm, (const char **) paths, npaths) < 0)
+ return -1;
- ret = 0;
- cleanup:
- VIR_FREE(dmPath);
- VIR_FREE(paths);
- return ret;
+ return 0;
}
Index: libvirt-5.1.0/src/util/virdevmapper.h
===================================================================
--- libvirt-5.1.0.orig/src/util/virdevmapper.h
+++ libvirt-5.1.0/src/util/virdevmapper.h
@@ -18,11 +18,13 @@
* <http://www.gnu.org/licenses/>.
*/
+#include "internal.h"
+
#ifndef LIBVIRT_VIRDEVMAPPER_H
# define LIBVIRT_VIRDEVMAPPER_H
int
virDevMapperGetTargets(const char *path,
- char ***devPaths);
+ char ***devPaths) ATTRIBUTE_NOINLINE;
#endif /* LIBVIRT_VIRDEVMAPPER_H */
Index: libvirt-5.1.0/src/util/virutil.h
===================================================================
--- libvirt-5.1.0.orig/src/util/virutil.h
+++ libvirt-5.1.0/src/util/virutil.h
@@ -160,7 +160,7 @@ bool virValidateWWN(const char *wwn);
int virGetDeviceID(const char *path,
int *maj,
- int *min);
+ int *min) ATTRIBUTE_NOINLINE;
int virSetDeviceUnprivSGIO(const char *path,
const char *sysfs_dir,
int unpriv_sgio);
Index: libvirt-5.1.0/tests/qemuhotplugmock.c
===================================================================
--- /dev/null
+++ libvirt-5.1.0/tests/qemuhotplugmock.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 IBM Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "qemu/qemu_process.h"
+#include "virdevmapper.h"
+#include "virutil.h"
+#include "virmock.h"
+
+
+static int (*real_virGetDeviceID)(const char *path, int *maj, int *min);
+static bool (*real_virFileExists)(const char *path);
+
+static void
+init_syms(void)
+{
+ if (real_virFileExists)
+ return;
+
+ VIR_MOCK_REAL_INIT(virGetDeviceID);
+ VIR_MOCK_REAL_INIT(virFileExists);
+}
+
+int
+virDevMapperGetTargets(const char *path,
+ char ***devPaths)
+{
+ *devPaths = NULL;
+
+ if (STREQ(path, "/dev/mapper/virt")) {
+ devPaths = malloc(sizeof(char *) * 4);
+ //ignore_value(VIR_STRDUP((*devPaths)[0], "/dev/block/8:0")); /* /dev/sda */
+ //ignore_value(VIR_STRDUP((*devPaths)[1], "/dev/block/8:16")); /* /dev/sdb */
+ //ignore_value(VIR_STRDUP((*devPaths)[2], "/dev/block/8:32")); /* /dev/sdc */
+ (*devPaths)[0] = NULL;
+ (*devPaths)[1] = NULL;
+ (*devPaths)[2] = NULL;
+ (*devPaths)[3] = NULL;
+ }
+
+ return 0;
+}
+
+
+int
+virGetDeviceID(const char *path, int *maj, int *min)
+{
+ init_syms();
+
+ if (STREQ(path, "/dev/mapper/virt")) {
+ *maj = 254;
+ *min = 0;
+ return 0;
+ }
+
+ return real_virGetDeviceID(path, maj, min);
+}
+
+
+bool
+virFileExists(const char *path)
+{
+ init_syms();
+
+ if (STREQ(path, "/dev/mapper/virt"))
+ return true;
+
+ return real_virFileExists(path);
+}
+
+
+int
+qemuProcessStartManagedPRDaemon(virDomainObjPtr vm ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+
+void
+qemuProcessKillManagedPRDaemon(virDomainObjPtr vm ATTRIBUTE_UNUSED)
+{
+}
Index: libvirt-5.1.0/tests/qemuhotplugtest.c
===================================================================
--- libvirt-5.1.0.orig/tests/qemuhotplugtest.c
+++ libvirt-5.1.0/tests/qemuhotplugtest.c
@@ -78,6 +78,8 @@ qemuHotplugCreateObjects(virDomainXMLOpt
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_PLAIN);
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_DOORBELL);
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_SCSI_DISK_WWN);
+ virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_PR_MANAGER_HELPER);
+ virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_SCSI_BLOCK);
if (qemuTestCapsCacheInsert(driver.qemuCapsCache, priv->qemuCaps) < 0)
goto cleanup;
@@ -724,6 +726,17 @@ mymain(void)
"device_del", QMP_DEVICE_DELETED("scsi3-0-5-7") QMP_OK,
"human-monitor-command", HMP(""));
+ DO_TEST_ATTACH("base-live", "disk-scsi-multipath", false, true,
+ "object-add", QMP_OK,
+ "human-monitor-command", HMP("OK\\r\\n"),
+ "device_add", QMP_OK);
+ DO_TEST_DETACH("base-live", "disk-scsi-multipath", true, true,
+ "device_del", QMP_OK,
+ "human-monitor-command", HMP(""));
+ DO_TEST_DETACH("base-live", "disk-scsi-multipath", false, false,
+ "device_del", QMP_DEVICE_DELETED("scsi0-0-0-0") QMP_OK,
+ "human-monitor-command", HMP(""));
+
DO_TEST_ATTACH("base-live", "qemu-agent", false, true,
"chardev-add", QMP_OK,
"device_add", QMP_OK);
@@ -846,4 +859,4 @@ mymain(void)
return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
-VIR_TEST_MAIN(mymain)
+VIR_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/libqemuhotplugmock.so");
Index: libvirt-5.1.0/tests/qemuhotplugtestdevices/qemuhotplug-disk-scsi-multipath.xml
===================================================================
--- /dev/null
+++ libvirt-5.1.0/tests/qemuhotplugtestdevices/qemuhotplug-disk-scsi-multipath.xml
@@ -0,0 +1,8 @@
+<disk type='block' device='lun'>
+ <driver name='qemu' type='raw'/>
+ <source dev='/dev/mapper/virt'>
+ <reservations managed='yes'/>
+ </source>
+ <target dev='sda' bus='scsi'/>
+ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+</disk>
Index: libvirt-5.1.0/tests/qemuhotplugtestdomains/qemuhotplug-base-live+disk-scsi-multipath.xml
===================================================================
--- /dev/null
+++ libvirt-5.1.0/tests/qemuhotplugtestdomains/qemuhotplug-base-live+disk-scsi-multipath.xml
@@ -0,0 +1,62 @@
+<domain type='kvm' id='7'>
+ <name>hotplug</name>
+ <uuid>d091ea82-29e6-2e34-3005-f02617b36e87</uuid>
+ <memory unit='KiB'>4194304</memory>
+ <currentMemory unit='KiB'>4194304</currentMemory>
+ <vcpu placement='static'>4</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <pae/>
+ </features>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-x86_64</emulator>
+ <disk type='block' device='lun'>
+ <driver name='qemu' type='raw'/>
+ <source dev='/dev/mapper/virt'>
+ <reservations managed='yes'>
+ <source type='unix' path='/tmp/lib/domain-7-hotplug/pr-helper0.sock' mode='client'/>
+ </reservations>
+ </source>
+ <backingStore/>
+ <target dev='sda' bus='scsi'/>
+ <alias name='scsi0-0-0-0'/>
+ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+ </disk>
+ <controller type='usb' index='0'>
+ <alias name='usb'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='ide' index='0'>
+ <alias name='ide'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+ </controller>
+ <controller type='scsi' index='0' model='virtio-scsi'>
+ <alias name='scsi0'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'>
+ <alias name='pci'/>
+ </controller>
+ <controller type='virtio-serial' index='0'>
+ <alias name='virtio-serial0'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </controller>
+ <input type='mouse' bus='ps2'>
+ <alias name='input0'/>
+ </input>
+ <input type='keyboard' bus='ps2'>
+ <alias name='input1'/>
+ </input>
+ <memballoon model='none'/>
+ </devices>
+ <seclabel type='none' model='none'/>
+</domain>
Index: libvirt-5.1.0/tests/Makefile.am
===================================================================
--- libvirt-5.1.0.orig/tests/Makefile.am
+++ libvirt-5.1.0/tests/Makefile.am
@@ -221,6 +221,7 @@ test_libraries = libshunload.la \
virhostcpumock.la \
domaincapsmock.la \
virfilecachemock.la \
+ libqemuhotplugmock.la \
$(NULL)
if WITH_REMOTE
@@ -579,6 +580,11 @@ qemucpumock_la_SOURCES = \
qemucpumock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
qemucpumock_la_LIBADD = $(MOCKLIBS_LIBS)
+libqemuhotplugmock_la_SOURCES = \
+ qemuhotplugmock.c
+libqemuhotplugmock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
+libqemuhotplugmock_la_LIBADD = $(MOCKLIBS_LIBS)
+
qemuxml2argvtest_SOURCES = \
qemuxml2argvtest.c testutilsqemu.c testutilsqemu.h \
testutils.c testutils.h
@@ -657,7 +663,12 @@ qemuhotplugtest_SOURCES = \
testutils.c testutils.h \
testutilsqemu.c testutilsqemu.h \
$(NULL)
-qemuhotplugtest_LDADD = libqemumonitortestutils.la $(qemu_LDADDS) $(LDADDS)
+qemuhotplugtest_LDADD = \
+ libqemutestdriver.la \
+ libqemumonitortestutils.la \
+ $(qemu_LDADDS) \
+ $(LDADDS) \
+ $(NULL)
qemublocktest_SOURCES = \
qemublocktest.c \
@@ -711,6 +722,7 @@ EXTRA_DIST += qemuxml2argvtest.c qemuxml
qemumigparamstest.c \
qemusecuritytest.c qemusecuritytest.h \
qemusecuritymock.c \
+ qemuhotplugmock.c \
$(QEMUMONITORTESTUTILS_SOURCES)
endif ! WITH_QEMU