[libvirt] [PATCHv9.5 1/2] blockjob: add qemu capabilities related to block jobs

Eric Blake eblake at redhat.com
Fri Oct 26 23:00:24 UTC 2012


Upstream qemu 1.3 is adding two new monitor commands, 'drive-mirror'
and 'block-job-complete'[1], which can drive live block copy and
storage migration.  [Additionally, RHEL 6.3 had backported an earlier
version of most of the same functionality, but under the names
'__com.redhat_drive-mirror' and '__com.redhat_drive-reopen' and with
slightly different JSON arguments, and has been using patches similar
to these upstream patches for several months now.]

The libvirt API virDomainBlockRebase as already committed for 0.9.12
is flexible enough to expose the basics of block copy, but some
additional features in the 'drive-mirror' qemu command, such as
setting error policy, setting granularity, or using a persistent
bitmap, may later require a new libvirt API virDomainBlockCopy.  I
will wait to add that API until we know more about what qemu 1.3
will finally provide.

This patch caters only to the upstream qemu 1.3 interface, although
I have proven that the changes for RHEL 6.3 can be isolated to
just qemu_monitor_json.c, and the rest of this series will
gracefully handle either interface once the JSON differences are
papered over in a downstream patch.

For consistency with other block job commands, libvirt must handle
the bandwidth argument as MiB/sec from the user, even though qemu
exposes the speed argument as bytes/sec; then again, qemu rounds
up to cluster size internally, so using MiB hides the worst effects
of that rounding if you pass small numbers.

[1]https://lists.gnu.org/archive/html/qemu-devel/2012-10/msg04123.html

* src/qemu/qemu_capabilities.h (QEMU_CAPS_DRIVE_MIRROR)
(QEMU_CAPS_DRIVE_REOPEN): New bits.
* src/qemu/qemu_capabilities.c (qemuCaps): Name them.
* src/qemu/qemu_monitor_json.c (qemuMonitorJSONCheckCommands): Set
them.
(qemuMonitorJSONDriveMirror, qemuMonitorDrivePivot): New functions.
* src/qemu/qemu_monitor_json.h (qemuMonitorJSONDriveMirror)
(qemuMonitorDrivePivot): Declare them.
* src/qemu/qemu_monitor.c (qemuMonitorDriveMirror)
(qemuMonitorDrivePivot): New passthroughs.
* src/qemu/qemu_monitor.h (qemuMonitorDriveMirror)
(qemuMonitorDrivePivot): Declare them.
---

v9.5: Update the commit message to point to Kevin's PULL request
(we're one step closer to having drive-mirror in upstream qemu.git,
and a PULL request means the interface is now stable).  Drop
consideration for RHEL 6.3, by dropping the 'bool reopen' parameter;
later patches in the series will trivially rebase that part out.

 src/qemu/qemu_capabilities.c |  4 +++
 src/qemu/qemu_capabilities.h |  1 +
 src/qemu/qemu_monitor.c      | 56 +++++++++++++++++++++++++++++++++++++++--
 src/qemu/qemu_monitor.h      | 12 +++++++++
 src/qemu/qemu_monitor_json.c | 60 ++++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_monitor_json.h | 19 ++++++++++++--
 6 files changed, 148 insertions(+), 4 deletions(-)

diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 115a054..6194310 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -189,6 +189,8 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
               "seamless-migration",
               "block-commit",
               "vnc",
+
+              "drive-mirror", /* 115 */
     );

 struct _qemuCaps {
@@ -1889,6 +1891,8 @@ qemuCapsProbeQMPCommands(qemuCapsPtr caps,
             qemuCapsSet(caps, QEMU_CAPS_BLOCK_COMMIT);
         else if (STREQ(name, "query-vnc"))
             qemuCapsSet(caps, QEMU_CAPS_VNC);
+        else if (STREQ(name, "drive-mirror"))
+            qemuCapsSet(caps, QEMU_CAPS_DRIVE_MIRROR);
         VIR_FREE(name);
     }
     VIR_FREE(commands);
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 988dfdb..cce372b 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -152,6 +152,7 @@ enum qemuCapsFlags {
     QEMU_CAPS_SEAMLESS_MIGRATION = 112, /* seamless-migration for SPICE */
     QEMU_CAPS_BLOCK_COMMIT       = 113, /* block-commit */
     QEMU_CAPS_VNC                = 114, /* Is -vnc available? */
+    QEMU_CAPS_DRIVE_MIRROR       = 115, /* drive-mirror monitor command */

     QEMU_CAPS_LAST,                   /* this must always be the last item */
 };
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 2d9c44c..3126960 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2780,6 +2780,39 @@ qemuMonitorDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr actions,
     return ret;
 }

+/* Start a drive-mirror block job.  bandwidth is in MiB/sec.  */
+int
+qemuMonitorDriveMirror(qemuMonitorPtr mon,
+                       const char *device, const char *file,
+                       const char *format, unsigned long bandwidth,
+                       unsigned int flags)
+{
+    int ret = -1;
+    unsigned long long speed;
+
+    VIR_DEBUG("mon=%p, device=%s, file=%s, format=%s, bandwidth=%ld, "
+              "flags=%x",
+              mon, device, file, NULLSTR(format), bandwidth, flags);
+
+    /* Convert bandwidth MiB to bytes */
+    speed = bandwidth;
+    if (speed > ULLONG_MAX / 1024 / 1024) {
+        virReportError(VIR_ERR_OVERFLOW,
+                       _("bandwidth must be less than %llu"),
+                       ULLONG_MAX / 1024 / 1024);
+        return -1;
+    }
+    speed <<= 20;
+
+    if (mon->json)
+        ret = qemuMonitorJSONDriveMirror(mon, device, file, format, speed,
+                                         flags);
+    else
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("drive-mirror requires JSON monitor"));
+    return ret;
+}
+
 /* Use the transaction QMP command to run atomic snapshot commands.  */
 int
 qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
@@ -2796,7 +2829,7 @@ qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
     return ret;
 }

-/* Start a block-commit block job.  bandwidth is in MB/sec.  */
+/* Start a block-commit block job.  bandwidth is in MiB/sec.  */
 int
 qemuMonitorBlockCommit(qemuMonitorPtr mon, const char *device,
                        const char *top, const char *base,
@@ -2826,6 +2859,25 @@ qemuMonitorBlockCommit(qemuMonitorPtr mon, const char *device,
     return ret;
 }

+/* Use the block-job-complete monitor command to pivot a block copy
+ * job.  */
+int
+qemuMonitorDrivePivot(qemuMonitorPtr mon, const char *device,
+                      const char *file, const char *format)
+{
+    int ret = -1;
+
+    VIR_DEBUG("mon=%p, device=%s, file=%s, format=%s",
+              mon, device, file, NULLSTR(format));
+
+    if (mon->json)
+        ret = qemuMonitorJSONDrivePivot(mon, device, file, format);
+    else
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("drive pivot requires JSON monitor"));
+    return ret;
+}
+
 int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
                                 const char *cmd,
                                 char **reply,
@@ -2893,7 +2945,7 @@ int qemuMonitorScreendump(qemuMonitorPtr mon,
     return ret;
 }

-/* bandwidth is in MB/sec */
+/* bandwidth is in MiB/sec */
 int qemuMonitorBlockJob(qemuMonitorPtr mon,
                         const char *device,
                         const char *base,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 8856d9f..f6a4a47 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -523,6 +523,18 @@ int qemuMonitorDiskSnapshot(qemuMonitorPtr mon,
                             bool reuse);
 int qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int qemuMonitorDriveMirror(qemuMonitorPtr mon,
+                           const char *device,
+                           const char *file,
+                           const char *format,
+                           unsigned long bandwidth,
+                           unsigned int flags)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+int qemuMonitorDrivePivot(qemuMonitorPtr mon,
+                          const char *device,
+                          const char *file,
+                          const char *format)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);

 int qemuMonitorBlockCommit(qemuMonitorPtr mon,
                            const char *device,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index e495c0a..8f207b1 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -3249,6 +3249,41 @@ cleanup:
     return ret;
 }

+/* speed is in bytes/sec */
+int
+qemuMonitorJSONDriveMirror(qemuMonitorPtr mon,
+                           const char *device, const char *file,
+                           const char *format, unsigned long long speed,
+                           unsigned int flags)
+{
+    int ret = -1;
+    virJSONValuePtr cmd;
+    virJSONValuePtr reply = NULL;
+    bool shallow = (flags & VIR_DOMAIN_BLOCK_REBASE_SHALLOW) != 0;
+    bool reuse = (flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT) != 0;
+
+    cmd = qemuMonitorJSONMakeCommand("drive-mirror",
+                                     "s:device", device,
+                                     "s:target", file,
+                                     "U:speed", speed,
+                                     "s:sync", shallow ? "top" : "full",
+                                     "s:mode",
+                                     reuse ? "existing" : "absolute-paths",
+                                     format ? "s:format" : NULL, format,
+                                     NULL);
+    if (!cmd)
+        return -1;
+
+    if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
+        goto cleanup;
+    ret = qemuMonitorJSONCheckError(cmd, reply);
+
+cleanup:
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
 int
 qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
 {
@@ -3306,6 +3341,31 @@ cleanup:
     return ret;
 }

+int
+qemuMonitorJSONDrivePivot(qemuMonitorPtr mon, const char *device,
+                          const char *file ATTRIBUTE_UNUSED,
+                          const char *format ATTRIBUTE_UNUSED)
+{
+    int ret;
+    virJSONValuePtr cmd;
+    virJSONValuePtr reply = NULL;
+
+    cmd = qemuMonitorJSONMakeCommand("block-job-complete",
+                                     "s:device", device,
+                                     NULL);
+    if (!cmd)
+        return -1;
+
+    if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
+        goto cleanup;
+    ret = qemuMonitorJSONCheckError(cmd, reply);
+
+cleanup:
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+

 int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
                                     const char *cmd_str,
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 61127a7..2834fed 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -232,8 +232,23 @@ int qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon,
                                 const char *device,
                                 const char *file,
                                 const char *format,
-                                bool reuse);
-int qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions);
+                                bool reuse)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3)
+    ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
+int qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int qemuMonitorJSONDriveMirror(qemuMonitorPtr mon,
+                               const char *device,
+                               const char *file,
+                               const char *format,
+                               unsigned long long speed,
+                               unsigned int flags)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+int qemuMonitorJSONDrivePivot(qemuMonitorPtr mon,
+                              const char *device,
+                              const char *file,
+                              const char *format)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);

 int qemuMonitorJSONBlockCommit(qemuMonitorPtr mon,
                                const char *device,
-- 
1.7.11.7




More information about the libvir-list mailing list