[libvirt] [PATCH v3 12/18] blockcopy: expose new API in virsh
Peter Krempa
pkrempa at redhat.com
Fri Sep 5 09:41:08 UTC 2014
On 08/31/14 06:02, Eric Blake wrote:
> Expose the new power of virDomainBlockCopy through virsh (well,
> all but the finer-grained bandwidth, as that is its own can of
> worms for a later patch). Continue to use the older API where
> possible, for maximum compatibility.
>
> The command now requires either --dest (with optional --format
> and --blockdev), to directly describe the file destination, or
> --xml, to name a file that contains an XML description such as:
>
> <disk type='network'>
> <driver type='raw'/>
> <source protocol='gluster' name='vol1/img'>
> <host name='red'/>
> </source>
> </disk>
>
> Non-zero option parameters are converted into virTypedParameters,
> and if anything requires the new API, the command can synthesize
> appropriate XML even if the --dest option was used instead of --xml.
>
> The existing --raw flag remains for back-compat, but the preferred
> spelling is now --format=raw, since the new API now allows us
> to specify all formats rather than just a boolean raw to suppress
> probing.
>
> I hope I did justice in describing the effects of granularity and
> buf-size on how they get passed through to qemu.
>
> * tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
> --granularity, --buf-size, --format. Make --raw an alias for
> --format=raw. Call new API if new parameters are in use.
> * tools/virsh.pod (blockcopy): Document new options.
>
> Signed-off-by: Eric Blake <eblake at redhat.com>
> ---
> tools/virsh-domain.c | 145 +++++++++++++++++++++++++++++++++++++++++++++------
> tools/virsh.pod | 45 +++++++++-------
> 2 files changed, 156 insertions(+), 34 deletions(-)
>
> diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
> index b92b2eb..16d7f05 100644
> --- a/tools/virsh-domain.c
> +++ b/tools/virsh-domain.c
> @@ -1893,6 +1912,23 @@ cmdBlockCopy(vshControl *ctl, const vshCmd *cmd)
> const char *path = NULL;
> bool quit = false;
> int abort_flags = 0;
> + const char *xml = NULL;
> + char *xmlstr = NULL;
> + virTypedParameterPtr params = NULL;
> + int nparams = 0;
> +
> + if (vshCommandOptStringReq(ctl, cmd, "path", &path) < 0)
> + return false;
> + if (vshCommandOptString(cmd, "dest", &dest) < 0)
> + return false;
> + if (vshCommandOptString(cmd, "xml", &xml) < 0)
> + return false;
> + if (vshCommandOptString(cmd, "format", &format) < 0)
> + return false;
> +
> + VSH_EXCLUSIVE_OPTIONS_VAR(dest, xml);
These were designed to work on booleans, but pointers are fortunately
sharing the semantics :)
> + VSH_EXCLUSIVE_OPTIONS_VAR(format, xml);
> + VSH_EXCLUSIVE_OPTIONS_VAR(blockdev, xml);
>
> if (vshCommandOptStringReq(ctl, cmd, "path", &path) < 0)
> return false;
> @@ -1926,24 +1962,101 @@ cmdBlockCopy(vshControl *ctl, const vshCmd *cmd)
> if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
> goto cleanup;
>
> + /* XXX: Parse bandwidth as scaled input, rather than forcing
> + * MiB/s, and either reject negative input or treat it as 0 rather
> + * than trying to guess which value will work well across both
> + * APIs with their different sizes and scales. */
> if (vshCommandOptULWrap(cmd, "bandwidth", &bandwidth) < 0) {
> vshError(ctl, "%s", _("bandwidth must be a number"));
> goto cleanup;
> }
> + if (vshCommandOptUInt(cmd, "granularity", &granularity) < 0) {
> + vshError(ctl, "%s", _("granularity must be a number"));
> + goto cleanup;
> + }
> + if (vshCommandOptULongLong(cmd, "buf-size", &buf_size) < 0) {
> + vshError(ctl, "%s", _("buf-size must be a number"));
> + goto cleanup;
> + }
>
> + if (xml) {
> + if (virFileReadAll(xml, 8192, &xmlstr) < 0) {
> + vshReportError(ctl);
> + goto cleanup;
> + }
> + } else if (!dest) {
> + vshError(ctl, "%s", _("need either --dest or --xml"));
> + goto cleanup;
> + }
> +
> + /* Exploit that VIR_DOMAIN_BLOCK_REBASE_* and
> + * VIR_DOMAIN_BLOCK_COPY_* flags have the same values. */
> if (vshCommandOptBool(cmd, "shallow"))
> flags |= VIR_DOMAIN_BLOCK_REBASE_SHALLOW;
> if (vshCommandOptBool(cmd, "reuse-external"))
> flags |= VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT;
> - if (vshCommandOptBool(cmd, "raw"))
> - flags |= VIR_DOMAIN_BLOCK_REBASE_COPY_RAW;
> - if (vshCommandOptBool(cmd, "blockdev"))
> - flags |= VIR_DOMAIN_BLOCK_REBASE_COPY_DEV;
> - if (vshCommandOptStringReq(ctl, cmd, "dest", &dest) < 0)
> - goto cleanup;
> -
> - if (virDomainBlockRebase(dom, path, dest, bandwidth, flags) < 0)
> - goto cleanup;
> +
> + if (granularity || buf_size || (format && STRNEQ(format, "raw")) || xml) {
> + /* New API */
> + if (bandwidth || granularity || buf_size) {
> + params = vshCalloc(ctl, 3, sizeof(*params));
> + if (bandwidth) {
> + /* bandwidth is ulong MiB/s, but the typed parameter is
> + * ullong bytes/s; make sure we don't overflow */
> + if (bandwidth > LLONG_MAX >> 20) {
> + virReportError(VIR_ERR_OVERFLOW,
> + _("bandwidth must be less than %llu"),
> + LLONG_MAX >> 20);
> + }
> + if (virTypedParameterAssign(¶ms[nparams++],
> + VIR_DOMAIN_BLOCK_COPY_BANDWIDTH,
> + VIR_TYPED_PARAM_ULLONG,
> + bandwidth << 20ULL) < 0)
> + goto cleanup;
> + }
> + if (granularity &&
> + virTypedParameterAssign(¶ms[nparams++],
> + VIR_DOMAIN_BLOCK_COPY_GRANULARITY,
> + VIR_TYPED_PARAM_UINT,
> + granularity) < 0)
> + goto cleanup;
> + if (buf_size &&
> + virTypedParameterAssign(¶ms[nparams++],
> + VIR_DOMAIN_BLOCK_COPY_BUF_SIZE,
> + VIR_TYPED_PARAM_ULLONG,
> + buf_size) < 0)
> + goto cleanup;
> + }
> +
> + if (!xmlstr) {
> + virBuffer buf = VIR_BUFFER_INITIALIZER;
> + virBufferEscapeString(&buf, "<disk type='%s'>\n",
> + blockdev ? "block" : "file");
This one doesn't really need escaping
> + virBufferAdjustIndent(&buf, 2);
> + virBufferEscapeString(&buf, "<source %s",
> + blockdev ? "dev" : "file");
and this either
> + virBufferEscapeString(&buf, "='%s'/>\n", dest);
> + virBufferEscapeString(&buf, "<driver type='%s'/>\n", format);
> + virBufferAdjustIndent(&buf, -2);
> + virBufferAddLit(&buf, "</disk>\n");
> + if (virBufferCheckError(&buf) < 0)
> + goto cleanup;
> + xmlstr = virBufferContentAndReset(&buf);
> + }
> +
> + if (virDomainBlockCopy(dom, path, xmlstr, params, nparams, flags) < 0)
> + goto cleanup;
> + } else {
> + /* Old API */
> + flags |= VIR_DOMAIN_BLOCK_REBASE_COPY;
> + if (vshCommandOptBool(cmd, "blockdev"))
> + flags |= VIR_DOMAIN_BLOCK_REBASE_COPY_DEV;
> + if (STREQ_NULLABLE(format, "raw"))
> + flags |= VIR_DOMAIN_BLOCK_REBASE_COPY_RAW;
> +
> + if (virDomainBlockRebase(dom, path, dest, bandwidth, flags) < 0)
> + goto cleanup;
> + }
>
> if (!blocking) {
> vshPrint(ctl, "%s", _("Block Copy started"));
> @@ -2014,6 +2127,8 @@ cmdBlockCopy(vshControl *ctl, const vshCmd *cmd)
>
> ret = true;
> cleanup:
> + VIR_FREE(xmlstr);
> + virTypedParamsFree(params, nparams);
> if (dom)
> virDomainFree(dom);
> if (blocking)
> diff --git a/tools/virsh.pod b/tools/virsh.pod
> index 2923fd9..c3a76dc 100644
> --- a/tools/virsh.pod
> +++ b/tools/virsh.pod
> @@ -898,30 +898,31 @@ value is interpreted as an unsigned long long value or essentially
> unlimited. The hypervisor can choose whether to reject the value or
> convert it to the maximum value allowed.
>
> -=item B<blockcopy> I<domain> I<path> I<dest> [I<bandwidth>] [I<--shallow>]
> -[I<--reuse-external>] [I<--raw>] [I<--blockdev>]
> -[I<--wait> [I<--async>] [I<--verbose>]]
> -[{I<--pivot> | I<--finish>}] [I<--timeout> B<seconds>]
> +=item B<blockcopy> I<domain> I<path> { I<dest> [I<format>] [I<--blockdev>]
> +| I<xml> } [I<--shallow>] [I<--reuse-external>] [I<bandwidth>]
> +[I<--wait> [I<--async>] [I<--verbose>]] [{I<--pivot> | I<--finish>}]
> +[I<--timeout> B<seconds>] [I<granularity>] [I<buf-size>]
>
> -Copy a disk backing image chain to I<dest>. By default, this command
> -flattens the entire chain; but if I<--shallow> is specified, the copy
> -shares the backing chain.
> +Copy a disk backing image chain to a destination. Either I<dest> as
> +the destination file name, or I<xml> as the name of an XML file containing
> +a top-level <disk> element describing the destination, must be present.
> +Additionally, if I<dest> is given, I<format> should be specified to declare
> +the format of the destination (if I<format> is omitted, then libvirt
> +will reuse the format of the source, or with I<--reuse-external> will
> +be forced to probe the destination format, which could be a potential
> +security hole). The command supports I<--raw> as a boolean flag synonym for
> +I<--format=raw>. When using I<dest>, the destination is treated as a regular
> +file unless I<--blockdev> is used to signal that it is a block device. By
> +default, this command flattens the entire chain; but if I<--shallow> is
> +specified, the copy shares the backing chain.
>
> -If I<--reuse-external> is specified, then I<dest> must exist and have
> +If I<--reuse-external> is specified, then the destination must exist and have
> sufficient space to hold the copy. If I<--shallow> is used in
> conjunction with I<--reuse-external> then the pre-created image must have
> guest visible contents identical to guest visible contents of the backing
> file of the original image. This may be used to modify the backing file
> names on the destination.
>
> -The format of the destination is determined by the first match in the
> -following list: if I<--raw> is specified, it will be raw; if
> -I<--reuse-external> is specified, the existing destination is probed
> -for a format; and in all other cases, the destination format will
> -match the source format. The destination is treated as a regular
> -file unless I<--blockdev> is used to signal that it is a block
> -device.
> -
> By default, the copy job runs in the background, and consists of two
> phases. Initially, the job must copy all data from the source, and
> during this phase, the job can only be canceled to revert back to the
> @@ -943,9 +944,15 @@ while longer until the job has actually cancelled.
>
> I<path> specifies fully-qualified path of the disk.
> I<bandwidth> specifies copying bandwidth limit in MiB/s. Specifying a negative
> -value is interpreted as an unsigned long long value or essentially
> -unlimited. The hypervisor can choose whether to reject the value or
> -convert it to the maximum value allowed.
> +value is interpreted as an unsigned long long value that might be essentially
> +unlimited, but more likely would overflow; it is safer to use 0 for that
> +purpose. Specifying I<granularity> allows fine-tuning of the granularity that
> +will be copied when a dirty region is detected; larger values trigger less
> +I/O overhead but may end up copying more data overall (the default value is
> +usually correct); this value must be a power of two. Specifying I<buf-size>
> +will control how much data can be simultaneously in-flight during the copy;
> +larger values use more memory but may allow faster completion (the default
> +value is usually correct).
>
> =item B<blockpull> I<domain> I<path> [I<bandwidth>] [I<base>]
> [I<--wait> [I<--verbose>] [I<--timeout> B<seconds>] [I<--async>]]
>
ACK as is, all comments are pure cosmetic.
Peter
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20140905/a0298266/attachment-0001.sig>
More information about the libvir-list
mailing list