]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
blockjob: add new --bytes flag to virsh blockjob
authorEric Blake <eblake@redhat.com>
Thu, 28 Aug 2014 23:39:25 +0000 (17:39 -0600)
committerEric Blake <eblake@redhat.com>
Fri, 5 Sep 2014 19:13:23 +0000 (13:13 -0600)
Expose the new flag just added to virDomainGetBlockJobInfo.
With --raw, the presence or absence of --bytes determines which
flag to use in the single API call.  Without --raw, the use of
--bytes forces an error if the server doesn't support it,
otherwise, the code tries to silently fall back to scaling the
MiB/s value.

My goal is to eventually also support --bytes in bandwidth mode;
but that's a bit further down the road (and needs a new API flag
added in libvirt.h first).

This changes the human output, but the previous patch added
raw output precisely so that we can have flexibility with the
human output.  For this commit, I used qemu-monitor-command to
force an unusual bandwidth, but the same will be possible once
qemu implements virDomainBlockCopy:

Before:
Block Copy: [100 %]    Bandwidth limit: 2 MiB/s
After:
Block Copy: [100 %]    Bandwidth limit: 1048577 bytes/s (1.000 MiB/s)

The cache avoids having to repeatedly checking whether the flag
works when talking to an older server, when multiple blockjob
commands are issued during a batch session and the user is
manually polling for job completion.

* tools/virsh.h (_vshControl): Add a cache.
* tools/virsh.c (cmdConnect, vshReconnect): Initialize the cache.
* tools/virsh-domain.c (opts_block_job): Add --bytes.
* tools/virsh.pod (blockjob): Document this.

Signed-off-by: Eric Blake <eblake@redhat.com>
tools/virsh-domain.c
tools/virsh.c
tools/virsh.h
tools/virsh.pod

index f39d0a6c50a9012107c600bf45ba4368b2d5c0c5..2bb3bbc48ffc8c00afadaf9862d2e1e4d81abda3 100644 (file)
@@ -2048,6 +2048,10 @@ static const vshCmdOptDef opts_block_job[] = {
      .type = VSH_OT_BOOL,
      .help = N_("get active job information for the specified disk")
     },
+    {.name = "bytes",
+     .type = VSH_OT_BOOL,
+     .help = N_("with --info, get bandwidth in bytes rather than MiB/s")
+    },
     {.name = "raw",
      .type = VSH_OT_BOOL,
      .help = N_("implies --info; output details rather than human summary")
@@ -2080,8 +2084,9 @@ cmdBlockJob(vshControl *ctl, const vshCmd *cmd)
 {
     virDomainBlockJobInfo info;
     bool ret = false;
-    int rc;
+    int rc = -1;
     bool raw = vshCommandOptBool(cmd, "raw");
+    bool bytes = vshCommandOptBool(cmd, "bytes");
     bool abortMode = (vshCommandOptBool(cmd, "abort") ||
                       vshCommandOptBool(cmd, "async") ||
                       vshCommandOptBool(cmd, "pivot"));
@@ -2090,12 +2095,18 @@ cmdBlockJob(vshControl *ctl, const vshCmd *cmd)
     virDomainPtr dom = NULL;
     const char *path;
     unsigned int flags = 0;
+    unsigned long long speed;
 
     if (abortMode + infoMode + bandwidth > 1) {
         vshError(ctl, "%s",
                  _("conflict between abort, info, and bandwidth modes"));
         return false;
     }
+    /* XXX also support --bytes with bandwidth mode */
+    if (bytes && (abortMode || bandwidth)) {
+        vshError(ctl, "%s", _("--bytes requires info mode"));
+        return false;
+    }
 
     if (abortMode)
         return blockJobImpl(ctl, cmd, VSH_CMD_BLOCK_JOB_ABORT, NULL);
@@ -2110,9 +2121,47 @@ cmdBlockJob(vshControl *ctl, const vshCmd *cmd)
     if (vshCommandOptStringReq(ctl, cmd, "path", &path) < 0)
         goto cleanup;
 
-    rc = virDomainGetBlockJobInfo(dom, path, &info, flags);
-    if (rc < 0)
-        goto cleanup;
+    /* If bytes were requested, or if raw mode is not forcing a MiB/s
+     * query and cache can't prove failure, then query bytes/sec.  */
+    if (bytes || !(raw || ctl->blockJobNoBytes)) {
+        flags |= VIR_DOMAIN_BLOCK_JOB_INFO_BANDWIDTH_BYTES;
+        rc = virDomainGetBlockJobInfo(dom, path, &info, flags);
+        if (rc < 0) {
+            /* Check for particular errors, let all the rest be fatal. */
+            switch (last_error->code) {
+            case VIR_ERR_INVALID_ARG:
+                ctl->blockJobNoBytes = true;
+                /* fallthrough */
+            case VIR_ERR_OVERFLOW:
+                if (!bytes && !raw) {
+                    /* try again with MiB/s, unless forcing bytes */
+                    vshResetLibvirtError();
+                    break;
+                }
+                /* fallthrough */
+            default:
+                goto cleanup;
+            }
+        }
+        speed = info.bandwidth;
+    }
+    /* If we don't already have a query result, query for MiB/s */
+    if (rc < 0) {
+        flags &= ~VIR_DOMAIN_BLOCK_JOB_INFO_BANDWIDTH_BYTES;
+        if ((rc = virDomainGetBlockJobInfo(dom, path, &info, flags)) < 0)
+            goto cleanup;
+        speed = info.bandwidth;
+        /* Scale to bytes/s unless in raw mode */
+        if (!raw) {
+            speed <<= 20;
+            if (speed >> 20 != info.bandwidth) {
+                vshError(ctl, _("overflow in converting %ld MiB/s to bytes\n"),
+                         info.bandwidth);
+                goto cleanup;
+            }
+        }
+    }
+
     if (rc == 0) {
         if (!raw)
             vshPrint(ctl, _("No current block job for %s"), path);
@@ -2127,9 +2176,12 @@ cmdBlockJob(vshControl *ctl, const vshCmd *cmd)
     } else {
         vshPrintJobProgress(vshDomainBlockJobToString(info.type),
                             info.end - info.cur, info.end);
-        if (info.bandwidth != 0)
-            vshPrint(ctl, _("    Bandwidth limit: %lu MiB/s"),
-                     info.bandwidth);
+        if (speed) {
+            const char *unit;
+            double val = vshPrettyCapacity(speed, &unit);
+            vshPrint(ctl, _("    Bandwidth limit: %llu bytes/s (%-.3lf %s/s)"),
+                     speed, val, unit);
+        }
         vshPrint(ctl, "\n");
     }
     ret = true;
index 713c9a5fb69f1a5a0e800332eb9aaf4c2ebd39c2..9706acc88ed6333b605e79a824372063e4e60d41 100644 (file)
@@ -397,6 +397,7 @@ vshReconnect(vshControl *ctl)
     disconnected = 0;
     ctl->useGetInfo = false;
     ctl->useSnapshotOld = false;
+    ctl->blockJobNoBytes = false;
 }
 
 
@@ -454,6 +455,7 @@ cmdConnect(vshControl *ctl, const vshCmd *cmd)
 
     ctl->useGetInfo = false;
     ctl->useSnapshotOld = false;
+    ctl->blockJobNoBytes = false;
     ctl->readonly = ro;
 
     ctl->conn = vshConnect(ctl, ctl->name, ctl->readonly);
index b4df24bb39d45b5fa26eb5ef79d3af7d61a71e45..7d5d8a2dc63fa0803a1eb3bc7cd7910964d4e49c 100644 (file)
@@ -238,6 +238,8 @@ struct _vshControl {
                                    virDomainGetState is not supported */
     bool useSnapshotOld;        /* cannot use virDomainSnapshotGetParent or
                                    virDomainSnapshotNumChildren */
+    bool blockJobNoBytes;       /* true if _BANDWIDTH_BYTE blockjob flags
+                                   are missing */
     virThread eventLoop;
     virMutex lock;
     bool eventLoopStarted;
index acde0a1ae04a630b4f6e67744224083caac6998d..d95df364d86da0d6e4e810aa02218c8eecc413e8 100644 (file)
@@ -1013,7 +1013,7 @@ exclusive. If no flag is specified, behavior is different depending
 on hypervisor.
 
 =item B<blockjob> I<domain> I<path> { [I<--abort>] [I<--async>] [I<--pivot>] |
-[I<--info>] [I<--raw>] | [I<bandwidth>] }
+[I<--info>] [I<--raw>] [I<--bytes>] | [I<bandwidth>] }
 
 Manage active block operations.  There are three mutually-exclusive modes:
 I<--info>, I<bandwidth>, and I<--abort>.  I<--async> and I<--pivot> imply
@@ -1034,7 +1034,11 @@ commit job be pivoted over to the new image.
 In I<--info> mode, the active job information on the specified
 disk will be printed.  By default, the output is a single human-readable
 summary line; this format may change in future versions.  Adding
-I<--raw> lists each field of the struct, in a stable format.
+I<--raw> lists each field of the struct, in a stable format.  If the
+I<--bytes> flag is set, then the command errors out if the server could
+not supply bytes/s resolution; when omitting the flag, raw output is
+listed in MiB/s and human-readable output automatically selects the
+best resolution supported by the server.
 
 I<bandwidth> can be used to set bandwidth limit for the active job.
 Specifying a negative value is interpreted as an unsigned long long