提交 a30078cb 编写于 作者: M Michal Privoznik

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#c61Signed-off-by: NMichal Privoznik <mprivozn@redhat.com>
Tested-by: NLin Ma <LMa@suse.com>
Reviewed-by: NJim Fehlig <jfehlig@suse.com>
上级 a18f2c52
......@@ -62,6 +62,7 @@
#include "virdomaincheckpointobjlist.h"
#include "backup_conf.h"
#include "virutil.h"
#include "virdevmapper.h"
#ifdef __linux__
# include <sys/sysmacros.h>
......@@ -14623,6 +14624,9 @@ qemuDomainSetupDisk(virQEMUDriverConfigPtr cfg G_GNUC_UNUSED,
bool hasNVMe = false;
for (next = disk->src; virStorageSourceIsBacking(next); next = next->backingStore) {
VIR_AUTOSTRINGLIST targetPaths = NULL;
size_t i;
if (next->type == VIR_STORAGE_TYPE_NVME) {
g_autofree char *nvmePath = NULL;
......@@ -14641,6 +14645,19 @@ qemuDomainSetupDisk(virQEMUDriverConfigPtr cfg G_GNUC_UNUSED,
if (qemuDomainCreateDevice(next->path, data, false) < 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;
}
for (i = 0; targetPaths && targetPaths[i]; i++) {
if (qemuDomainCreateDevice(targetPaths[i], data, false) < 0)
return -1;
}
}
}
......@@ -15656,21 +15673,19 @@ qemuDomainNamespaceSetupDisk(virDomainObjPtr vm,
virStorageSourcePtr src)
{
virStorageSourcePtr next;
char **paths = NULL;
VIR_AUTOSTRINGLIST paths = NULL;
size_t npaths = 0;
bool hasNVMe = false;
g_autofree char *dmPath = NULL;
g_autofree char *vfioPath = NULL;
int ret = -1;
for (next = src; virStorageSourceIsBacking(next); next = next->backingStore) {
VIR_AUTOSTRINGLIST targetPaths = NULL;
g_autofree char *tmpPath = NULL;
if (next->type == VIR_STORAGE_TYPE_NVME) {
hasNVMe = true;
if (!(tmpPath = virPCIDeviceAddressGetIOMMUGroupDev(&next->nvme->pciAddr)))
goto cleanup;
return -1;
} else {
if (virStorageSourceIsEmpty(next) ||
!virStorageSourceIsLocalStorage(next)) {
......@@ -15681,30 +15696,35 @@ qemuDomainNamespaceSetupDisk(virDomainObjPtr vm,
tmpPath = g_strdup(next->path);
}
if (VIR_APPEND_ELEMENT(paths, npaths, tmpPath) < 0)
goto cleanup;
if (virStringListAdd(&paths, tmpPath) < 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) {
dmPath = g_strdup(QEMU_DEVICE_MAPPER_CONTROL_PATH);
if (VIR_APPEND_ELEMENT_COPY(paths, npaths, dmPath) < 0)
goto cleanup;
}
if (src->pr &&
virStringListAdd(&paths, QEMU_DEVICE_MAPPER_CONTROL_PATH) < 0)
return -1;
if (hasNVMe) {
vfioPath = g_strdup(QEMU_DEV_VFIO);
if (VIR_APPEND_ELEMENT(paths, npaths, vfioPath) < 0)
goto cleanup;
}
if (hasNVMe &&
virStringListAdd(&paths, QEMU_DEV_VFIO) < 0)
return -1;
npaths = virStringListLength((const char **) paths);
if (qemuDomainNamespaceMknodPaths(vm, (const char **) paths, npaths) < 0)
goto cleanup;
return -1;
ret = 0;
cleanup:
virStringListFreeCount(paths, npaths);
return ret;
return 0;
}
......
......@@ -20,6 +20,8 @@
#pragma once
#include "internal.h"
int
virDevMapperGetTargets(const char *path,
char ***devPaths);
char ***devPaths) G_GNUC_NO_INLINE;
......@@ -120,7 +120,7 @@ bool virValidateWWN(const char *wwn);
int virGetDeviceID(const char *path,
int *maj,
int *min);
int *min) G_GNUC_NO_INLINE;
int virSetDeviceUnprivSGIO(const char *path,
const char *sysfs_dir,
int unpriv_sgio);
......
......@@ -19,7 +19,24 @@
#include <config.h>
#include "qemu/qemu_hotplug.h"
#include "qemu/qemu_process.h"
#include "conf/domain_conf.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);
}
unsigned long long
qemuDomainGetUnplugTimeout(virDomainObjPtr vm G_GNUC_UNUSED)
......@@ -31,3 +48,61 @@ qemuDomainGetUnplugTimeout(virDomainObjPtr vm G_GNUC_UNUSED)
return 200;
return 100;
}
int
virDevMapperGetTargets(const char *path,
char ***devPaths)
{
*devPaths = NULL;
if (STREQ(path, "/dev/mapper/virt")) {
*devPaths = g_new(char *, 4);
(*devPaths)[0] = g_strdup("/dev/block/8:0"); /* /dev/sda */
(*devPaths)[1] = g_strdup("/dev/block/8:16"); /* /dev/sdb */
(*devPaths)[2] = g_strdup("/dev/block/8:32"); /* /dev/sdc */
(*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 G_GNUC_UNUSED)
{
return 0;
}
void
qemuProcessKillManagedPRDaemon(virDomainObjPtr vm G_GNUC_UNUSED)
{
}
......@@ -87,6 +87,8 @@ qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt,
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_VNC);
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_SPICE);
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_SPICE_FILE_XFER_DISABLE);
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_PR_MANAGER_HELPER);
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_SCSI_BLOCK);
if (qemuTestCapsCacheInsert(driver.qemuCapsCache, priv->qemuCaps) < 0)
return -1;
......@@ -750,6 +752,17 @@ mymain(void)
"device_del", QMP_DEVICE_DELETED("scsi3-0-5-6") 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);
......
<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>
<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>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册