blockjob: add new --bytes flag to virsh blockjob

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>
This commit is contained in:
Eric Blake 2014-08-28 17:39:25 -06:00
parent 2019b7caca
commit 1105c1deff
4 changed files with 69 additions and 9 deletions

View 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;
/* 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)
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;

View 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);

View 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;

View 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