[libvirt] [PATCHv3 11/16] blockjob: implement block copy for qemu

Eric Blake eblake at redhat.com
Fri Apr 6 18:29:42 UTC 2012


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.
---
 src/qemu/qemu_driver.c |  119 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 118 insertions(+), 1 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index dd844a1..1b1c921 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -11868,10 +11868,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;
+    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 */
+    qemuDomainObjEnterMonitorWithDriver(driver, vm);
+    ret = qemuMonitorDriveMirror(priv->mon, NULL, device, dest, format, mode);
+    if (ret == 0 && bandwidth != 0)
+        ret = qemuMonitorBlockJob(priv->mon, device, NULL, bandwidth, NULL,
+                                  BLOCK_JOB_SPEED_INTERNAL);
+    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 &= ~(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);
 }
@@ -11880,6 +11996,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




More information about the libvir-list mailing list