diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c index ce4056a7b3..b17577e987 100644 --- a/src/qemu/qemu_blockjob.c +++ b/src/qemu/qemu_blockjob.c @@ -78,6 +78,11 @@ qemuBlockJobDataDisposeJobdata(qemuBlockJobDataPtr job) { if (job->type == QEMU_BLOCKJOB_TYPE_CREATE) virObjectUnref(job->data.create.src); + + if (job->type == QEMU_BLOCKJOB_TYPE_BACKUP) { + virObjectUnref(job->data.backup.store); + g_free(job->data.backup.bitmap); + } } @@ -370,6 +375,34 @@ qemuBlockJobDiskNewCopy(virDomainObjPtr vm, } +qemuBlockJobDataPtr +qemuBlockJobDiskNewBackup(virDomainObjPtr vm, + virDomainDiskDefPtr disk, + virStorageSourcePtr store, + bool deleteStore, + const char *bitmap) +{ + g_autoptr(qemuBlockJobData) job = NULL; + g_autofree char *jobname = NULL; + + jobname = g_strdup_printf("backup-%s-%s", disk->dst, disk->src->nodeformat); + + if (!(job = qemuBlockJobDataNew(QEMU_BLOCKJOB_TYPE_BACKUP, jobname))) + return NULL; + + job->data.backup.bitmap = g_strdup(bitmap); + job->data.backup.store = virObjectRef(store); + job->data.backup.deleteStore = deleteStore; + + /* backup jobs are usually started in bulk by transaction so the caller + * shall save the status XML */ + if (qemuBlockJobRegister(job, vm, disk, false) < 0) + return NULL; + + return g_steal_pointer(&job); +} + + /** * qemuBlockJobDiskGetJob: * @disk: disk definition diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h index 4734984c99..52b03aaf9e 100644 --- a/src/qemu/qemu_blockjob.h +++ b/src/qemu/qemu_blockjob.h @@ -107,6 +107,16 @@ struct _qemuBlockJobCopyData { }; +typedef struct _qemuBlockJobBackupData qemuBlockJobBackupData; +typedef qemuBlockJobBackupData *qemuBlockJobDataBackupPtr; + +struct _qemuBlockJobBackupData { + virStorageSourcePtr store; + bool deleteStore; + char *bitmap; +}; + + typedef struct _qemuBlockJobData qemuBlockJobData; typedef qemuBlockJobData *qemuBlockJobDataPtr; @@ -124,6 +134,7 @@ struct _qemuBlockJobData { qemuBlockJobCommitData commit; qemuBlockJobCreateData create; qemuBlockJobCopyData copy; + qemuBlockJobBackupData backup; } data; int type; /* qemuBlockJobType */ @@ -184,6 +195,13 @@ qemuBlockJobDiskNewCopy(virDomainObjPtr vm, bool shallow, bool reuse); +qemuBlockJobDataPtr +qemuBlockJobDiskNewBackup(virDomainObjPtr vm, + virDomainDiskDefPtr disk, + virStorageSourcePtr store, + bool deleteStore, + const char *bitmap); + qemuBlockJobDataPtr qemuBlockJobDiskGetJob(virDomainDiskDefPtr disk) ATTRIBUTE_NONNULL(1); diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 1be6cfccff..873a397ac6 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2608,6 +2608,18 @@ qemuDomainObjPrivateXMLFormatBlockjobIterator(void *payload, break; case QEMU_BLOCKJOB_TYPE_BACKUP: + virBufferEscapeString(&childBuf, "\n", job->data.backup.bitmap); + if (job->data.backup.store) { + if (qemuDomainObjPrivateXMLFormatBlockjobFormatSource(&childBuf, + "store", + job->data.backup.store, + data->xmlopt, + false) < 0) + return -1; + + if (job->data.backup.deleteStore) + virBufferAddLit(&childBuf, "\n"); + } break; case QEMU_BLOCKJOB_TYPE_BROKEN: @@ -3202,6 +3214,15 @@ qemuDomainObjPrivateXMLParseBlockjobDataSpecific(qemuBlockJobDataPtr job, break; case QEMU_BLOCKJOB_TYPE_BACKUP: + job->data.backup.bitmap = virXPathString("string(./bitmap/@name)", ctxt); + + if (!(tmp = virXPathNode("./store", ctxt)) || + !(job->data.backup.store = qemuDomainObjPrivateXMLParseBlockjobChain(tmp, ctxt, xmlopt))) + goto broken; + + if (virXPathNode("./deleteStore", ctxt)) + job->data.backup.deleteStore = true; + break; case QEMU_BLOCKJOB_TYPE_BROKEN: