]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
blockjob: add qemu capabilities related to block pull jobs
authorEric Blake <eblake@redhat.com>
Wed, 11 Apr 2012 21:40:16 +0000 (15:40 -0600)
committerEric Blake <eblake@redhat.com>
Thu, 12 Apr 2012 02:43:53 +0000 (20:43 -0600)
RHEL 6.2 was released with an early version of block jobs, which only
worked on the qed file format, where the commands were spelled with
underscore (contrary to QMP style), and where 'block_job_cancel' was
synchronous and did not trigger an event.

The upcoming qemu 1.1 release has fixed these short-comings [1][2]:
the commands now work on multiple file types, are spelled with dash,
and 'block-job-cancel' is asynchronous and emits an event upon conclusion.

[1]qemu commit 370521a1d6f5537ea7271c119f3fbb7b0fa57063
[2]https://lists.gnu.org/archive/html/qemu-devel/2012-04/msg01248.html

This patch recognizes the new spellings, and fixes virDomainBlockRebase
to give a graceful error when talking to a too-old qemu on a partial
rebase attempt.  Fixes for the new semantics will come later.  This
patch also removes a bogus ATTRIBUTE_NONNULL mistakenly added in
commit 10ec36e2.

* src/qemu/qemu_capabilities.h (QEMU_CAPS_BLOCKJOB_SYNC)
(QEMU_CAPS_BLOCKJOB_ASYNC): New bits.
* src/qemu/qemu_capabilities.c (qemuCaps): Name them.
* src/qemu/qemu_monitor_json.c (qemuMonitorJSONCheckCommands): Set
them.
(qemuMonitorJSONBlockJob): Manage both command names.
(qemuMonitorJSONDiskSnapshot): Minor formatting fix.
* src/qemu/qemu_monitor.h (qemuMonitorBlockJob): Alter signature.
* src/qemu/qemu_monitor_json.h (qemuMonitorJSONBlockJob): Likewise.
* src/qemu/qemu_monitor.c (qemuMonitorBlockJob): Pass through
capability bit.
* src/qemu/qemu_driver.c (qemuDomainBlockJobImpl): Update callers.

src/qemu/qemu_capabilities.c
src/qemu/qemu_capabilities.h
src/qemu/qemu_driver.c
src/qemu/qemu_monitor.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_json.h

index 0e09d6d285c750805d3836a8e3ad521b2b4bdc61..fd4ca4d3d7dd91ed22ecbb1debbd85367f8d69b4 100644 (file)
@@ -156,6 +156,9 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
               "scsi-disk.channel",
               "scsi-block",
               "transaction",
+
+              "block-job-sync", /* 90 */
+              "block-job-async",
     );
 
 struct qemu_feature_flags {
index 78cdbe08843d8964d88108655015204b8b3e6a18..6550d599fc5c299b7a797b78a89f68f459d73220 100644 (file)
@@ -124,6 +124,8 @@ enum qemuCapsFlags {
     QEMU_CAPS_SCSI_DISK_CHANNEL  = 87, /* Is scsi-disk.channel available? */
     QEMU_CAPS_SCSI_BLOCK         = 88, /* -device scsi-block */
     QEMU_CAPS_TRANSACTION        = 89, /* transaction monitor command */
+    QEMU_CAPS_BLOCKJOB_SYNC      = 90, /* RHEL 6.2 block_job_cancel */
+    QEMU_CAPS_BLOCKJOB_ASYNC     = 91, /* qemu 1.1 block-job-cancel */
 
     QEMU_CAPS_LAST,                   /* this must always be the last item */
 };
index e18e72d15c0fcc29fa8d3da25606b2643d54db93..f939a31d1b1f7f1bec79d4e26e54ad69009b19bf 100644 (file)
@@ -11607,6 +11607,7 @@ qemuDomainBlockJobImpl(virDomainPtr dom, const char *path, const char *base,
     char uuidstr[VIR_UUID_STRING_BUFLEN];
     char *device = NULL;
     int ret = -1;
+    bool async = false;
 
     qemuDriverLock(driver);
     virUUIDFormat(dom->uuid, uuidstr);
@@ -11616,6 +11617,19 @@ qemuDomainBlockJobImpl(virDomainPtr dom, const char *path, const char *base,
                         _("no domain with matching uuid '%s'"), uuidstr);
         goto cleanup;
     }
+    priv = vm->privateData;
+    if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC)) {
+        async = true;
+    } else if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_SYNC)) {
+        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                        _("block jobs not supported with this QEMU binary"));
+        goto cleanup;
+    } else if (base) {
+        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                        _("partial block pull not supported with this "
+                          "QEMU binary"));
+        goto cleanup;
+    }
 
     device = qemuDiskPathToAlias(vm, path, NULL);
     if (!device) {
@@ -11632,13 +11646,11 @@ qemuDomainBlockJobImpl(virDomainPtr dom, const char *path, const char *base,
     }
 
     qemuDomainObjEnterMonitorWithDriver(driver, vm);
-    priv = vm->privateData;
-    /* XXX - add a qemu capability check, since only qemu 1.1 or newer
-     * supports the base argument.
-     * XXX - libvirt should really be tracking the backing file chain
+    /* XXX - libvirt should really be tracking the backing file chain
      * itself, and validating that base is on the chain, rather than
      * relying on qemu to do this.  */
-    ret = qemuMonitorBlockJob(priv->mon, device, base, bandwidth, info, mode);
+    ret = qemuMonitorBlockJob(priv->mon, device, base, bandwidth, info, mode,
+                              async);
     qemuDomainObjExitMonitorWithDriver(driver, vm);
 
 endjob:
index e1a8d4c9c6e8cbbbfcc1270f378c11ac8cef5de6..36f3832e1848b0e562e7608bfb040c0108968cd4 100644 (file)
@@ -2773,15 +2773,18 @@ int qemuMonitorBlockJob(qemuMonitorPtr mon,
                         const char *base,
                         unsigned long bandwidth,
                         virDomainBlockJobInfoPtr info,
-                        int mode)
+                        int mode,
+                        bool async)
 {
     int ret = -1;
 
-    VIR_DEBUG("mon=%p, device=%s, base=%s, bandwidth=%lu, info=%p, mode=%o",
-              mon, device, NULLSTR(base), bandwidth, info, mode);
+    VIR_DEBUG("mon=%p, device=%s, base=%s, bandwidth=%lu, info=%p, mode=%o, "
+              "async=%d", mon, device, NULLSTR(base), bandwidth, info, mode,
+              async);
 
     if (mon->json)
-        ret = qemuMonitorJSONBlockJob(mon, device, base, bandwidth, info, mode);
+        ret = qemuMonitorJSONBlockJob(mon, device, base, bandwidth, info, mode,
+                                      async);
     else
         qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                         _("block jobs require JSON monitor"));
index b48096661ab26afee466b5f25d8c22f0abdf4494..dc02964fd2cd17d20202b6b5728e104ee7970c6a 100644 (file)
@@ -538,8 +538,9 @@ int qemuMonitorBlockJob(qemuMonitorPtr mon,
                         const char *back,
                         unsigned long bandwidth,
                         virDomainBlockJobInfoPtr info,
-                        int mode)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(5);
+                        int mode,
+                        bool async)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 
 int qemuMonitorOpenGraphics(qemuMonitorPtr mon,
                             const char *protocol,
index d09d7793ff82059b2906c5a83fd1a073d3ac6ea7..d4d2c3e6bda42409585362846112706617e5d3c2 100644 (file)
@@ -939,12 +939,14 @@ qemuMonitorJSONCheckCommands(qemuMonitorPtr mon,
 
         if (STREQ(name, "human-monitor-command"))
             *json_hmp = 1;
-
-        if (STREQ(name, "system_wakeup"))
+        else if (STREQ(name, "system_wakeup"))
             qemuCapsSet(qemuCaps, QEMU_CAPS_WAKEUP);
-
-        if (STREQ(name, "transaction"))
+        else if (STREQ(name, "transaction"))
             qemuCapsSet(qemuCaps, QEMU_CAPS_TRANSACTION);
+        else if (STREQ(name, "block_job_cancel"))
+            qemuCapsSet(qemuCaps, QEMU_CAPS_BLOCKJOB_SYNC);
+        else if (STREQ(name, "block-job-cancel"))
+            qemuCapsSet(qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC);
     }
 
     ret = 0;
@@ -3114,7 +3116,7 @@ qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr actions,
                             const char *device, const char *file,
                             const char *format, bool reuse)
 {
-    int ret;
+    int ret = -1;
     virJSONValuePtr cmd;
     virJSONValuePtr reply = NULL;
 
@@ -3132,14 +3134,13 @@ qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr actions,
     if (actions) {
         if (virJSONValueArrayAppend(actions, cmd) < 0) {
             virReportOOMError();
-            ret = -1;
         } else {
             ret = 0;
             cmd = NULL;
         }
     } else {
         if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
-        goto cleanup;
+            goto cleanup;
 
         if (qemuMonitorJSONHasError(reply, "CommandNotFound") &&
             qemuMonitorCheckHMP(mon, "snapshot_blkdev")) {
@@ -3388,39 +3389,43 @@ qemuMonitorJSONBlockJob(qemuMonitorPtr mon,
                         const char *base,
                         unsigned long bandwidth,
                         virDomainBlockJobInfoPtr info,
-                        int mode)
+                        int mode,
+                        bool async)
 {
     int ret = -1;
     virJSONValuePtr cmd = NULL;
     virJSONValuePtr reply = NULL;
     const char *cmd_name = NULL;
 
-    if (base && mode != BLOCK_JOB_PULL) {
+    if (base && (mode != BLOCK_JOB_PULL || !async)) {
         qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("only block pull supports base: %s"), base);
+                        _("only modern block pull supports base: %s"), base);
         return -1;
     }
 
-    if (mode == BLOCK_JOB_ABORT) {
-        cmd_name = "block_job_cancel";
+    switch ((BLOCK_JOB_CMD) mode) {
+    case BLOCK_JOB_ABORT:
+        cmd_name = async ? "block-job-cancel" : "block_job_cancel";
         cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device", device, NULL);
-    } else if (mode == BLOCK_JOB_INFO) {
+        break;
+    case BLOCK_JOB_INFO:
         cmd_name = "query-block-jobs";
         cmd = qemuMonitorJSONMakeCommand(cmd_name, NULL);
-    } else if (mode == BLOCK_JOB_SPEED) {
-        cmd_name = "block_job_set_speed";
+        break;
+    case BLOCK_JOB_SPEED:
+        cmd_name = async ? "block-job-set-speed" : "block_job_set_speed";
         cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device",
                                          device, "U:value",
                                          bandwidth * 1024ULL * 1024ULL,
                                          NULL);
-    } else if (mode == BLOCK_JOB_PULL) {
-        cmd_name = "block_stream";
-        if (base)
-            cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device",
-                                             device, "s:base", base, NULL);
-        else
-            cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device",
-                                             device, NULL);
+        break;
+    case BLOCK_JOB_PULL:
+        cmd_name = async ? "block-stream" : "block_stream";
+        cmd = qemuMonitorJSONMakeCommand(cmd_name,
+                                         "s:device", device,
+                                         base ? "s:base" : NULL, base,
+                                         NULL);
+        break;
     }
 
     if (!cmd)
index a0f67aaba18c09bcbd82575a1520503d886a8ac4..aacbb5ff9fda74af96d35ac7633fc52fd337d349 100644 (file)
@@ -253,7 +253,9 @@ int qemuMonitorJSONBlockJob(qemuMonitorPtr mon,
                             const char *base,
                             unsigned long bandwidth,
                             virDomainBlockJobInfoPtr info,
-                            int mode);
+                            int mode,
+                            bool async)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 
 int qemuMonitorJSONSetLink(qemuMonitorPtr mon,
                            const char *name,