diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7b93b42264575b1e008aa34742b010466bd9611f..5fea1bca41d9a58eb8002664be1c26995ddcd143 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 9b49f9c1e1632abf83489a4c2c7a40717dd6d435..bd714f7aee09010fd88517f9359d4f120c9fdc48 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 8c744138cef7b64647b32f81e01a1016d546893e..76678658c0f2736c224182828dfb941c584a1049 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 08f67a44b91c2b4f6a3cc8e5705485316d3e3cbe..81a9811d14d63873f23848dc5e13aa3aa75d4c25 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 31c9da673ca4f4d4bcb580b4370d27f974b2c448..da1fe679fed7021b32ebce1a99af462fc3a8df51 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 c14615fa7364447b5068f82c6dc251949cf6ec51..f43b8602ae3462ef3740859e81ad9b5db922b8d4 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 2dccec264b104aa7e8869222e094a63260678e3d..fbbbcf208fc92e4126c6878d63b78e455a4e4291 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 9dd5c97642dbdf692abb81aa792537a1a9c760e4..3bf66f71b74741d84560f37daff51b24eed65dc6 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 46ae1ba8fb51fa074dc07a9df4a2db914a6dd9da..87c34995614d825888f9e83c8f0d121c91bf0d53 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 7240a20fd60058ce8e1b4d1460b1c51f11688dd7..0bba016e4ebb7af3fecf27f55fe8fb85d26fe375 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 0000000000000000000000000000000000000000..dce3fc41053cc1496c47d73aefb12029ebda8bcb --- /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 ddf567b62238a0a5afaeaeeaf2e65c76d3f0a76d..8da2f17f4fa5e643b58cbe370794703161de3a21 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;