Signed-off-by: Nikolai Barybin <[email protected]>
---
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