From 13fe558fb4c4ecf75bd667297c7b42d09f9272a2 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Wed, 18 Apr 2018 16:55:14 +0200 Subject: [PATCH] qemu: Generate pr cmd line at startup For command line we need two things: 1) -object pr-manager-helper,id=$alias,path=$socketPath 2) -drive file.pr-manager=$alias In -object pr-manager-helper we tell qemu which socket to connect to, then in -drive file-pr-manager we just reference the object the drive in question should use. For managed PR helper the alias is always "pr-helper0" and socket path "${vm->priv->libDir}/pr-helper0.sock". Signed-off-by: Michal Privoznik Reviewed-by: John Ferlan --- src/libvirt_private.syms | 2 + src/qemu/qemu_alias.c | 18 +++ src/qemu/qemu_alias.h | 4 + src/qemu/qemu_command.c | 134 ++++++++++++++++++ src/qemu/qemu_command.h | 5 + src/qemu/qemu_domain.c | 22 +++ src/qemu/qemu_domain.h | 3 + src/qemu/qemu_process.h | 1 + src/util/virstoragefile.c | 14 ++ src/util/virstoragefile.h | 2 + .../disk-virtio-scsi-reservations.args | 38 +++++ tests/qemuxml2argvtest.c | 4 + 12 files changed, 247 insertions(+) create mode 100644 tests/qemuxml2argvdata/disk-virtio-scsi-reservations.args diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7b93b42264..5fea1bca41 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2803,7 +2803,9 @@ virStorageNetHostTransportTypeToString; virStorageNetProtocolTypeToString; virStoragePRDefFormat; virStoragePRDefFree; +virStoragePRDefIsEnabled; virStoragePRDefIsEqual; +virStoragePRDefIsManaged; virStoragePRDefParseXML; virStorageSourceBackingStoreClear; virStorageSourceClear; diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c index 9b49f9c1e1..bd714f7aee 100644 --- a/src/qemu/qemu_alias.c +++ b/src/qemu/qemu_alias.c @@ -773,3 +773,21 @@ qemuAliasChardevFromDevAlias(const char *devAlias) return ret; } + + +const char * +qemuDomainGetManagedPRAlias(void) +{ + return "pr-helper0"; +} + + +char * +qemuDomainGetUnmanagedPRAlias(const virDomainDiskDef *disk) +{ + char *ret; + + ignore_value(virAsprintf(&ret, "pr-helper-%s", disk->info.alias)); + + return ret; +} diff --git a/src/qemu/qemu_alias.h b/src/qemu/qemu_alias.h index 8c744138ce..76678658c0 100644 --- a/src/qemu/qemu_alias.h +++ b/src/qemu/qemu_alias.h @@ -92,4 +92,8 @@ char *qemuAliasTLSObjFromSrcAlias(const char *srcAlias) char *qemuAliasChardevFromDevAlias(const char *devAlias) ATTRIBUTE_NONNULL(1); +const char *qemuDomainGetManagedPRAlias(void); + +char *qemuDomainGetUnmanagedPRAlias(const virDomainDiskDef *disk); + #endif /* __QEMU_ALIAS_H__*/ diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 08f67a44b9..81a9811d14 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1470,6 +1470,28 @@ qemuDiskSourceGetProps(virStorageSourcePtr src) } +static int +qemuBuildDriveSourcePR(virBufferPtr buf, + virDomainDiskDefPtr disk) +{ + char *alias = NULL; + const char *defaultAlias = NULL; + + if (!virStoragePRDefIsEnabled(disk->src->pr)) + return 0; + + if (virStoragePRDefIsManaged(disk->src->pr)) + defaultAlias = qemuDomainGetManagedPRAlias(); + else if (!(alias = qemuDomainGetUnmanagedPRAlias(disk))) + return -1; + + + virBufferAsprintf(buf, ",file.pr-manager=%s", alias ? alias : defaultAlias); + VIR_FREE(alias); + return 0; +} + + static int qemuBuildDriveSourceStr(virDomainDiskDefPtr disk, virQEMUCapsPtr qemuCaps, @@ -1533,6 +1555,9 @@ qemuBuildDriveSourceStr(virDomainDiskDefPtr disk, if (disk->src->debug) virBufferAsprintf(buf, ",file.debug=%d", disk->src->debugLevel); + + if (qemuBuildDriveSourcePR(buf, disk) < 0) + goto cleanup; } else { if (!(source = virQEMUBuildDriveCommandlineFromJSON(srcprops))) goto cleanup; @@ -9619,6 +9644,112 @@ qemuBuildPanicCommandLine(virCommandPtr cmd, } +/** + * qemuBuildPRManagerInfoProps: + * @prd: disk PR runtime info + * @propsret: JSON properties to return + * + * Build the JSON properties for the pr-manager object. + * + * Returns: 0 on success (@propsret is NULL if no properties are needed), + * -1 on failure (with error message set). + */ +int +qemuBuildPRManagerInfoProps(virDomainObjPtr vm, + const virDomainDiskDef *disk, + virJSONValuePtr *propsret, + char **aliasret) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + char *socketPath = NULL; + char *alias = NULL; + int ret = -1; + + *propsret = NULL; + *aliasret = NULL; + + if (!virStoragePRDefIsEnabled(disk->src->pr)) + return 0; + + if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_PR_MANAGER_HELPER)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("reservations not supported with this QEMU binary")); + return ret; + } + + if (!(socketPath = qemuDomainGetPRSocketPath(vm, disk->src->pr))) + return ret; + + if (virStoragePRDefIsManaged(disk->src->pr)) { + if (VIR_STRDUP(alias, qemuDomainGetManagedPRAlias()) < 0) + goto cleanup; + } else { + if (!(alias = qemuDomainGetUnmanagedPRAlias(disk))) + goto cleanup; + } + + if (virJSONValueObjectCreate(propsret, + "s:path", socketPath, + NULL) < 0) + goto cleanup; + + VIR_STEAL_PTR(*aliasret, alias); + ret = 0; + cleanup: + VIR_FREE(alias); + VIR_FREE(socketPath); + return ret; +} + + +static int +qemuBuildMasterPRCommandLine(virDomainObjPtr vm, + virCommandPtr cmd, + const virDomainDef *def) +{ + size_t i; + bool managedAdded = false; + virJSONValuePtr props = NULL; + char *alias = NULL; + char *tmp = NULL; + int ret = -1; + + for (i = 0; i < def->ndisks; i++) { + const virDomainDiskDef *disk = def->disks[i]; + + if (virStoragePRDefIsManaged(disk->src->pr)) { + if (managedAdded) + continue; + + managedAdded = true; + } + + if (qemuBuildPRManagerInfoProps(vm, disk, &props, &alias) < 0) + goto cleanup; + + if (!props) + continue; + + if (!(tmp = virQEMUBuildObjectCommandlineFromJSON("pr-manager-helper", + alias, + props))) + goto cleanup; + VIR_FREE(alias); + virJSONValueFree(props); + props = NULL; + + virCommandAddArgList(cmd, "-object", tmp, NULL); + VIR_FREE(tmp); + } + + ret = 0; + cleanup: + VIR_FREE(alias); + virJSONValueFree(props); + return ret; +} + + /** * qemuBuildCommandLineValidate: * @@ -9787,6 +9918,9 @@ qemuBuildCommandLine(virQEMUDriverPtr driver, if (qemuBuildMasterKeyCommandLine(cmd, priv) < 0) goto error; + if (qemuBuildMasterPRCommandLine(vm, cmd, def) < 0) + goto error; + if (enableFips) virCommandAddArg(cmd, "-enable-fips"); diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 31c9da673c..da1fe679fe 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -54,6 +54,11 @@ virCommandPtr qemuBuildCommandLine(virQEMUDriverPtr driver, size_t *nnicindexes, int **nicindexes); +/* Generate the object properties for pr-manager */ +int qemuBuildPRManagerInfoProps(virDomainObjPtr vm, + const virDomainDiskDef *disk, + virJSONValuePtr *propsret, + char **alias); /* Generate the object properties for a secret */ int qemuBuildSecretInfoProps(qemuDomainSecretInfoPtr secinfo, diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index c14615fa73..f43b8602ae 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -12001,3 +12001,25 @@ qemuProcessEventFree(struct qemuProcessEvent *event) } VIR_FREE(event); } + + +char * +qemuDomainGetPRSocketPath(virDomainObjPtr vm, + virStoragePRDefPtr pr) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + const char *defaultAlias = NULL; + char *ret = NULL; + + if (!virStoragePRDefIsEnabled(pr)) + return NULL; + + if (virStoragePRDefIsManaged(pr)) { + defaultAlias = qemuDomainGetManagedPRAlias(); + ignore_value(virAsprintf(&ret, "%s/%s.sock", priv->libDir, defaultAlias)); + } else { + ignore_value(VIR_STRDUP(ret, pr->path)); + } + + return ret; +} diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 2dccec264b..fbbbcf208f 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -1003,4 +1003,7 @@ qemuDomainDiskCachemodeFlags(int cachemode, bool *direct, bool *noflush); +char * qemuDomainGetPRSocketPath(virDomainObjPtr vm, + virStoragePRDefPtr pr); + #endif /* __QEMU_DOMAIN_H__ */ diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 9dd5c97642..3bf66f71b7 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -24,6 +24,7 @@ # include "qemu_conf.h" # include "qemu_domain.h" +# include "virstoragefile.h" int qemuProcessPrepareMonitorChr(virDomainChrSourceDefPtr monConfig, const char *domainDir); diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 46ae1ba8fb..87c3499561 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -2041,6 +2041,20 @@ virStoragePRDefIsEqual(virStoragePRDefPtr a, } +bool +virStoragePRDefIsEnabled(virStoragePRDefPtr prd) +{ + return prd && prd->enabled == VIR_TRISTATE_BOOL_YES; +} + + +bool +virStoragePRDefIsManaged(virStoragePRDefPtr prd) +{ + return prd && prd->managed == VIR_TRISTATE_BOOL_YES; +} + + virSecurityDeviceLabelDefPtr virStorageSourceGetSecurityLabelDef(virStorageSourcePtr src, const char *model) diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 7240a20fd6..0bba016e4e 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -397,6 +397,8 @@ void virStoragePRDefFormat(virBufferPtr buf, virStoragePRDefPtr prd); bool virStoragePRDefIsEqual(virStoragePRDefPtr a, virStoragePRDefPtr b); +bool virStoragePRDefIsEnabled(virStoragePRDefPtr prd); +bool virStoragePRDefIsManaged(virStoragePRDefPtr prd); virSecurityDeviceLabelDefPtr virStorageSourceGetSecurityLabelDef(virStorageSourcePtr src, diff --git a/tests/qemuxml2argvdata/disk-virtio-scsi-reservations.args b/tests/qemuxml2argvdata/disk-virtio-scsi-reservations.args new file mode 100644 index 0000000000..dce3fc4105 --- /dev/null +++ b/tests/qemuxml2argvdata/disk-virtio-scsi-reservations.args @@ -0,0 +1,38 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-i686 \ +-name QEMUGuest1 \ +-S \ +-object pr-manager-helper,id=pr-helper0,\ +path=/tmp/lib/domain--1-QEMUGuest1/pr-helper0.sock \ +-object pr-manager-helper,id=pr-helper-scsi0-0-0-1,\ +path=/path/to/qemu-pr-helper.sock \ +-machine pc,accel=tcg,usb=off,dump-guest-core=off \ +-m 214 \ +-smp 8,sockets=8,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot c \ +-device virtio-scsi-pci,id=scsi0,num_queues=8,bus=pci.0,addr=0x3 \ +-usb \ +-drive file=/dev/HostVG/QEMUGuest1,file.pr-manager=pr-helper0,format=raw,\ +if=none,id=drive-scsi0-0-0-0,boot=on \ +-device scsi-block,bus=scsi0.0,channel=0,scsi-id=0,lun=0,\ +drive=drive-scsi0-0-0-0,id=scsi0-0-0-0 \ +-drive file=/dev/HostVG/QEMUGuest2,file.pr-manager=pr-helper-scsi0-0-0-1,\ +format=raw,if=none,id=drive-scsi0-0-0-1 \ +-device scsi-block,bus=scsi0.0,channel=0,scsi-id=0,lun=1,\ +drive=drive-scsi0-0-0-1,id=scsi0-0-0-1 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index ddf567b622..8da2f17f4f 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -2801,6 +2801,10 @@ mymain(void) QEMU_CAPS_PIIX_DISABLE_S3, QEMU_CAPS_PIIX_DISABLE_S4, QEMU_CAPS_ICH9_USB_EHCI1); + DO_TEST("disk-virtio-scsi-reservations", + QEMU_CAPS_DRIVE_BOOT, QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_SCSI_BLOCK, QEMU_CAPS_PR_MANAGER_HELPER); + /* Test disks with format probing enabled for legacy reasons. * New tests should not go in this section. */ driver.config->allowDiskFormatProbing = true; -- GitLab