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(a)redhat.com>
---
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