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