virsh: expose new active commit controls

Add knobs to virsh to manage a 2-phase active commit of the top
layer, similar to knobs already present on blockcopy.  While this
code will fail until later patches actually implement the new
knobs in the qemu driver, doing it now proves that the API is
usable and also makes it easier for testing the qemu changes as
they are made.

* tools/virsh-domain.c (cmdBlockCommit): Add --active, --pivot,
and --keep-overlay options, modeled after blockcopy.
(blockJobImpl): Support --active flag.
* tools/virsh.pod (blockcommit): Document new flags.
(blockjob): Mention 2-phase commit interaction.

Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Eric Blake 2014-05-20 22:11:29 -06:00
parent 1bfe73a126
commit f182da20b0
2 changed files with 73 additions and 15 deletions

View File

@ -1492,6 +1492,10 @@ blockJobImpl(vshControl *ctl, const vshCmd *cmd,
flags |= VIR_DOMAIN_BLOCK_COMMIT_SHALLOW;
if (vshCommandOptBool(cmd, "delete"))
flags |= VIR_DOMAIN_BLOCK_COMMIT_DELETE;
if (vshCommandOptBool(cmd, "active") ||
vshCommandOptBool(cmd, "pivot") ||
vshCommandOptBool(cmd, "keep-overlay"))
flags |= VIR_DOMAIN_BLOCK_COMMIT_ACTIVE;
ret = virDomainBlockCommit(dom, path, base, top, bandwidth, flags);
break;
case VSH_CMD_BLOCK_JOB_COPY:
@ -1592,13 +1596,18 @@ static const vshCmdOptDef opts_block_commit[] = {
.type = VSH_OT_DATA,
.help = N_("path of top file to commit from (default top of chain)")
},
{.name = "active",
.type = VSH_OT_BOOL,
.help = N_("trigger two-stage active commit of top file")
},
{.name = "delete",
.type = VSH_OT_BOOL,
.help = N_("delete files that were successfully committed")
},
{.name = "wait",
.type = VSH_OT_BOOL,
.help = N_("wait for job to complete")
.help = N_("wait for job to complete "
"(with --active, wait for job to sync)")
},
{.name = "verbose",
.type = VSH_OT_BOOL,
@ -1606,7 +1615,15 @@ static const vshCmdOptDef opts_block_commit[] = {
},
{.name = "timeout",
.type = VSH_OT_INT,
.help = N_("with --wait, abort if copy exceeds timeout (in seconds)")
.help = N_("implies --wait, abort if copy exceeds timeout (in seconds)")
},
{.name = "pivot",
.type = VSH_OT_BOOL,
.help = N_("implies --active --wait, pivot when commit is synced")
},
{.name = "keep-overlay",
.type = VSH_OT_BOOL,
.help = N_("implies --active --wait, quit when commit is synced")
},
{.name = "async",
.type = VSH_OT_BOOL,
@ -1620,8 +1637,11 @@ cmdBlockCommit(vshControl *ctl, const vshCmd *cmd)
{
virDomainPtr dom = NULL;
bool ret = false;
bool blocking = vshCommandOptBool(cmd, "wait");
bool verbose = vshCommandOptBool(cmd, "verbose");
bool pivot = vshCommandOptBool(cmd, "pivot");
bool finish = vshCommandOptBool(cmd, "keep-overlay");
bool active = vshCommandOptBool(cmd, "active") || pivot || finish;
bool blocking = vshCommandOptBool(cmd, "wait");
int timeout = 0;
struct sigaction sig_action;
struct sigaction old_sig_action;
@ -1632,7 +1652,12 @@ cmdBlockCommit(vshControl *ctl, const vshCmd *cmd)
bool quit = false;
int abort_flags = 0;
blocking |= vshCommandOptBool(cmd, "timeout") || pivot || finish;
if (blocking) {
if (pivot && finish) {
vshError(ctl, "%s", _("cannot mix --pivot and --keep-overlay"));
return false;
}
if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
return false;
if (vshCommandOptStringReq(ctl, cmd, "path", &path) < 0)
@ -1650,8 +1675,7 @@ cmdBlockCommit(vshControl *ctl, const vshCmd *cmd)
sigaction(SIGINT, &sig_action, &old_sig_action);
GETTIMEOFDAY(&start);
} else if (verbose || vshCommandOptBool(cmd, "timeout") ||
vshCommandOptBool(cmd, "async")) {
} else if (verbose || vshCommandOptBool(cmd, "async")) {
vshError(ctl, "%s", _("missing --wait option"));
return false;
}
@ -1683,6 +1707,8 @@ cmdBlockCommit(vshControl *ctl, const vshCmd *cmd)
if (verbose)
vshPrintJobProgress(_("Block Commit"),
info.end - info.cur, info.end);
if (active && info.cur == info.end)
break;
GETTIMEOFDAY(&curr);
if (intCaught || (timeout &&
@ -1709,7 +1735,25 @@ cmdBlockCommit(vshControl *ctl, const vshCmd *cmd)
/* printf [100 %] */
vshPrintJobProgress(_("Block Commit"), 0, 1);
}
vshPrint(ctl, "\n%s", quit ? _("Commit aborted") : _("Commit complete"));
if (!quit && pivot) {
abort_flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT;
if (virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
vshError(ctl, _("failed to pivot job for disk %s"), path);
goto cleanup;
}
} else if (finish && !quit &&
virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
vshError(ctl, _("failed to finish job for disk %s"), path);
goto cleanup;
}
if (quit)
vshPrint(ctl, "\n%s", _("Commit aborted"));
else if (pivot)
vshPrint(ctl, "\n%s", _("Successfully pivoted"));
else if (!finish)
vshPrint(ctl, "\n%s", _("Now in synchronized phase"));
else
vshPrint(ctl, "\n%s", _("Commit complete"));
ret = true;
cleanup:

View File

@ -774,8 +774,9 @@ address of virtual interface (such as I<detach-interface> or
I<domif-setlink>) will accept the MAC address printed by this command.
=item B<blockcommit> I<domain> I<path> [I<bandwidth>]
{[I<base>] | [I<--shallow>]} [I<top>] [I<--delete>]
[I<--wait> [I<--verbose>] [I<--timeout> B<seconds>] [I<--async>]]
[I<base>] [I<--shallow>] [I<top>] [I<--delete>]
[I<--wait> [I<--async>] [I<--verbose>]] [I<--timeout> B<seconds>]
[I<--active>] [{I<--pivot> | I<--keep-overlay>}]
Reduce the length of a backing image chain, by committing changes at the
top of the chain (snapshot or delta files) into backing images. By
@ -785,19 +786,32 @@ operation is constrained to committing just that portion of the chain;
I<--shallow> can be used instead of I<base> to specify the immediate
backing file of the resulting top image to be committed. The files
being committed are rendered invalid, possibly as soon as the operation
starts; using the I<--delete> flag will remove these files at the successful
completion of the commit operation.
starts; using the I<--delete> flag will attempt to remove these invalidated
files at the successful completion of the commit operation.
When I<top> is omitted or specified as the active image, it is also
possible to specify I<--active> to trigger a two-phase active commit. In
the first phase, I<top> is copied into I<base> and the job can only be
canceled, with top still containing data not yet in base. In the second
phase, I<top> and I<base> remain identical until a call to B<blockjob>
with the I<--abort> flag (keeping top as the active image that tracks
changes from that point in time) or the I<--pivot> flag (making base
the new active image and invalidating top).
By default, this command returns as soon as possible, and data for
the entire disk is committed in the background; the progress of the
operation can be checked with B<blockjob>. However, if I<--wait> is
specified, then this command will block until the operation completes,
or cancel the operation if the optional I<timeout> in seconds elapses
specified, then this command will block until the operation completes
(or for I<--active>, enters the second phase), or until the operation
is canceled because the optional I<timeout> in seconds elapses
or SIGINT is sent (usually with C<Ctrl-C>). Using I<--verbose> along
with I<--wait> will produce periodic status updates. If job cancellation
is triggered, I<--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.
longer until the job is done cleaning up. Using I<--pivot> is shorthand
for combining I<--active> I<--wait> with an automatic B<blockjob>
I<--pivot>; and using I<--keep-overlay> is shorthand for combining
I<--active> I<--wait> with an automatic B<blockjob> 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
@ -924,8 +938,8 @@ 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 cancellation to complete. If
I<--pivot> is specified, this requests that an active copy job
be pivoted over to the new copy.
I<--pivot> is specified, this requests that an active copy or active
commit job be pivoted over to the new image.
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.