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 attempt a flag probe 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@xxxxxxxxxx> --- tools/virsh-domain.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++------ tools/virsh.c | 2 ++ tools/virsh.h | 2 ++ tools/virsh.pod | 8 +++++-- 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index b95e971..eb3ed15 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -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,45 @@ 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 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); + } + } + if (rc == 0) { if (!raw) vshPrint(ctl, _("No current block job for %s"), path); @@ -2127,9 +2174,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; diff --git a/tools/virsh.c b/tools/virsh.c index 713c9a5..9706acc 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -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); diff --git a/tools/virsh.h b/tools/virsh.h index b4df24b..7d5d8a2 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -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; diff --git a/tools/virsh.pod b/tools/virsh.pod index 3f1bf7e..406de5c 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -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 -- 1.9.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list