[libvirt] [PATCH 13/13] WIP: blockjob: implement block copy for qemu

Eric Blake eblake at redhat.com
Tue Apr 3 04:43:21 UTC 2012


Wire up all the pieces in the previous patches to actually enable
a block copy job.

This compiles, but isn't correct, and there are still more patches
to go:

prereq patch: fix qemuDomainBlockJobImpl to do BLOCK_JOB_PULL and
BLOCK_JOB_SPEED in one monitor job, rather than two

this patch: fix things to reuse the same block job for all three
monitor calls (drive-mirror, block_stream, block_job_set_speed);
handle errors better, set SELinux labels and lock manager usage
properly, add a disk audit message

future patch 1: add block job abort processing, which calls
'drive-reopen' at the proper times, and also includes SELinux
and lock manager activity

future patch 2: wire up the _SHALLOW flag to use 'query-block'
to determine the appropriate 'base' argument for shallow copy

future patch 3: wire up the virDomainBlockCopy command to this
function

future patch 4: RHEL-only: cater to the __com.redhat_* naming
prefix of an early backport

what else?  probably several cleanup patches

But the series is progressing nicely, and even though this
particular patch isn't ready, the prereqs can be reviewed.

* src/qemu/qemu_driver.c (qemuDomainBlockCopy): New function.
(qemuDomainBlockRebase): Call it when appropriate.
---
 src/qemu/qemu_driver.c |  108 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 107 insertions(+), 1 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1664e14..42af95e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -11769,12 +11769,117 @@ qemuDomainBlockJobSetSpeed(virDomainPtr dom, const char *path,
 }

 static int
+qemuDomainBlockCopy(virDomainPtr dom, const char *path, const char *base,
+                    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;
+
+    /* Step 0: get the disk, check for caps */
+    virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT, -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;
+    }
+
+    /* Step 1: call 'drive-mirror' to start the mirroring */
+    actions = virJSONValueNewArray();
+    if (!actions) {
+        virReportOOMError();
+        goto endjob;
+    }
+    qemuDomainObjEnterMonitorWithDriver(driver, vm);
+    ret = qemuMonitorDriveMirror(priv->mon, actions, device, dest,
+                                 format ? format : disk->driverType,
+                                 (flags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT ?
+                                  QEMU_MONITOR_DRIVE_MIRROR_EXISTING :
+                                  QEMU_MONITOR_DRIVE_MIRROR_ABSOLUTE));
+
+    if (ret == 0)
+        ret = qemuMonitorTransaction(priv->mon, actions);
+    qemuDomainObjExitMonitorWithDriver(driver, vm);
+
+    /* Step 2: call 'block_stream' to pull into the mirror */
+    ret = qemuDomainBlockJobImpl(dom, path, base, bandwidth, NULL,
+                                 BLOCK_JOB_PULL, flags);
+    if (ret == 0 && bandwidth != 0)
+        ret = qemuDomainBlockJobImpl(dom, path, NULL, bandwidth, NULL,
+                                     BLOCK_JOB_SPEED, flags);
+
+endjob:
+    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)
 {
     int ret;

-    virCheckFlags(0, -1);
+    virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_COPY |
+                  VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT, -1);
+
+    if (flags & VIR_DOMAIN_BLOCK_REBASE_COPY)
+        return qemuDomainBlockCopy(dom, path, NULL, base, NULL, bandwidth,
+                                   flags & ~VIR_DOMAIN_BLOCK_REBASE_COPY);
+
     ret = qemuDomainBlockJobImpl(dom, path, base, bandwidth, NULL,
                                  BLOCK_JOB_PULL, flags);
     if (ret == 0 && bandwidth != 0)
@@ -11787,6 +11892,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