[libvirt] [PATCH v6 2/2] blockcommit: turn on active commit

Eric Blake eblake at redhat.com
Wed Jul 30 04:05:57 UTC 2014


With this in place, I can (finally!) now do:

virsh blockcommit $dom vda --shallow --verbose --pivot

and watch qemu shorten the backing chain by one, followed by
libvirt automatically updating the dumpxml output, effectively
undoing the work of virsh snapshot-commit --no-metadata --disk-only.
Commit is SOOOO much faster than blockpull, when I'm still fairly
close in time to when the temporary qcow2 wrapper file was created
via a snapshot operation!

* src/qemu/qemu_driver.c (qemuDomainBlockCommit): Implement live
commit.

Signed-off-by: Eric Blake <eblake at redhat.com>
---
 src/qemu/qemu_driver.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 41 insertions(+), 5 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 9ee62ef..a3de784 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -15512,9 +15512,11 @@ qemuDomainBlockCommit(virDomainPtr dom,
     char *topPath = NULL;
     char *basePath = NULL;
     char *backingPath = NULL;
+    virStorageSourcePtr mirror = NULL;

-    /* XXX Add support for COMMIT_ACTIVE, COMMIT_DELETE */
+    /* XXX Add support for COMMIT_DELETE */
     virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW |
+                  VIR_DOMAIN_BLOCK_COMMIT_ACTIVE |
                   VIR_DOMAIN_BLOCK_COMMIT_RELATIVE, -1);

     if (!(vm = qemuDomObjFromDomain(dom)))
@@ -15563,9 +15565,6 @@ qemuDomainBlockCommit(virDomainPtr dom,
                                                      &top_parent)))
         goto endjob;

-    /* FIXME: qemu 2.0 supports active commit, but as a two-stage
-     * process; qemu 2.1 is further improving active commit. We need
-     * to start supporting it in libvirt. */
     if (topSource == disk->src) {
         if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_ACTIVE_COMMIT)) {
             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
@@ -15579,6 +15578,12 @@ qemuDomainBlockCommit(virDomainPtr dom,
                            disk->dst);
             goto endjob;
         }
+        if (disk->mirror) {
+            virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
+                           _("disk '%s' already in active block job"),
+                           disk->dst);
+            goto endjob;
+        }
     } else if (flags & VIR_DOMAIN_BLOCK_COMMIT_ACTIVE) {
         virReportError(VIR_ERR_INVALID_ARG,
                        _("active commit requested but '%s' is not active"),
@@ -15609,6 +15614,16 @@ qemuDomainBlockCommit(virDomainPtr dom,
         goto endjob;
     }

+    /* For an active commit, clone enough of the base to act as the mirror */
+    if (topSource == disk->src) {
+        if (!(mirror = virStorageSourceCopy(baseSource, false)))
+            goto endjob;
+        if (virStorageSourceInitChainElement(mirror,
+                                             disk->src,
+                                             false) < 0)
+            goto endjob;
+    }
+
     /* For the commit to succeed, we must allow qemu to open both the
      * 'base' image and the parent of 'top' as read/write; 'top' might
      * not have a parent, or might already be read-write.  XXX It
@@ -15653,13 +15668,33 @@ qemuDomainBlockCommit(virDomainPtr dom,
      * if any, through to qemu, since qemu may behave differently
      * depending on whether the input was specified as relative or
      * absolute (that is, our absolute top_canon may do the wrong
-     * thing if the user specified a relative name). */
+     * thing if the user specified a relative name).  Be prepared for
+     * a ready event to occur while locks are dropped.  */
+    if (mirror) {
+        disk->mirror = mirror;
+        disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT;
+    }
     qemuDomainObjEnterMonitor(driver, vm);
     ret = qemuMonitorBlockCommit(priv->mon, device,
                                  topPath, basePath, backingPath,
                                  bandwidth);
     qemuDomainObjExitMonitor(driver, vm);

+    if (mirror) {
+        if (ret == 0) {
+            virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+
+            mirror = NULL;
+            if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
+                VIR_WARN("Unable to save status on vm %s after block job",
+                         vm->def->name);
+            virObjectUnref(cfg);
+        } else {
+            disk->mirror = NULL;
+            disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
+        }
+    }
+
  endjob:
     if (ret < 0 && clean_access) {
         /* Revert access to read-only, if possible.  */
@@ -15669,6 +15704,7 @@ qemuDomainBlockCommit(virDomainPtr dom,
             qemuDomainPrepareDiskChainElement(driver, vm, top_parent,
                                               VIR_DISK_CHAIN_READ_ONLY);
     }
+    virStorageSourceFree(mirror);
     if (!qemuDomainObjEndJob(driver, vm))
         vm = NULL;

-- 
1.9.3




More information about the libvir-list mailing list