Rather than further overloading 'blockpull', I decided to create a
new virsh command to expose the new flags of virDomainBlockRebase.
Someday, I'd also like to make blockpull and blockcopy have a
synchronous mode, which blocks until the event happens or Ctrl-C
is pressed, as well as a --verbose flag to print status updates
before the job finishes - but not today.
* tools/virsh.c (VSH_CMD_BLOCK_JOB_COPY): New mode.
(blockJobImpl): Support new flags.
(cmdBlockCopy): New command.
(cmdBlockJob): Support new job info, new abort flag.
* tools/virsh.pod (blockcopy, blockjob): Document the new command
and flags.
---
tools/virsh.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++-------
tools/virsh.pod | 36 +++++++++++++++++++++++--
2 files changed, 101 insertions(+), 13 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 084d533..25403f5 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -7515,16 +7515,18 @@ typedef enum {
VSH_CMD_BLOCK_JOB_INFO = 1,
VSH_CMD_BLOCK_JOB_SPEED = 2,
VSH_CMD_BLOCK_JOB_PULL = 3,
-} VSH_CMD_BLOCK_JOB_MODE;
+ VSH_CMD_BLOCK_JOB_COPY = 4,
+} vshCmdBlockJobMode;
static int
blockJobImpl(vshControl *ctl, const vshCmd *cmd,
- virDomainBlockJobInfoPtr info, int mode)
+ virDomainBlockJobInfoPtr info, int mode)
{
virDomainPtr dom = NULL;
const char *name, *path;
unsigned long bandwidth = 0;
int ret = -1;
+ const char *base = NULL;
unsigned int flags = 0;
if (!vshConnectionUsability(ctl, ctl->conn))
@@ -7541,22 +7543,39 @@ blockJobImpl(vshControl *ctl, const vshCmd *cmd,
goto cleanup;
}
- if (mode == VSH_CMD_BLOCK_JOB_ABORT) {
+ switch ((vshCmdBlockJobMode) mode) {
+ case VSH_CMD_BLOCK_JOB_ABORT:
if (vshCommandOptBool(cmd, "async"))
flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC;
+ if (vshCommandOptBool(cmd, "pivot"))
+ flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT;
ret = virDomainBlockJobAbort(dom, path, flags);
- } else if (mode == VSH_CMD_BLOCK_JOB_INFO) {
+ break;
+ case VSH_CMD_BLOCK_JOB_INFO:
ret = virDomainGetBlockJobInfo(dom, path, info, 0);
- } else if (mode == VSH_CMD_BLOCK_JOB_SPEED) {
+ break;
+ case VSH_CMD_BLOCK_JOB_SPEED:
ret = virDomainBlockJobSetSpeed(dom, path, bandwidth, 0);
- } else if (mode == VSH_CMD_BLOCK_JOB_PULL) {
- const char *base = NULL;
+ break;
+ case VSH_CMD_BLOCK_JOB_PULL:
if (vshCommandOptString(cmd, "base", &base) < 0)
goto cleanup;
if (base)
ret = virDomainBlockRebase(dom, path, base, bandwidth, 0);
else
ret = virDomainBlockPull(dom, path, bandwidth, 0);
+ break;
+ case VSH_CMD_BLOCK_JOB_COPY:
+ flags |= VIR_DOMAIN_BLOCK_REBASE_COPY;
+ 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 (vshCommandOptString(cmd, "dest", &base) < 0)
+ goto cleanup;
+ ret = virDomainBlockRebase(dom, path, base, bandwidth, flags);
}
cleanup:
@@ -7566,6 +7585,34 @@ cleanup:
}
/*
+ * "blockcopy" command
+ */
+static const vshCmdInfo info_block_copy[] = {
+ {"help", N_("Start a block copy operation.")},
+ {"desc", N_("Populate a disk from its backing image.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_block_copy[] = {
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or
uuid")},
+ {"path", VSH_OT_DATA, VSH_OFLAG_REQ, N_("Fully-qualified path of
disk")},
+ {"dest", VSH_OT_DATA, VSH_OFLAG_REQ, N_("path of the copy to
create")},
+ {"bandwidth", VSH_OT_DATA, VSH_OFLAG_NONE, N_("Bandwidth limit in
MB/s")},
+ {"shallow", VSH_OT_BOOL, 0, N_("make the copy share a backing
chain")},
+ {"reuse-external", VSH_OT_BOOL, 0, N_("reuse existing
destination")},
+ {"raw", VSH_OT_BOOL, 0, N_("use raw destination file")},
+ {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdBlockCopy(vshControl *ctl, const vshCmd *cmd)
+{
+ if (blockJobImpl(ctl, cmd, NULL, VSH_CMD_BLOCK_JOB_COPY) != 0)
+ return false;
+ return true;
+}
+
+/*
* "blockpull" command
*/
static const vshCmdInfo info_block_pull[] = {
@@ -7607,6 +7654,8 @@ static const vshCmdOptDef opts_block_job[] = {
N_("Abort the active job on the specified disk")},
{"async", VSH_OT_BOOL, VSH_OFLAG_NONE,
N_("don't wait for --abort to complete")},
+ {"pivot", VSH_OT_BOOL, VSH_OFLAG_NONE,
+ N_("conclude and pivot a copy job")},
{"info", VSH_OT_BOOL, VSH_OFLAG_NONE,
N_("Get active job information for the specified disk")},
{"bandwidth", VSH_OT_DATA, VSH_OFLAG_NONE,
@@ -7622,7 +7671,8 @@ cmdBlockJob(vshControl *ctl, const vshCmd *cmd)
const char *type;
int ret;
bool abortMode = (vshCommandOptBool(cmd, "abort") ||
- vshCommandOptBool(cmd, "async"));
+ vshCommandOptBool(cmd, "async") ||
+ vshCommandOptBool(cmd, "pivot"));
bool infoMode = vshCommandOptBool(cmd, "info");
bool bandwidth = vshCommandOptBool(cmd, "bandwidth");
@@ -7646,10 +7696,17 @@ cmdBlockJob(vshControl *ctl, const vshCmd *cmd)
if (ret == 0 || mode != VSH_CMD_BLOCK_JOB_INFO)
return true;
- if (info.type == VIR_DOMAIN_BLOCK_JOB_TYPE_PULL)
+ switch (info.type) {
+ case VIR_DOMAIN_BLOCK_JOB_TYPE_PULL:
type = _("Block Pull");
- else
+ break;
+ case VIR_DOMAIN_BLOCK_JOB_TYPE_COPY:
+ type = _("Block Copy");
+ break;
+ default:
type = _("Unknown job");
+ break;
+ }
print_job_progress(type, info.end - info.cur, info.end);
if (info.bandwidth != 0)
@@ -17128,6 +17185,7 @@ static const vshCmdDef domManagementCmds[] = {
{"autostart", cmdAutostart, opts_autostart, info_autostart, 0},
{"blkdeviotune", cmdBlkdeviotune, opts_blkdeviotune, info_blkdeviotune,
0},
{"blkiotune", cmdBlkiotune, opts_blkiotune, info_blkiotune, 0},
+ {"blockcopy", cmdBlockCopy, opts_block_copy, info_block_copy, 0},
{"blockjob", cmdBlockJob, opts_block_job, info_block_job, 0},
{"blockpull", cmdBlockPull, opts_block_pull, info_block_pull, 0},
{"blockresize", cmdBlockResize, opts_block_resize, info_block_resize, 0},
diff --git a/tools/virsh.pod b/tools/virsh.pod
index d6ba035..ee84ce5 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -638,6 +638,34 @@ currently in use by a running domain. Other contexts that require a
MAC
address of virtual interface (such as I<detach-interface> or
I<domif-setlink>) will accept the MAC address printed by this command.
+=item B<blockcopy> I<domain> I<path> I<dest> [I<bandwidth>]
[I<--shallow>]
+[I<--reuse-external>] [I<--raw>]
+
+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.
+
+If I<--reuse-external> is specified, then I<dest> must exist and have
+contents identical to the resulting backing file (that is, it must
+start with contents matching the backing file I<disk> if I<--shallow>
+is used, otherwise it must start empty); this option is typically used
+to set up a relative backing file name in 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 copy runs in the background; 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 source disk. After this phase completes, both the
+source and the destination remain mirrored until a call to B<blockjob>
+with the I<--abort> and I<--pivot> flags pivots over to the copy.
+
+I<path> specifies fully-qualified path of the disk.
+I<bandwidth> specifies copying bandwidth limit in Mbps.
+
=item B<blockpull> I<domain> I<path> [I<bandwidth>]
[I<base>]
Populate a disk from its backing image chain. By default, this command
@@ -689,12 +717,12 @@ Both I<--live> and I<--current> flags may be given, but
I<--current> is
exclusive. If no flag is specified, behavior is different depending
on hypervisor.
-=item B<blockjob> I<domain> I<path> { [I<--abort>]
[I<--async>] |
+=item B<blockjob> I<domain> I<path> { [I<--abort>]
[I<--async>] [I<--pivot>] |
[I<--info>] | [I<bandwidth>] }
Manage active block operations. There are three modes: I<--info>,
I<bandwidth>, and I<--abort>; I<--info> is default except that
I<--async>
-implies I<--abort>.
+or I<--pivot> implies I<--abort>.
I<path> specifies fully-qualified path of the disk; it corresponds
to a unique target name (<target dev='name'/>) or source file (<source
@@ -703,7 +731,9 @@ also B<domblklist> for listing these names).
If I<--abort> is specified, the active job on the specified disk will
be aborted. If I<--async> is also specified, this command will return
-immediately, rather than waiting for the cancelation to complete.
+immediately, rather than waiting for the cancelation to complete. If
+I<--pivot> is specified, this requests that an active copy job
+be pivoted over to the new copy.
If I<--info> is specified, the active job information on the specified
disk will be printed.
I<bandwidth> can be used to set bandwidth limit for the active job.
--
1.7.7.6