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 --finish 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(a)redhat.com>
---
tools/virsh-domain.c | 58 +++++++++++++++++++++++++++++++++++++++++++++-------
tools/virsh.pod | 36 ++++++++++++++++++++++----------
2 files changed, 76 insertions(+), 18 deletions(-)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 294b594..3db0bae 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -1498,6 +1498,10 @@ blockJobImpl(vshControl *ctl, const vshCmd *cmd,
flags |= VIR_DOMAIN_BLOCK_COMMIT_DELETE;
if (vshCommandOptBool(cmd, "keep-relative"))
flags |= VIR_DOMAIN_BLOCK_COMMIT_RELATIVE;
+ 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:
@@ -1598,13 +1602,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,
@@ -1612,7 +1621,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,
@@ -1621,7 +1638,7 @@ static const vshCmdOptDef opts_block_commit[] = {
{.name = "keep-relative",
.type = VSH_OT_BOOL,
.help = N_("keep the backing chain relative if it was relatively "
- "referenced if it was before")
+ "referenced before")
},
{.name = NULL}
};
@@ -1631,8 +1648,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;
@@ -1643,7 +1663,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)
@@ -1661,8 +1686,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;
}
@@ -1694,6 +1718,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 &&
@@ -1720,7 +1746,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:
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 77013f5..21c29ec 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -769,8 +769,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<--keep-relative>]
-[I<--wait> [I<--verbose>] [I<--timeout> B<seconds>]
[I<--async>]]
+[I<base>] [I<--shallow>] [I<top>] [I<--delete>]
[I<--keep-relative>]
+[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
@@ -780,21 +781,34 @@ 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. Using the I<--keep-relative> flag
-will try to keep the backing chain names relative (if they were
-relative before).
+starts; using the I<--delete> flag will attempt to remove these invalidated
+files at the successful completion of the commit operation. Using the
+I<--keep-relative> flag will try to keep the backing chain names relative
+(if they were relative before).
+
+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
@@ -925,8 +939,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.
--
1.9.3