Allow specifying sizes in bytes or as scaled integers for user convenience. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1288000 --- tools/virsh-domain.c | 17 ++++++++++------- tools/virsh.pod | 11 ++++++++--- tools/vsh.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/vsh.h | 4 ++++ 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 854823e..5ea39f7 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -2492,7 +2492,7 @@ static const vshCmdOptDef opts_block_job[] = { }, {.name = "bytes", .type = VSH_OT_BOOL, - .help = N_("with --info, get bandwidth in bytes rather than MiB/s") + .help = N_("get/set bandwidth in bytes rather than MiB/s") }, {.name = "raw", .type = VSH_OT_BOOL, @@ -2611,14 +2611,19 @@ static bool virshBlockJobSetSpeed(vshControl *ctl, const vshCmd *cmd, virDomainPtr dom, - const char *path) + const char *path, + bool bytes) { unsigned long bandwidth; + unsigned int flags = 0; - if (vshCommandOptULWrap(ctl, cmd, "bandwidth", &bandwidth) < 0) + if (bytes) + flags |= VIR_DOMAIN_BLOCK_JOB_SPEED_BANDWIDTH_BYTES; + + if (vshBlockJobOptionBandwidth(ctl, cmd, bytes, &bandwidth) < 0) return false; - if (virDomainBlockJobSetSpeed(dom, path, bandwidth, 0) < 0) + if (virDomainBlockJobSetSpeed(dom, path, bandwidth, flags) < 0) return false; return true; @@ -2672,8 +2677,6 @@ cmdBlockJob(vshControl *ctl, const vshCmd *cmd) VSH_EXCLUSIVE_OPTIONS("bytes", "abort"); VSH_EXCLUSIVE_OPTIONS_VAR(bytes, pivot); VSH_EXCLUSIVE_OPTIONS_VAR(bytes, async); - /* XXX also support --bytes with bandwidth mode */ - VSH_EXCLUSIVE_OPTIONS_VAR(bytes, bandwidth); if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) goto cleanup; @@ -2683,7 +2686,7 @@ cmdBlockJob(vshControl *ctl, const vshCmd *cmd) goto cleanup; if (bandwidth) - ret = virshBlockJobSetSpeed(ctl, cmd, dom, path); + ret = virshBlockJobSetSpeed(ctl, cmd, dom, path, bytes); else if (abortMode || pivot || async) ret = virshBlockJobAbort(dom, path, pivot, async); else diff --git a/tools/virsh.pod b/tools/virsh.pod index 1e2c6a6..edb9ce5 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1152,10 +1152,15 @@ 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 +I<bandwidth> can be used to set bandwidth limit for the active job in MiB/s. +If I<--bytes> is specified then the bandwidth value is interpreted in +bytes/s. Specifying a negative value is interpreted as an unsigned long value or essentially unlimited. The hypervisor can choose whether to -reject the value or convert it to the maximum value allowed. +reject the value or convert it to the maximum value allowed. Optionally a +scaled positive number may be used as bandwidth (see B<NOTES> above). Using +I<--bytes> with a scaled value allows to use finer granularity. A scaled value +used without I<--bytes> will be rounded down to MiB/s. Note that the +I<--bytes> may be unsupported by the hypervisor. =item B<blockresize> I<domain> I<path> I<size> diff --git a/tools/vsh.c b/tools/vsh.c index cbe8189..f90619d 100644 --- a/tools/vsh.c +++ b/tools/vsh.c @@ -1201,6 +1201,58 @@ vshCommandOptArgv(vshControl *ctl ATTRIBUTE_UNUSED, const vshCmd *cmd, } +/** + * vshBlockJobOptionBandwidth + * @ctl: virsh control data + * @cmd: virsh command description + * @bytes: return bandwidth in bytes/s instead of MiB/s + * @bandwidth: return value + * + * Extracts the value of --bandwidth either as a wrappable number without scale + * or as a scaled integer. The returned value is checked to fit into a unsigned + * long data type. This is a legacy compatibility function and it should not + * be used for things other the block job APIs. + * + * Returns 0 on success, -1 on error. + */ +int +vshBlockJobOptionBandwidth(vshControl *ctl, + const vshCmd *cmd, + bool bytes, + unsigned long *bandwidth) +{ + vshCmdOpt *arg; + char *end; + unsigned long long bw; + int ret; + + if ((ret = vshCommandOpt(cmd, "bandwidth", &arg, true)) <= 0) + return ret; + + /* due to historical reasons we declare to parse negative numbers and wrap + * them to the unsigned data type. */ + if (virStrToLong_ul(arg->data, NULL, 10, bandwidth) < 0) { + /* try to parse the number as scaled size in this cas we don't accept + * wrapping since it would be ridiculous. In case of a 32 bit host, + * limit the value to ULONG_MAX */ + if (virStrToLong_ullp(arg->data, &end, 10, &bw) < 0 || + virScaleInteger(&bw, end, 1, ULONG_MAX) < 0) { + vshError(ctl, + _("Scaled numeric value '%s' for <--bandwidth> option is " + "malformed or out of range"), arg->data); + return -1; + } + + if (!bytes) + bw >>= 20; + + *bandwidth = bw; + } + + return 0; +} + + /* * Executes command(s) and returns return code from last command */ diff --git a/tools/vsh.h b/tools/vsh.h index f6e40e6..f738a6f 100644 --- a/tools/vsh.h +++ b/tools/vsh.h @@ -291,6 +291,10 @@ int vshCommandOptScaledInt(vshControl *ctl, const vshCmd *cmd, const char *name, unsigned long long *value, int scale, unsigned long long max) ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK; +int vshBlockJobOptionBandwidth(vshControl *ctl, + const vshCmd *cmd, + bool bytes, + unsigned long *bandwidth); bool vshCommandOptBool(const vshCmd *cmd, const char *name); bool vshCommandRun(vshControl *ctl, const vshCmd *cmd); bool vshCommandStringParse(vshControl *ctl, char *cmdstr); -- 2.7.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list