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, 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.
---
src/qemu/qemu_driver.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 128 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 22829ba..41b45ec 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -11871,10 +11871,136 @@ 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;
+ virJSONValuePtr actions = NULL;
+ int mode;
+
+ /* 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))) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("block copy is not supported with this QEMU
binary"));
+ goto cleanup;
+ }
+ if (vm->persistent) {
+ 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;
+ }
+ if (flags & VIR_DOMAIN_BLOCK_REBASE_SHALLOW)
+ mode = QEMU_MONITOR_DRIVE_MIRROR_ABSOLUTE;
+ else
+ mode = QEMU_MONITOR_DRIVE_MIRROR_NO_BACKING;
+
+ /* Actually start the mirroring */
+ actions = virJSONValueNewArray();
+ if (!actions) {
+ virReportOOMError();
+ goto endjob;
+ }
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ ret = qemuMonitorDriveMirror(priv->mon, actions, device, dest,
+ format, mode);
+ if (ret == 0)
+ ret = qemuMonitorTransaction(priv->mon, actions);
+ if (ret == 0 && bandwidth != 0)
+ ret = qemuMonitorBlockJob(priv->mon, device, NULL, bandwidth, NULL,
+ BLOCK_JOB_SPEED_INTERNAL);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+ virJSONValueFree(actions);
+
+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 &= ~(VIR_DOMAIN_BLOCK_REBASE_COPY |
+ VIR_DOMAIN_BLOCK_REBASE_COPY_RAW);
+ return qemuDomainBlockCopy(dom, path, base, format, bandwidth, flags);
+ }
+
return qemuDomainBlockJobImpl(dom, path, base, bandwidth, NULL,
BLOCK_JOB_PULL, flags);
}
@@ -11883,6 +12009,7 @@ static int
qemuDomainBlockPull(virDomainPtr dom, const char *path, unsigned long bandwidth,
unsigned int flags)
{
+ virCheckFlags(0, -1);
return qemuDomainBlockRebase(dom, path, NULL, bandwidth, flags);
}
--
1.7.7.6