Signed-off-by: Nikolai Barybin <nikolai.bary...@virtuozzo.com> --- docs/manpages/virsh.rst | 39 ++++++++++ tools/virsh-domain.c | 160 ++++++++++++++++++++++++++++++++++++++++ tools/vsh.c | 14 ++++ tools/vsh.h | 2 + 4 files changed, 215 insertions(+)
diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index bcb5495ed9..16c4f5d28d 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -1626,6 +1626,45 @@ on the *bandwidth* argument see the corresponding section for the ``blockjob`` command. +blockrebase-params +------------------ + +**Syntax:** + +:: + + blockrebase-params domain path [bandwidth] [base] + [--wait [--verbose] [--timeout seconds] [--async]] + [--keep-relative] + +Populate a disk from its backing image chain. By default, this command +flattens the entire chain; but if *base* is specified, containing the +name of one of the backing files in the chain, then that file becomes +the new backing file and only the intermediate portion of the chain is +pulled. Once all requested data from the backing image chain has been +pulled, the disk no longer depends on that portion of the backing chain. + +By default, this command returns as soon as possible, and data for +the entire disk is pulled in the background; the progress of the +operation can be checked with ``blockjob``. However, if *--wait* is +specified, then this command will block until the operation completes, +or cancel the operation if the optional *timeout* in seconds elapses +or SIGINT is sent (usually with ``Ctrl-C``). Using *--verbose* along +with *--wait* will produce periodic status updates. If job cancellation +is triggered, *--async* will return control to the user as fast as +possible, otherwise the command may continue to block a little while +longer until the job is done cleaning up. + +Using the *--keep-relative* flag will keep the backing chain names +relative. + +*path* specifies fully-qualified path of the disk; it corresponds +to a unique target name (<target dev='name'/>) or source file (<source +file='name'/>) for one of the disk devices attached to *domain* (see +also ``domblklist`` for listing these names). +*bandwidth* specifies copying bandwidth limit in Bytes/s. + + blockresize ----------- diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 6e18d195e6..9023f8f72d 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -3306,6 +3306,160 @@ cmdBlockpull(vshControl *ctl, const vshCmd *cmd) return ret; } +/* + * "blockrebase-params" command + */ +static const vshCmdInfo info_blockrebase_params = { + .help = N_("Populate a disk from its backing image."), + .desc = N_("Populate a disk from its backing image."), +}; + +static const vshCmdOptDef opts_blockrebase_params[] = { + VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), + {.name = "path", + .type = VSH_OT_STRING, + .positional = true, + .required = true, + .completer = virshDomainDiskTargetCompleter, + .help = N_("fully-qualified path of disk") + }, + {.name = "bandwidth", + .type = VSH_OT_INT, + .unwanted_positional = true, + .help = N_("bandwidth limit in bytes/s") + }, + {.name = "base", + .type = VSH_OT_STRING, + .unwanted_positional = true, + .completer = virshDomainBlockjobBaseTopCompleter, + .help = N_("path of backing file in chain specifying a new base") + }, + {.name = "wait", + .type = VSH_OT_BOOL, + .help = N_("wait for job to finish") + }, + {.name = "verbose", + .type = VSH_OT_BOOL, + .help = N_("with --wait, display the progress") + }, + {.name = "timeout", + .type = VSH_OT_INT, + .unwanted_positional = true, + .help = N_("with --wait, abort if rebase exceeds timeout (in seconds)") + }, + {.name = "async", + .type = VSH_OT_BOOL, + .help = N_("with --wait, don't wait for cancel to finish") + }, + {.name = "keep-relative", + .type = VSH_OT_BOOL, + .help = N_("keep the backing chain relatively referenced") + }, + {.name = NULL} +}; + +static bool +cmdBlockrebaseParams(vshControl *ctl, const vshCmd *cmd) +{ + g_autoptr(virshDomain) dom = NULL; + bool ret = false; + bool blocking = vshCommandOptBool(cmd, "wait"); + bool verbose = vshCommandOptBool(cmd, "verbose"); + bool async = vshCommandOptBool(cmd, "async"); + int timeout = 0; + const char *path = NULL; + const char *base = NULL; + unsigned long long bandwidth = 0; + unsigned int flags = 0; + virshBlockJobWaitData *bjWait = NULL; + int nparams = 0; + int maxparams = 0; + virTypedParameterPtr params = NULL; + + VSH_REQUIRE_OPTION("verbose", "wait"); + VSH_REQUIRE_OPTION("async", "wait"); + + if (vshCommandOptString(ctl, cmd, "path", &path) < 0) + return false; + + if (vshCommandOptString(ctl, cmd, "base", &base) < 0) + return false; + + if (vshBlockRebaseParamsOptionBandwidth(cmd, &bandwidth) < 0) + return false; + + if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0) + return false; + + if (vshCommandOptBool(cmd, "keep-relative")) + flags |= VIR_DOMAIN_BLOCK_REBASE_PARAMS_RELATIVE; + + if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (blocking && + !(bjWait = virshBlockJobWaitInit(ctl, dom, path, _("Block Rebase Params"), + verbose, timeout, async))) + goto cleanup; + + if (base && + virTypedParamsAddString(¶ms, &nparams, &maxparams, + VIR_DOMAIN_BLOCK_REBASE_PARAM_BASE, + base) < 0) { + vshError(ctl, _("failed to add param %1$s:%2$s to params list"), + VIR_DOMAIN_BLOCK_REBASE_PARAM_BASE, base); + goto cleanup; + } + + if (bandwidth > 0 && + virTypedParamsAddULLong(¶ms, &nparams, &maxparams, + VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH, + bandwidth) < 0) { + vshError(ctl, _("failed to add param %1$s:%2$llu to params list"), + VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH, bandwidth); + goto cleanup; + } + + if (virDomainBlockRebaseParams(dom, path, params, nparams, flags) < 0) + goto cleanup; + + if (!blocking) { + vshPrintExtra(ctl, "%s", _("Block Rebase started")); + ret = true; + goto cleanup; + } + + /* Execution continues here only if --wait or friends were specified */ + switch (virshBlockJobWait(bjWait)) { + case -1: + goto cleanup; + + case VIR_DOMAIN_BLOCK_JOB_CANCELED: + vshPrintExtra(ctl, "\n%s", _("Rebase aborted")); + goto cleanup; + break; + + case VIR_DOMAIN_BLOCK_JOB_FAILED: + vshPrintExtra(ctl, "\n%s", _("Rebase failed")); + goto cleanup; + break; + + case VIR_DOMAIN_BLOCK_JOB_READY: + case VIR_DOMAIN_BLOCK_JOB_COMPLETED: + vshPrintExtra(ctl, "\n%s", _("Rebase complete")); + break; + } + + ret = true; + + cleanup: + virshBlockJobWaitFree(bjWait); + virTypedParamsFree(params, nparams); + params = NULL; + nparams = 0; + return ret; +} + /* * "blockresize" command */ @@ -13976,6 +14130,12 @@ const vshCmdDef domManagementCmds[] = { .info = &info_blockpull, .flags = 0 }, + {.name = "blockrebase-params", + .handler = cmdBlockrebaseParams, + .opts = opts_blockrebase_params, + .info = &info_blockrebase_params, + .flags = 0 + }, {.name = "blockresize", .handler = cmdBlockresize, .opts = opts_blockresize, diff --git a/tools/vsh.c b/tools/vsh.c index 4aacc5feac..480b54b572 100644 --- a/tools/vsh.c +++ b/tools/vsh.c @@ -1346,6 +1346,20 @@ vshBlockJobOptionBandwidth(vshControl *ctl, } +int +vshBlockRebaseParamsOptionBandwidth(const vshCmd *cmd, + unsigned long long *bandwidth) +{ + vshCmdOpt *arg; + int ret; + + if ((ret = vshCommandOpt(cmd, "bandwidth", &arg, true)) <= 0) + return ret; + + return virStrToLong_ull(arg->data, NULL, 10, bandwidth); +} + + /** * vshCommandRun: * @ctl: virt shell data diff --git a/tools/vsh.h b/tools/vsh.h index bd2494e899..0f79c32d41 100644 --- a/tools/vsh.h +++ b/tools/vsh.h @@ -287,6 +287,8 @@ int vshBlockJobOptionBandwidth(vshControl *ctl, const vshCmd *cmd, bool bytes, unsigned long *bandwidth); +int vshBlockRebaseParamsOptionBandwidth(const vshCmd *cmd, + unsigned long long *bandwidth); bool vshCommandOptBool(const vshCmd *cmd, const char *name); int vshCommandRun(vshControl *ctl, const vshCmd *cmd); bool vshCommandStringParse(vshControl *ctl, char *cmdstr, -- 2.43.5