diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index 560488c8522ed02c3342ba3b17b534fb72f84ee9..0a6522577d5491d8afe4060b459e2ca343610b1c 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -1622,6 +1622,123 @@ qemuBlockStorageSourceDetachPrepare(virStorageSourcePtr src, } +void +qemuBlockStorageSourceChainDataFree(qemuBlockStorageSourceChainDataPtr data) +{ + size_t i; + + if (!data) + return; + + for (i = 0; i < data->nsrcdata; i++) + qemuBlockStorageSourceAttachDataFree(data->srcdata[i]); + + VIR_FREE(data->srcdata); + VIR_FREE(data); +} + + +/** + * qemuBlockStorageSourceChainDetachPrepareBlockdev + * @src: storage source chain to remove + * + * Prepares qemuBlockStorageSourceChainDataPtr for detaching @src and its + * backingStore if -blockdev was used. + */ +qemuBlockStorageSourceChainDataPtr +qemuBlockStorageSourceChainDetachPrepareBlockdev(virStorageSourcePtr src) +{ + VIR_AUTOPTR(qemuBlockStorageSourceAttachData) backend = NULL; + VIR_AUTOPTR(qemuBlockStorageSourceChainData) data = NULL; + virStorageSourcePtr n; + + if (VIR_ALLOC(data) < 0) + return NULL; + + for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) { + if (!(backend = qemuBlockStorageSourceDetachPrepare(n, NULL))) + return NULL; + + if (VIR_APPEND_ELEMENT(data->srcdata, data->nsrcdata, backend) < 0) + return NULL; + } + + VIR_RETURN_PTR(data); +} + + +/** + * qemuBlockStorageSourceChainDetachPrepareLegacy + * @src: storage source chain to remove + * @driveAlias: Alias of the 'drive' backend (always consumed) + * + * Prepares qemuBlockStorageSourceChainDataPtr for detaching @src and its + * backingStore if -drive was used. + */ +qemuBlockStorageSourceChainDataPtr +qemuBlockStorageSourceChainDetachPrepareDrive(virStorageSourcePtr src, + char *driveAlias) +{ + VIR_AUTOPTR(qemuBlockStorageSourceAttachData) backend = NULL; + VIR_AUTOPTR(qemuBlockStorageSourceChainData) data = NULL; + + if (VIR_ALLOC(data) < 0) + return NULL; + + if (!(backend = qemuBlockStorageSourceDetachPrepare(src, driveAlias))) + return NULL; + + if (VIR_APPEND_ELEMENT(data->srcdata, data->nsrcdata, backend) < 0) + return NULL; + + VIR_RETURN_PTR(data); +} + + +/** + * qemuBlockStorageSourceChainAttach: + * @mon: monitor object + * @data: storage source chain data + * + * Attach a storage source including its backing chain and supporting objects. + * Caller must enter @mon prior calling this function. In case of error this + * function returns -1. @data is updated so that qemuBlockStorageSourceChainDetach + * can be used to roll-back the changes. + */ +int +qemuBlockStorageSourceChainAttach(qemuMonitorPtr mon, + qemuBlockStorageSourceChainDataPtr data) +{ + size_t i; + + for (i = data->nsrcdata; i > 0; i--) { + if (qemuBlockStorageSourceAttachApply(mon, data->srcdata[i - 1]) < 0) + return -1; + } + + return 0; +} + + +/** + * qemuBlockStorageSourceChainDetach: + * @mon: monitor object + * @data: storage source chain data + * + * Detach a unused storage source including all its backing chain and related + * objects described by @data. + */ +void +qemuBlockStorageSourceChainDetach(qemuMonitorPtr mon, + qemuBlockStorageSourceChainDataPtr data) +{ + size_t i; + + for (i = 0; i < data->nsrcdata; i++) + qemuBlockStorageSourceAttachRollback(mon, data->srcdata[i]); +} + + /** * qemuBlockStorageSourceDetachOneBlockdev: * @driver: qemu driver object diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h index a49c73670b36657a6925accbff5801e789478685..934a1f125d770cb3e9408419bf5d2f1b5dcd59b3 100644 --- a/src/qemu/qemu_block.h +++ b/src/qemu/qemu_block.h @@ -125,6 +125,35 @@ qemuBlockStorageSourceDetachOneBlockdev(virQEMUDriverPtr driver, qemuDomainAsyncJob asyncJob, virStorageSourcePtr src); +struct _qemuBlockStorageSourceChainData { + qemuBlockStorageSourceAttachDataPtr *srcdata; + size_t nsrcdata; +}; + +typedef struct _qemuBlockStorageSourceChainData qemuBlockStorageSourceChainData; +typedef qemuBlockStorageSourceChainData *qemuBlockStorageSourceChainDataPtr; + +void +qemuBlockStorageSourceChainDataFree(qemuBlockStorageSourceChainDataPtr data); + +qemuBlockStorageSourceChainDataPtr +qemuBlockStorageSourceChainDetachPrepareBlockdev(virStorageSourcePtr src); +qemuBlockStorageSourceChainDataPtr +qemuBlockStorageSourceChainDetachPrepareDrive(virStorageSourcePtr src, + char *driveAlias); + +int +qemuBlockStorageSourceChainAttach(qemuMonitorPtr mon, + qemuBlockStorageSourceChainDataPtr data); + +void +qemuBlockStorageSourceChainDetach(qemuMonitorPtr mon, + qemuBlockStorageSourceChainDataPtr data); + + +VIR_DEFINE_AUTOPTR_FUNC(qemuBlockStorageSourceChainData, + qemuBlockStorageSourceChainDataFree); + int qemuBlockSnapshotAddLegacy(virJSONValuePtr actions, virDomainDiskDefPtr disk, diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index b767a1e15fc2a94a3fbd77097a0640d9ced20212..8b2832e011d56e935b2ffbd4cbbfcc4997c245f6 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -11184,3 +11184,66 @@ qemuBuildStorageSourceAttachPrepareCommon(virStorageSourcePtr src, return 0; } + + +/** + * qemuBuildStorageSourceChainAttachPrepareDrive: + * @disk: disk definition + * @qemuCaps: qemu capabilities object + * + * Prepares qemuBlockStorageSourceChainDataPtr for attaching @disk via -drive. + */ +qemuBlockStorageSourceChainDataPtr +qemuBuildStorageSourceChainAttachPrepareDrive(virDomainDiskDefPtr disk, + virQEMUCapsPtr qemuCaps) +{ + VIR_AUTOPTR(qemuBlockStorageSourceAttachData) elem = NULL; + VIR_AUTOPTR(qemuBlockStorageSourceChainData) data = NULL; + + if (VIR_ALLOC(data) < 0) + return NULL; + + if (!(elem = qemuBuildStorageSourceAttachPrepareDrive(disk, qemuCaps))) + return NULL; + + if (qemuBuildStorageSourceAttachPrepareCommon(disk->src, elem, qemuCaps) < 0) + return NULL; + + if (VIR_APPEND_ELEMENT(data->srcdata, data->nsrcdata, elem) < 0) + return NULL; + + VIR_RETURN_PTR(data); +} + + +/** + * qemuBuildStorageSourceChainAttachPrepareDrive: + * @top: storage source chain + * @qemuCaps: qemu capabilities object + * + * Prepares qemuBlockStorageSourceChainDataPtr for attaching @top via -blockdev. + */ +qemuBlockStorageSourceChainDataPtr +qemuBuildStorageSourceChainAttachPrepareBlockdev(virStorageSourcePtr top, + virQEMUCapsPtr qemuCaps) +{ + VIR_AUTOPTR(qemuBlockStorageSourceAttachData) elem = NULL; + VIR_AUTOPTR(qemuBlockStorageSourceChainData) data = NULL; + virStorageSourcePtr n; + + if (VIR_ALLOC(data) < 0) + return NULL; + + for (n = top; virStorageSourceIsBacking(n); n = n->backingStore) { + if (!(elem = qemuBlockStorageSourceAttachPrepareBlockdev(n))) + return NULL; + + if (qemuBuildStorageSourceAttachPrepareCommon(n, elem, qemuCaps) < 0) + return NULL; + + if (VIR_APPEND_ELEMENT(data->srcdata, data->nsrcdata, elem) < 0) + return NULL; + } + + VIR_RETURN_PTR(data); +} diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index c885d615785a1b2ab94f3137ae0757cc385ace24..8695832c16b6196f67dd2518e2feee12211e5e5e 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -107,6 +107,17 @@ qemuBuildStorageSourceAttachPrepareCommon(virStorageSourcePtr src, qemuBlockStorageSourceAttachDataPtr data, virQEMUCapsPtr qemuCaps); + +qemuBlockStorageSourceChainDataPtr +qemuBuildStorageSourceChainAttachPrepareDrive(virDomainDiskDefPtr disk, + virQEMUCapsPtr qemuCaps); + + +qemuBlockStorageSourceChainDataPtr +qemuBuildStorageSourceChainAttachPrepareBlockdev(virStorageSourcePtr top, + virQEMUCapsPtr qemuCaps); + + char *qemuBuildDiskDeviceStr(const virDomainDef *def, virDomainDiskDefPtr disk,