This is a helper blockjob which uses the 'block-dirty-bitmap-populate' command to convert the allocation map of a qcow2 image into a dirty bitmap. Internally it's a blockjob so we need to treat it as such. We only care about the results when there's a sync thread waiting for it, otherwise we clean up the created bitmap. Signed-off-by: Peter Krempa <pkrempa@xxxxxxxxxx> --- src/qemu/qemu_blockjob.c | 69 ++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_blockjob.h | 13 ++++++++ src/qemu/qemu_domain.c | 13 ++++++++ src/qemu/qemu_driver.c | 1 + 4 files changed, 96 insertions(+) diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c index 17dc08476b..79820c6ca8 100644 --- a/src/qemu/qemu_blockjob.c +++ b/src/qemu/qemu_blockjob.c @@ -69,6 +69,7 @@ VIR_ENUM_IMPL(qemuBlockjob, "backup", "", "create", + "populate", "broken"); static virClassPtr qemuBlockJobDataClass; @@ -356,6 +357,38 @@ qemuBlockJobNewCreate(virDomainObjPtr vm, } +/** + * qemuBlockJobNewPopulate: + * @vm: domain object + * @src: storage source the populate job is running on + * + * Instantiate block job data for running a 'dirty-bitmap-populate' blockjob. + * Note that this job is expected to run as part of a single 'modify' qemu + * domain job as this job is not registered with the disk itself and @src must + * be valid for the whole time the job is running. + */ +qemuBlockJobDataPtr +qemuBlockJobNewPopulate(virDomainObjPtr vm, + virStorageSourcePtr src) +{ + g_autoptr(qemuBlockJobData) job = NULL; + g_autofree char *jobname = NULL; + const char *nodename = src->nodeformat; + + jobname = g_strdup_printf("bitmap-populate-%s", nodename); + + if (!(job = qemuBlockJobDataNew(QEMU_BLOCKJOB_TYPE_POPULATE, jobname))) + return NULL; + + job->data.populate.src = src; + + if (qemuBlockJobRegister(job, vm, NULL, true) < 0) + return NULL; + + return g_steal_pointer(&job); +} + + qemuBlockJobDataPtr qemuBlockJobDiskNewCopy(virDomainObjPtr vm, virDomainDiskDefPtr disk, @@ -1478,6 +1511,38 @@ qemuBlockJobProcessEventConcludedBackup(virQEMUDriverPtr driver, } +static void +qemuBlockJobProcessEventConcludedPopulate(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuBlockJobDataPtr job, + qemuDomainAsyncJob asyncJob) +{ + g_autoptr(virJSONValue) actions = NULL; + + /* On successful completion there must be a synchronous handler waiting for + * this job. If there isn't one we need to clean up the associated bitmap. + */ + if (job->newstate == QEMU_BLOCKJOB_STATE_COMPLETED && + job->synchronous) + return; + + if (qemuMonitorTransactionBitmapRemove(actions, + job->data.populate.src->nodeformat, + "libvirt-tmp-bitmap") < 0) + return; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) + return; + + qemuMonitorTransaction(qemuDomainGetMonitor(vm), &actions); + + if (qemuDomainObjExitMonitor(driver, vm) < 0) + return; + + return; +} + + static void qemuBlockJobEventProcessConcludedTransition(qemuBlockJobDataPtr job, virQEMUDriverPtr driver, @@ -1527,6 +1592,10 @@ qemuBlockJobEventProcessConcludedTransition(qemuBlockJobDataPtr job, progressTotal); break; + case QEMU_BLOCKJOB_TYPE_POPULATE: + qemuBlockJobProcessEventConcludedPopulate(driver, vm, job, asyncJob); + break; + case QEMU_BLOCKJOB_TYPE_BROKEN: case QEMU_BLOCKJOB_TYPE_NONE: case QEMU_BLOCKJOB_TYPE_INTERNAL: diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h index 19498b5bd8..0b9da7dd5b 100644 --- a/src/qemu/qemu_blockjob.h +++ b/src/qemu/qemu_blockjob.h @@ -64,6 +64,7 @@ typedef enum { /* Additional enum values local to qemu */ QEMU_BLOCKJOB_TYPE_INTERNAL, QEMU_BLOCKJOB_TYPE_CREATE, + QEMU_BLOCKJOB_TYPE_POPULATE, QEMU_BLOCKJOB_TYPE_BROKEN, QEMU_BLOCKJOB_TYPE_LAST } qemuBlockJobType; @@ -119,6 +120,13 @@ struct _qemuBlockJobBackupData { }; +typedef struct _qemuBlockJobBitmapPopulateData qemuBlockJobBitmapPopulateData; +typedef qemuBlockJobBitmapPopulateData *qemuBlockJobDataBitmapPopulatePtr; + +struct _qemuBlockJobBitmapPopulateData { + virStorageSourcePtr src; +}; + typedef struct _qemuBlockJobData qemuBlockJobData; typedef qemuBlockJobData *qemuBlockJobDataPtr; @@ -140,6 +148,7 @@ struct _qemuBlockJobData { qemuBlockJobCreateData create; qemuBlockJobCopyData copy; qemuBlockJobBackupData backup; + qemuBlockJobBitmapPopulateData populate; } data; int type; /* qemuBlockJobType */ @@ -197,6 +206,10 @@ qemuBlockJobNewCreate(virDomainObjPtr vm, virStorageSourcePtr chain, bool storage); +qemuBlockJobDataPtr +qemuBlockJobNewPopulate(virDomainObjPtr vm, + virStorageSourcePtr src); + qemuBlockJobDataPtr qemuBlockJobDiskNewCopy(virDomainObjPtr vm, virDomainDiskDefPtr disk, diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 0cd9cf8582..80d1d14e4f 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2737,6 +2737,12 @@ qemuDomainObjPrivateXMLFormatBlockjobIterator(void *payload, } break; + case QEMU_BLOCKJOB_TYPE_POPULATE: + if (job->data.populate.src) + virBufferAsprintf(&childBuf, "<src node='%s'/>\n", job->data.populate.src->nodeformat); + + break; + case QEMU_BLOCKJOB_TYPE_BROKEN: case QEMU_BLOCKJOB_TYPE_NONE: case QEMU_BLOCKJOB_TYPE_INTERNAL: @@ -3364,6 +3370,13 @@ qemuDomainObjPrivateXMLParseBlockjobDataSpecific(qemuBlockJobDataPtr job, goto broken; break; + case QEMU_BLOCKJOB_TYPE_POPULATE: + qemuDomainObjPrivateXMLParseBlockjobNodename(job, + "string(./src/@node)", + &job->data.populate.src, + ctxt); + break; + case QEMU_BLOCKJOB_TYPE_BROKEN: case QEMU_BLOCKJOB_TYPE_NONE: case QEMU_BLOCKJOB_TYPE_INTERNAL: diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 5a3b3bb35b..febe417faf 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -17263,6 +17263,7 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver, case QEMU_BLOCKJOB_TYPE_BACKUP: case QEMU_BLOCKJOB_TYPE_INTERNAL: case QEMU_BLOCKJOB_TYPE_CREATE: + case QEMU_BLOCKJOB_TYPE_POPULATE: case QEMU_BLOCKJOB_TYPE_BROKEN: virReportError(VIR_ERR_OPERATION_INVALID, _("job type '%s' does not support pivot"), -- 2.26.2