Minimal patch to wire up all the pieces in the previous patches
to actually enable a block copy job. By minimal, I mean that
qemu creates the file (that is, no REUSE_EXT flag support yet),
SELinux must be disabled, a lock manager is not informed, and
the audit logs aren't updated. But those will be added as
improvements in future patches.
* src/qemu/qemu_driver.c (qemuDomainBlockCopy): New function.
(qemuDomainBlockRebase): Call it when appropriate.
---
was 12/18 in v4
v5: address review comments, add comment in code
src/qemu/qemu_driver.c | 122 +++-
1 files changed, 120 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 8b6c984..5c3cea8 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -11910,10 +11910,126 @@ qemuDomainBlockJobSetSpeed(virDomainPtr dom, const
char *path,
}
static int
+qemuDomainBlockCopy(virDomainPtr dom, const char *path,
+const char *dest, const char *format,
+unsigned long bandwidth, unsigned int flags)
+{
+struct qemud_driver *driver = dom-conn-privateData;
+virDomainObjPtr vm = NULL;
+qemuDomainObjPrivatePtr priv;
+char uuidstr[VIR_UUID_STRING_BUFLEN];
+char *device = NULL;
+virDomainDiskDefPtr disk;
+int ret = -1;
+int idx;
+
+/* Preliminaries: find the disk we are editing, sanity checks */
+virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW, -1);
+
+qemuDriverLock(driver);
+virUUIDFormat(dom-uuid, uuidstr);
+vm = virDomainFindByUUID(driver-domains, dom-uuid);
+if (!vm) {
+qemuReportError(VIR_ERR_NO_DOMAIN,
+_(no domain with matching uuid '%s'), uuidstr);
+goto cleanup;
+}
+
+device = qemuDiskPathToAlias(vm, path, idx);
+if (!device) {
+goto cleanup;
+}
+disk = vm-def-disks[idx];
+if (disk-mirror) {
+qemuReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
+_(disk '%s' already in active block copy job),
+disk-dst);
+goto cleanup;
+}
+
+priv = vm-privateData;
+if (!(qemuCapsGet(priv-qemuCaps, QEMU_CAPS_DRIVE_MIRROR)
+ qemuCapsGet(priv-qemuCaps, QEMU_CAPS_DRIVE_REOPEN)
+ qemuCapsGet(priv-qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC))) {
+qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, %s,
+_(block copy is not supported with this QEMU
binary));
+goto cleanup;
+}
+if (vm-persistent) {
+/* XXX if qemu ever lets us start a new domain with mirroring
+ * already active, we can relax this; but for now, the risk of
+ * 'managedsave' due to libvirt-guests means we can't risk
+ * this on persistent domains. */
+qemuReportError(VIR_ERR_OPERATION_INVALID, %s,
+_(domain is not transient));
+goto cleanup;
+}
+
+if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) 0)
+goto cleanup;
+
+if (!virDomainObjIsActive(vm)) {
+qemuReportError(VIR_ERR_OPERATION_INVALID, %s,
+_(domain is not running));
+goto endjob;
+}
+
+/* Prepare the destination file. */
+/* XXX We also need to add security labeling, lock manager lease,
+ * and auditing of those events, as well as to support reuse of
+ * existing images, including probing the existing format of an
+ * existing image. */
+if (!format)
+format = disk-driverType;
+if ((format !(disk-mirrorFormat = strdup(format))) ||
+!(disk-mirror = strdup(dest))) {
+virReportOOMError();
+goto endjob;
+}
+
+/* Actually start the mirroring */
+qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ret = qemuMonitorDriveMirror(priv-mon, device, dest, format, flags);
+if (ret == 0 bandwidth != 0)
+ret = qemuMonitorBlockJob(priv-mon, device, NULL, bandwidth, NULL,
+ BLOCK_JOB_SPEED_INTERNAL, true);
+qemuDomainObjExitMonitorWithDriver(driver, vm);
+
+endjob:
+if (ret 0) {
+VIR_FREE(disk-mirror);
+VIR_FREE(disk-mirrorFormat);
+}
+if (qemuDomainObjEndJob(driver, vm) == 0) {
+vm = NULL;
+goto cleanup;
+}
+
+cleanup:
+VIR_FREE(device);
+if (vm)
+virDomainObjUnlock(vm);
+qemuDriverUnlock(driver);
+return ret;
+}
+
+static int
qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base,
unsigned long bandwidth, unsigned int flags)
{
-virCheckFlags(0, -1);
+virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
+ VIR_DOMAIN_BLOCK_REBASE_COPY |
+ VIR_DOMAIN_BLOCK_REBASE_COPY_RAW, -1);
+
+if (flags VIR_DOMAIN_BLOCK_REBASE_COPY) {
+const char *format = NULL;
+if (flags VIR_DOMAIN_BLOCK_REBASE_COPY_RAW)
+format = raw;
+flags =